diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 10eef898f..378cfdf67 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -223,11 +223,13 @@ jobs: name: tinymist-${{ env.target }}.vsix path: editors/vscode/tinymist-${{ env.target }}.vsix - name: Upload Tinymist E2E Test Snapshot + if: always() uses: actions/upload-artifact@v4 with: name: e2e-snapshot-${{ env.target }} path: target/e2e - name: Upload Tinymist Testing log + if: always() uses: actions/upload-artifact@v4 with: name: tinymist-lsp-tests.${{ env.target }}.log diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..7bc6d1cd2 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,2 @@ +# Only Myriad-Dreamin and Enter-tainer can merge changes to this repository. +* @Myriad-Dreamin @Enter-tainer diff --git a/Cargo.lock b/Cargo.lock index 5a9c5d341..0337c325b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,9 +51,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "android-tzdata" @@ -81,9 +81,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -96,43 +96,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.90" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "approx" @@ -184,7 +184,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -220,12 +220,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -320,9 +314,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", "serde", @@ -382,9 +376,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "camino" @@ -415,14 +409,14 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "cc" -version = "1.1.31" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ "shlex", ] @@ -433,6 +427,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chinese-number" version = "0.7.7" @@ -505,9 +505,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -515,9 +515,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -530,9 +530,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.33" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9646e2e245bf62f45d39a0f3f36f1171ad1ea0d6967fd114bca72cb02a8fcdfb" +checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" dependencies = [ "clap", ] @@ -566,14 +566,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "clap_mangen" @@ -609,9 +609,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "comemo" @@ -643,7 +643,7 @@ checksum = "54af6ac68ada2d161fa9cc1ab52676228e340866d094d6542107e74b82acc095" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -654,7 +654,7 @@ checksum = "c8936e42f9b4f5bdfaf23700609ac1f11cb03ad4c1ec128a4ee4fd0903e228db" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -696,9 +696,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" dependencies = [ "libc", ] @@ -773,9 +773,9 @@ dependencies = [ [[package]] name = "csv" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" dependencies = [ "csv-core", "itoa", @@ -813,7 +813,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -824,7 +824,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -938,7 +938,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -958,9 +958,9 @@ dependencies = [ [[package]] name = "ecow" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54bfbb1708988623190a6c4dbedaeaf0f53c20c6395abd6a01feb327b3146f4b" +checksum = "e42fc0a93992b20c58b99e59d61eaf1635a25bfbe49e4275c34ba0aee98119ba" dependencies = [ "serde", ] @@ -1006,9 +1006,9 @@ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] @@ -1030,7 +1030,7 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1056,6 +1056,16 @@ dependencies = [ "log", ] +[[package]] +name = "env_proxy" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a5019be18538406a43b5419a5501461f0c8b49ea7dfda0cfc32f4e51fc44be1" +dependencies = [ + "log", + "url", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1090,15 +1100,15 @@ checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fdeflate" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8090f921a24b04994d9929e204f50b498a33ea6ba559ffaa05e04f7ee7fb5ab" +checksum = "07c6f4c64c1d33a3111c4466f7365ebdcc37c5bd1ea0d62aae2e3d722aacbedb" dependencies = [ "simd-adler32", ] @@ -1117,9 +1127,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -1255,7 +1265,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1314,8 +1324,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -1358,25 +1370,6 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.6.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "h2" version = "0.4.6" @@ -1388,7 +1381,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.1.0", + "http", "indexmap 2.6.0", "slab", "tokio", @@ -1427,9 +1420,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" [[package]] name = "hashlink" @@ -1454,7 +1447,7 @@ dependencies = [ "paste", "serde", "serde_yaml", - "thiserror", + "thiserror 1.0.69", "unic-langid", "unicode-segmentation", "unscanny", @@ -1485,17 +1478,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.1.0" @@ -1507,17 +1489,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -1525,7 +1496,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http", ] [[package]] @@ -1536,8 +1507,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -1559,30 +1530,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "hyper" -version = "0.14.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.5.0" @@ -1592,9 +1539,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.6", - "http 1.1.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", "httpdate", "itoa", @@ -1604,20 +1551,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.31", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", -] - [[package]] name = "hyper-rustls" version = "0.27.3" @@ -1625,28 +1558,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http 1.1.0", - "hyper 1.5.0", + "http", + "hyper", "hyper-util", - "rustls 0.23.15", + "rustls", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls", "tower-service", - "webpki-roots 0.26.6", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper 0.14.31", - "native-tls", - "tokio", - "tokio-native-tls", + "webpki-roots", ] [[package]] @@ -1657,7 +1577,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.5.0", + "hyper", "hyper-util", "native-tls", "tokio", @@ -1672,7 +1592,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69ce21dae6ce6e5f336a444d846e592faf42c5c28f70a5c8ff67893cbcb304d3" dependencies = [ "http-body-util", - "hyper 1.5.0", + "hyper", "hyper-util", "pin-project-lite", "tokio", @@ -1682,16 +1602,16 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "hyper 1.5.0", + "http", + "http-body", + "hyper", "pin-project-lite", "socket2", "tokio", @@ -1774,6 +1694,30 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + [[package]] name = "icu_properties" version = "1.5.1" @@ -1850,7 +1794,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1884,12 +1828,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -1900,9 +1855,9 @@ checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" [[package]] name = "image" -version = "0.25.4" +version = "0.25.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc144d44a31d753b02ce64093d532f55ff8dc4ebf2ffb8a63c0dda691385acae" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" dependencies = [ "bytemuck", "byteorder-lite", @@ -1948,7 +1903,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "serde", ] @@ -1980,9 +1935,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.40.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6593a41c7a73841868772495db7dc1e8ecab43bb5c0b6da2059246c4b506ab60" +checksum = "7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8" dependencies = [ "console", "globset", @@ -2123,15 +2078,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.161" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libredox" @@ -2365,7 +2320,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2418,9 +2373,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "open" -version = "5.3.0" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3" +checksum = "3ecd52f0b8d15c40ce4820aa251ed5de032e5d91fab27f7db2f40d42a8bdf69c" dependencies = [ "is-wsl", "libc", @@ -2450,7 +2405,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2498,7 +2453,7 @@ dependencies = [ "by_address", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2590,7 +2545,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2610,9 +2565,9 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -2641,7 +2596,7 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ - "base64 0.22.1", + "base64", "indexmap 2.6.0", "quick-xml 0.32.0", "serde", @@ -2721,18 +2676,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] [[package]] name = "psm" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" +checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" dependencies = [ "cc", ] @@ -2790,45 +2745,49 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.15", + "rustls", "socket2", - "thiserror", + "thiserror 2.0.3", "tokio", "tracing", ] [[package]] name = "quinn-proto" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", + "getrandom", "rand", "ring", "rustc-hash 2.0.0", - "rustls 0.23.15", + "rustls", + "rustls-pki-types", "slab", - "thiserror", + "thiserror 2.0.3", "tinyvec", "tracing", + "web-time", ] [[package]] name = "quinn-udp" -version = "0.5.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" dependencies = [ + "cfg_aliases", "libc", "once_cell", "socket2", @@ -2918,19 +2877,20 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "reflexo" -version = "0.5.0-rc8" -source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=26e2eaa3696845a178df3266edc0019c77396414#26e2eaa3696845a178df3266edc0019c77396414" +version = "0.5.0-rc9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f73eee207a7d665262f6b3930ede406b7db2e946bf4d2da71e9f7d52436e3e9" dependencies = [ - "base64 0.22.1", + "base64", "bitvec", "comemo 0.4.0", "dashmap", - "ecow 0.2.2", + "ecow 0.2.3", "fxhash", "instant", "parking_lot", @@ -2948,12 +2908,13 @@ dependencies = [ [[package]] name = "reflexo-typst" -version = "0.5.0-rc8" -source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=26e2eaa3696845a178df3266edc0019c77396414#26e2eaa3696845a178df3266edc0019c77396414" +version = "0.5.0-rc9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a02123731ac8c421186dfa49e1b3ba6bf47462eab5ef79a5a2e94a1dbada8493" dependencies = [ "codespan-reporting", "comemo 0.4.0", - "ecow 0.2.2", + "ecow 0.2.3", "futures", "fxhash", "indexmap 2.6.0", @@ -2976,8 +2937,9 @@ dependencies = [ [[package]] name = "reflexo-typst-shim" -version = "0.5.0-rc8" -source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=26e2eaa3696845a178df3266edc0019c77396414#26e2eaa3696845a178df3266edc0019c77396414" +version = "0.5.0-rc9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411cf108f3a013c2aeb43afb7ba18efaa8dd0e14464511f5a635f164beda738b" dependencies = [ "cfg-if", "typst", @@ -2986,8 +2948,9 @@ dependencies = [ [[package]] name = "reflexo-typst2vec" -version = "0.5.0-rc8" -source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=26e2eaa3696845a178df3266edc0019c77396414#26e2eaa3696845a178df3266edc0019c77396414" +version = "0.5.0-rc9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ccc7218d4fbf5f370d3efcd4a7082bc4da58461cffb1d2d09399c6de1a7281" dependencies = [ "bitvec", "comemo 0.4.0", @@ -3011,10 +2974,11 @@ dependencies = [ [[package]] name = "reflexo-vec2svg" -version = "0.5.0-rc8" -source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=26e2eaa3696845a178df3266edc0019c77396414#26e2eaa3696845a178df3266edc0019c77396414" +version = "0.5.0-rc9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47518e908a003bb1b2c3d9d45f38903b745306868bfe9755fbec10d2cdd7c5f0" dependencies = [ - "base64 0.22.1", + "base64", "comemo 0.4.0", "log", "reflexo", @@ -3024,8 +2988,9 @@ dependencies = [ [[package]] name = "reflexo-vfs" -version = "0.5.0-rc8" -source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=26e2eaa3696845a178df3266edc0019c77396414#26e2eaa3696845a178df3266edc0019c77396414" +version = "0.5.0-rc9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c0d7b3666f65e95c80d2c546432ccadbc140dad5f67ea193bf5823317ed6eb1" dependencies = [ "indexmap 2.6.0", "log", @@ -3038,14 +3003,15 @@ dependencies = [ [[package]] name = "reflexo-world" -version = "0.5.0-rc8" -source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=26e2eaa3696845a178df3266edc0019c77396414#26e2eaa3696845a178df3266edc0019c77396414" +version = "0.5.0-rc9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96731b1e700e7f62fa27d590ed8f03c139f839ddea9a324e4eb19756ca7968c8" dependencies = [ "chrono", "codespan-reporting", "comemo 0.4.0", "dirs", - "ecow 0.2.2", + "ecow 0.2.3", "flate2", "fontdb", "hex", @@ -3054,7 +3020,7 @@ dependencies = [ "reflexo", "reflexo-typst-shim", "reflexo-vfs", - "reqwest 0.12.8", + "reqwest", "serde", "serde_json", "serde_with", @@ -3066,9 +3032,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -3078,9 +3044,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -3104,66 +3070,21 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.27" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.31", - "hyper-rustls 0.24.2", - "hyper-tls 0.5.0", - "ipnet", - "js-sys", - "log", - "mime", - "mime_guess", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration", - "tokio", - "tokio-native-tls", - "tokio-rustls 0.24.1", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots 0.25.4", - "winreg", -] - -[[package]] -name = "reqwest" -version = "0.12.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" -dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures-channel", "futures-core", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "hyper 1.5.0", - "hyper-rustls 0.27.3", - "hyper-tls 0.6.0", + "hyper", + "hyper-rustls", + "hyper-tls", "hyper-util", "ipnet", "js-sys", @@ -3175,22 +3096,22 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.15", - "rustls-pemfile 2.2.0", + "rustls", + "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper", "tokio", "tokio-native-tls", - "tokio-rustls 0.26.0", + "tokio-rustls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.26.6", + "webpki-roots", "windows-registry", ] @@ -3347,9 +3268,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" dependencies = [ "bitflags 2.6.0", "errno", @@ -3360,39 +3281,18 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.12" +version = "0.23.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.7", - "sct", -] - -[[package]] -name = "rustls" -version = "0.23.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.102.8", + "rustls-webpki", "subtle", "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -3407,15 +3307,8 @@ name = "rustls-pki-types" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring", - "untrusted", + "web-time", ] [[package]] @@ -3483,16 +3376,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "seahash" version = "4.1.0" @@ -3514,9 +3397,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -3533,29 +3416,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "serde_json" -version = "1.0.131" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67d42a0bd4ac281beff598909bb56a86acaf979b84483e1c79c10dcaf98f8cf3" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -3571,7 +3454,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3601,7 +3484,7 @@ version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ - "base64 0.22.1", + "base64", "chrono", "hex", "indexmap 1.9.3", @@ -3622,7 +3505,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3818,7 +3701,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3876,9 +3759,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -3887,7 +3770,7 @@ dependencies = [ [[package]] name = "sync-lsp" -version = "0.12.0" +version = "0.12.2" dependencies = [ "anyhow", "clap", @@ -3905,12 +3788,6 @@ dependencies = [ "tokio-util", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.1" @@ -3928,7 +3805,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3948,32 +3825,11 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "thiserror", + "thiserror 1.0.69", "walkdir", "yaml-rust", ] -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tap" version = "1.0.1" @@ -3982,9 +3838,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" +checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" dependencies = [ "filetime", "libc", @@ -3993,9 +3849,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -4036,7 +3892,7 @@ dependencies = [ [[package]] name = "tests" -version = "0.12.0" +version = "0.12.2" dependencies = [ "insta", "lsp-server", @@ -4054,22 +3910,42 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +dependencies = [ + "thiserror-impl 2.0.3", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] @@ -4139,11 +4015,11 @@ dependencies = [ [[package]] name = "tinymist" -version = "0.12.0" +version = "0.12.2" dependencies = [ "anyhow", "async-trait", - "base64 0.22.1", + "base64", "cargo_metadata", "chrono", "clap", @@ -4160,7 +4036,7 @@ dependencies = [ "env_logger", "futures", "http-body-util", - "hyper 1.5.0", + "hyper", "hyper-tungstenite", "hyper-util", "itertools 0.13.0", @@ -4178,8 +4054,9 @@ dependencies = [ "serde", "serde_json", "serde_yaml", + "strum", "sync-lsp", - "tinymist-assets 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tinymist-assets 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "tinymist-query", "tinymist-render", "tinymist-world", @@ -4205,11 +4082,11 @@ dependencies = [ [[package]] name = "tinymist-analysis" -version = "0.12.0" +version = "0.12.2" dependencies = [ - "base64 0.22.1", + "base64", "comemo 0.4.0", - "ecow 0.2.2", + "ecow 0.2.3", "insta", "log", "regex", @@ -4222,34 +4099,34 @@ dependencies = [ [[package]] name = "tinymist-assets" -version = "0.12.0" +version = "0.12.2" [[package]] name = "tinymist-assets" -version = "0.12.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c544e9b3366dd82252b8d5641f1ff6ac63535e9efe171db3ef73937ef97fa20a" +checksum = "8430e4e5358fcbb04a1f5a6c6503403e0d7bacb6c701f063394de758ade68c75" [[package]] name = "tinymist-derive" -version = "0.12.0" +version = "0.12.2" dependencies = [ "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "tinymist-query" -version = "0.12.0" +version = "0.12.2" dependencies = [ "anyhow", - "base64 0.22.1", + "base64", "biblatex 0.9.3", "chrono", "comemo 0.4.0", "dashmap", "dirs", - "ecow 0.2.2", + "ecow 0.2.3", "ena", "hashbrown 0.14.5", "hex", @@ -4294,9 +4171,9 @@ dependencies = [ [[package]] name = "tinymist-render" -version = "0.12.0" +version = "0.12.2" dependencies = [ - "base64 0.22.1", + "base64", "log", "reflexo-vec2svg", "serde", @@ -4305,25 +4182,23 @@ dependencies = [ [[package]] name = "tinymist-world" -version = "0.12.0" +version = "0.12.2" dependencies = [ "anyhow", "chrono", "clap", "comemo 0.4.0", "dirs", - "flate2", "log", "parking_lot", "reflexo-typst", "reflexo-typst-shim", - "reqwest 0.11.27", "serde", "serde_json", - "tar", - "tinymist-assets 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tinymist-assets 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "typst", "typst-assets", + "typst-kit", ] [[package]] @@ -4354,9 +4229,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -4378,7 +4253,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -4391,23 +4266,13 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.15", + "rustls", "rustls-pki-types", "tokio", ] @@ -4522,7 +4387,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -4570,12 +4435,12 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.1.0", + "http", "httparse", "log", "rand", "sha1", - "thiserror", + "thiserror 1.0.69", "utf-8", ] @@ -4615,11 +4480,11 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "typlite" -version = "0.12.0" +version = "0.12.2" dependencies = [ - "base64 0.22.1", + "base64", "comemo 0.4.0", - "ecow 0.2.2", + "ecow 0.2.3", "insta", "regex", "tinymist-analysis", @@ -4634,7 +4499,7 @@ name = "typlite-cli" version = "0.0.0" dependencies = [ "clap", - "ecow 0.2.2", + "ecow 0.2.3", "tinymist-world", "typlite", ] @@ -4652,7 +4517,7 @@ dependencies = [ "ciborium", "comemo 0.4.0", "csv", - "ecow 0.2.2", + "ecow 0.2.3", "flate2", "fontdb", "hayagriva", @@ -4717,7 +4582,7 @@ dependencies = [ "once_cell", "syntect", "termcolor", - "thiserror", + "thiserror 1.0.69", "two-face 0.3.0", "typst-syntax 0.11.1", ] @@ -4728,6 +4593,26 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fe00da1b24da2c4a7da532fc33d0c3bd43a902ca4c408ee2c36eabe70f2f4ba" +[[package]] +name = "typst-kit" +version = "0.12.0" +source = "git+https://github.com/Myriad-Dreamin/typst.git?tag=tinymist-v0.12.0#58426a90a7ef721738a01be09793d33e55eb75a9" +dependencies = [ + "dirs", + "ecow 0.2.3", + "env_proxy", + "flate2", + "fontdb", + "native-tls", + "once_cell", + "openssl", + "tar", + "typst", + "typst-timing", + "typst-utils", + "ureq", +] + [[package]] name = "typst-macros" version = "0.12.0" @@ -4736,7 +4621,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -4745,10 +4630,10 @@ version = "0.12.0" source = "git+https://github.com/Myriad-Dreamin/typst.git?tag=tinymist-v0.12.0#58426a90a7ef721738a01be09793d33e55eb75a9" dependencies = [ "arrayvec 0.7.6", - "base64 0.22.1", + "base64", "bytemuck", "comemo 0.4.0", - "ecow 0.2.2", + "ecow 0.2.3", "image", "indexmap 2.6.0", "miniz_oxide", @@ -4768,7 +4653,7 @@ dependencies = [ [[package]] name = "typst-preview" -version = "0.12.0" +version = "0.12.2" dependencies = [ "clap", "comemo 0.4.0", @@ -4781,7 +4666,7 @@ dependencies = [ "reflexo-vec2svg", "serde", "serde_json", - "tinymist-assets 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tinymist-assets 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio", "typst", "typst-assets", @@ -4808,7 +4693,7 @@ dependencies = [ [[package]] name = "typst-shim" -version = "0.12.0" +version = "0.12.2" dependencies = [ "cfg-if", "typst", @@ -4820,9 +4705,9 @@ name = "typst-svg" version = "0.12.0" source = "git+https://github.com/Myriad-Dreamin/typst.git?tag=tinymist-v0.12.0#58426a90a7ef721738a01be09793d33e55eb75a9" dependencies = [ - "base64 0.22.1", + "base64", "comemo 0.4.0", - "ecow 0.2.2", + "ecow 0.2.3", "flate2", "ttf-parser 0.24.1", "typst", @@ -4855,7 +4740,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3db69f2f41613b1ff6edbec44fd7dc524137f099ee36c46f560cedeaadb40c4" dependencies = [ "comemo 0.4.0", - "ecow 0.2.2", + "ecow 0.2.3", "once_cell", "serde", "unicode-ident", @@ -4870,7 +4755,7 @@ name = "typst-syntax" version = "0.12.0" source = "git+https://github.com/Myriad-Dreamin/typst.git?tag=tinymist-v0.12.0#58426a90a7ef721738a01be09793d33e55eb75a9" dependencies = [ - "ecow 0.2.2", + "ecow 0.2.3", "once_cell", "serde", "toml 0.8.19", @@ -5051,11 +4936,27 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "ureq" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" +dependencies = [ + "base64", + "flate2", + "log", + "native-tls", + "once_cell", + "serde", + "serde_json", + "url", +] + [[package]] name = "url" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", "idna", @@ -5069,7 +4970,7 @@ version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6803057b5cbb426e9fb8ce2216f3a9b4ca1dd2c705ba3cbebc13006e437735fd" dependencies = [ - "base64 0.22.1", + "base64", "data-url", "flate2", "fontdb", @@ -5096,6 +4997,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -5188,7 +5095,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-shared", ] @@ -5222,7 +5129,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5293,10 +5200,14 @@ dependencies = [ ] [[package]] -name = "webpki-roots" -version = "0.25.4" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] name = "webpki-roots" @@ -5550,14 +5461,10 @@ dependencies = [ ] [[package]] -name = "winreg" -version = "0.50.0" +name = "write16" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] name = "writeable" @@ -5643,7 +5550,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "synstructure", ] @@ -5665,7 +5572,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5685,7 +5592,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "synstructure", ] @@ -5727,7 +5634,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 97a893278..38cac7a9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace.package] description = "An integrated language service for Typst." authors = ["Myriad-Dreamin ", "Nathan Varner"] -version = "0.12.0" +version = "0.12.2" edition = "2021" readme = "README.md" license = "Apache-2.0" @@ -60,7 +60,7 @@ siphasher = "1" comemo = "0.4" # We need to freeze the version of the crate, as the raw-api feature is considered unstable dashmap = { version = "=5.5.3", features = ["raw-api"] } -ecow = "0.2.2" +ecow = "0.2.3" ena = "0.14.2" hashbrown = { version = "0.14", features = [ "inline-more", @@ -92,18 +92,19 @@ env_logger = "0.11.3" log = "0.4" # Typst -reflexo = { version = "0.5.0-rc8", default-features = false, features = [ +reflexo = { version = "0.5.0-rc9", default-features = false, features = [ "flat-vector", ] } -reflexo-world = { version = "0.5.0-rc8", features = ["system"] } -reflexo-typst = { version = "0.5.0-rc8", features = [ +reflexo-world = { version = "0.5.0-rc9", features = ["system"] } +reflexo-typst = { version = "0.5.0-rc9", features = [ "system", ], default-features = false } -reflexo-vec2svg = { version = "0.5.0-rc8" } -reflexo-typst-shim = { version = "0.5.0-rc8", features = ["nightly"] } +reflexo-vec2svg = { version = "0.5.0-rc9" } +reflexo-typst-shim = { version = "0.5.0-rc9", features = ["nightly"] } typst = "0.12.0" +typst-kit = "0.12.0" typst-timing = "0.12.0" typst-svg = "0.12.0" typst-render = "0.12.0" @@ -144,7 +145,7 @@ insta = { version = "1.39", features = ["glob"] } # Our Own Crates typst-preview = { path = "./crates/typst-preview" } -tinymist-assets = { version = "0.12.0" } +tinymist-assets = { version = "0.12.2" } tinymist = { path = "./crates/tinymist/" } tinymist-derive = { path = "./crates/tinymist-derive/" } tinymist-analysis = { path = "./crates/tinymist-analysis/" } @@ -182,6 +183,7 @@ undocumented_unsafe_blocks = "warn" # tinymist-assets = { path = "./crates/tinymist-assets/" } typst = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist-v0.12.0" } +typst-kit = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist-v0.12.0" } typst-timing = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist-v0.12.0" } typst-svg = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist-v0.12.0" } typst-render = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist-v0.12.0" } @@ -195,12 +197,12 @@ typst-syntax = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tin # typst-render = { path = "../typst/crates/typst-render" } # typst-syntax = { path = "../typst/crates/typst-syntax" } -reflexo = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "26e2eaa3696845a178df3266edc0019c77396414" } -reflexo-world = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "26e2eaa3696845a178df3266edc0019c77396414" } -reflexo-typst = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "26e2eaa3696845a178df3266edc0019c77396414" } -reflexo-typst2vec = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "26e2eaa3696845a178df3266edc0019c77396414" } -reflexo-vec2svg = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "26e2eaa3696845a178df3266edc0019c77396414" } -reflexo-typst-shim = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "26e2eaa3696845a178df3266edc0019c77396414" } +# reflexo = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "26e2eaa3696845a178df3266edc0019c77396414" } +# world = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "26e2eaa3696845a178df3266edc0019c77396414" } +# typst = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "26e2eaa3696845a178df3266edc0019c77396414" } +# typst2vec = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "26e2eaa3696845a178df3266edc0019c77396414" } +# vec2svg = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "26e2eaa3696845a178df3266edc0019c77396414" } +# shim = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "26e2eaa3696845a178df3266edc0019c77396414" } # reflexo = { path = "../typst.ts/crates/reflexo/" } # reflexo-world = { path = "../typst.ts/crates/reflexo-world/" } diff --git a/MAINTAINERS.typ b/MAINTAINERS.typ index f2b0d5b3a..d41772da0 100644 --- a/MAINTAINERS.typ +++ b/MAINTAINERS.typ @@ -30,11 +30,16 @@ - #document-previewing - #vs-code-client-side-support ] + - ParaN3xus + - #github("ParaN3xus") + - #email("paran3xus007@gmail.com") + - #maintains[ + - #nightly-releases + ] - Max397 - #github("max397574") - #maintains[ - #editor-integration - ] ] == Features diff --git a/README.md b/README.md index 1c5e646bf..34e30336f 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Language service (LSP) features: - Or ctrl+click on a symbol. - [Hover tips](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#show-hovers) - Also known as "hovering tooltip". + - Render docs according to [tidy](https://github.com/Mc-Zen/tidy) style. - [Inlay hints](https://www.jetbrains.com/help/idea/inlay-hints.html) - Inlay hints are special markers that appear in the editor and provide you with additional information about your code, like the names of the parameters that a called method expects. - [Color Provider](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#show-color-decorators) @@ -55,10 +56,12 @@ Language service (LSP) features: - [Workspace Symbols](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#show-all-symbol-definitions-in-folder) - [Code Action](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-code-actions) - Increasing/Decreasing heading levels. + - Turn equation into "inline", "block" or "multiple-line block" styles. - [experimental/onEnter](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#on-enter) - Enter inside triple-slash comments automatically inserts `///` - Enter in the middle or after a trailing space in `//` inserts `//` - Enter inside `//!` doc comments automatically inserts `//!` + - Enter inside equation markups automatically inserts indents. Extra features: @@ -75,7 +78,7 @@ Extra features: ## Versioning and Release Cycle Tinymist's versions follow the [Semantic Versioning](https://semver.org/) scheme, in format of `MAJOR.MINOR.PATCH`. Besides, tinymist follows special rules for the version number: -- If a version is suffixed with `-rcN` (typst-block), e.g. `0.11.0-rc1` and `0.12.1-rc1`, it means this version is a release candidate. It is used to test publish script and E2E functionalities. These versions will not be published to the marketplace. +- If a version is suffixed with `-rcN` (typst-block), e.g. `0.11.0-rc1` and `0.12.1-rc1`, it means this version is a release candidate. It is used to test publish script and E2E functionalities. These versions will not be published to the marketplace. - If the `PATCH` number is odd, e.g. `0.11.1` and `0.12.3`, it means this version is a nightly release. The nightly release will use both [tinymist](https://github.com/Myriad-Dreamin/tinymist/tree/main) and [typst](https://github.com/typst/typst/tree/main) at **main branch**. They will be published as prerelease version to the marketplace. - Otherwise, if the `PATCH` number is even, e.g. `0.11.0` and `0.12.2`, it means this version is a regular release. The regular release will always use the recent stable version of tinymist and typst. @@ -120,12 +123,30 @@ Nightly Channel: ## Roadmap +The development in typst v0.12.0 has been finished. We'll slow down for a while to catch regressions and bugs by changes. We are also planning to implement the following features in typst v0.13.0 or spare time in weekend: + - Spell checking: There is already a branch but no suitable (default) spell checking library is found. +- Type checking: complete the type checker. +- Static Linter: linting code statically according to feedback of the type checker and succeeding code analysis. - Periscope renderer: It is disabled since vscode reject to render SVGs containing foreignObjects. - Inlay hint: It is disabled _by default_ because of performance issues. - Find references of dictionary fields and named function arguments. -- Go to definition of dictionary fields and named function arguments. +- A reliable way of configuring projects's entry files and files to export across editors. See [GitHub Issue 530.](https://github.com/Myriad-Dreamin/tinymist/issues/530) - Improve symbol view's appearance. +- Improve package view. + - Navigate to symbols by clicking on the symbol name in the view. + - Automatically locate the symbol item in the view when viewing local documentation. + - Remember the recently invoked package commands, e.g. "Open Docs of \@preview/cetz:0.3.1", "Open directory of \@preview/touying:0.5.3". +- Improve label view. + - Group labels. + - Search labels. + - Keep (persist) group preferences. +- Improve Typst Preview. + - Browsing mode: if no main file is specified, the preview will be in browsing mode and use the recently focused file as the main. + - Pin drop-down: Set the file to preview in the drop-down for clients that doesn't support passing arguments to the preview command. + - Render in web worker (another thread) to reduce overhead on the electron's main thread. + +If you are interested by any above features, please feel free to send Issues to discuss or PRs to implement to [GitHub.](https://github.com/Myriad-Dreamin/tinymist) ## Contributing @@ -133,10 +154,12 @@ Please read the [CONTRIBUTING.md](CONTRIBUTING.md) file for contribution guideli ## Maintainers -Get list of maintainers from [MAINTAINERS.typ](MAINTAINERS.typ). Or programmatically by `yarn maintainers` +Get list of maintainers from [MAINTAINERS.typ](https://github.com/Myriad-Dreamin/tinymist/blob/main/MAINTAINERS.typ). Or programmatically by `yarn maintainers` + +> [!NOTE] +> +> You can add extra arguments for specific information. For example, `yarn maintainers --input="action=maintainers"`. -> [!TIP] -> You can add extra arguments for specific information. For example, `yarn maintainers --input="action=maintainers"`. ## Acknowledgements diff --git a/assets/images/introduction.typ-inlined0.svg b/assets/images/introduction.typ-inlined0.svg index 05da4d58e..aeef1ff91 100644 --- a/assets/images/introduction.typ-inlined0.svg +++ b/assets/images/introduction.typ-inlined0.svg @@ -1,5 +1,4 @@ - diff --git a/assets/images/introduction.typ-inlined1.svg b/assets/images/introduction.typ-inlined1.svg index 5d5f7223c..1e61dab07 100644 --- a/assets/images/introduction.typ-inlined1.svg +++ b/assets/images/introduction.typ-inlined1.svg @@ -1,5 +1,4 @@ - diff --git a/crates/sync-lsp/src/lib.rs b/crates/sync-lsp/src/lib.rs index 170fdfb0b..5b06bd3a2 100644 --- a/crates/sync-lsp/src/lib.rs +++ b/crates/sync-lsp/src/lib.rs @@ -173,6 +173,10 @@ impl LspClient { self.req_queue.lock().incoming.has_pending() } + pub fn begin_panic(&self) { + self.req_queue.lock().begin_panic(); + } + /// Sends a request to the client and registers a handler. pub fn send_request_( &self, @@ -526,8 +530,18 @@ where if is_replay { let client = self.client.clone(); let _ = std::thread::spawn(move || { + let since = std::time::Instant::now(); + let timeout = std::env::var("REPLAY_TIMEOUT") + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or(60); client.handle.block_on(async { while client.has_pending_requests() { + if since.elapsed().as_secs() > timeout { + log::error!("replay timeout reached, {timeout}s"); + client.begin_panic(); + } + tokio::time::sleep(std::time::Duration::from_millis(10)).await; } }) diff --git a/crates/sync-lsp/src/req_queue.rs b/crates/sync-lsp/src/req_queue.rs index 5ae32df03..7a7796252 100644 --- a/crates/sync-lsp/src/req_queue.rs +++ b/crates/sync-lsp/src/req_queue.rs @@ -31,6 +31,17 @@ impl fmt::Debug for ReqQueue { } } +impl ReqQueue { + pub fn begin_panic(&self) { + let keys = self.incoming.pending.keys().cloned().collect::>(); + log::error!("incoming pending: {keys:?}"); + let keys = self.outgoing.pending.keys().cloned().collect::>(); + log::error!("outgoing pending: {keys:?}"); + + panic!("req queue panicking"); + } +} + #[derive(Debug)] pub struct Incoming { pending: HashMap, diff --git a/crates/tinymist-query/src/adt/mod.rs b/crates/tinymist-query/src/adt/mod.rs index 56b3275a2..74dfb870c 100644 --- a/crates/tinymist-query/src/adt/mod.rs +++ b/crates/tinymist-query/src/adt/mod.rs @@ -1,2 +1,3 @@ pub mod interner; +pub mod revision; pub mod snapshot_map; diff --git a/crates/tinymist-query/src/adt/revision.rs b/crates/tinymist-query/src/adt/revision.rs new file mode 100644 index 000000000..a7279075c --- /dev/null +++ b/crates/tinymist-query/src/adt/revision.rs @@ -0,0 +1,136 @@ +use std::{ + collections::HashMap, + num::NonZeroUsize, + sync::{Arc, OnceLock}, +}; + +pub struct RevisionLock { + estimated: usize, + used: OnceLock, +} + +impl RevisionLock { + pub fn access(&self, revision: NonZeroUsize) { + self.used + .set(revision.get()) + .unwrap_or_else(|_| panic!("revision {revision} is determined")) + } +} + +pub struct RevisionSlot { + pub revision: usize, + pub data: T, +} + +impl std::ops::Deref for RevisionSlot { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.data + } +} + +impl std::ops::DerefMut for RevisionSlot { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.data + } +} + +pub struct RevisionManager { + estimated: usize, + locked: HashMap, + slots: Vec>>, +} + +impl Default for RevisionManager { + fn default() -> Self { + Self { + estimated: 0, + locked: Default::default(), + slots: Default::default(), + } + } +} + +impl RevisionManager { + pub fn clear(&mut self) { + self.slots.clear(); + } + + /// Lock the revision in *main thread*. + #[must_use] + pub fn lock(&mut self, used: NonZeroUsize) -> RevisionLock { + let l = self.lock_estimated(); + l.access(used); + l + } + + /// Lock the revision in *main thread*. + #[must_use] + pub fn lock_estimated(&mut self) -> RevisionLock { + let estimated = self.estimated; + *self.locked.entry(estimated).or_default() += 1; + RevisionLock { + estimated, + used: OnceLock::new(), + } + } + + /// Find the last revision slot by revision number. + pub fn find_revision( + &mut self, + revision: NonZeroUsize, + f: impl FnOnce(Option<&Arc>>) -> T, + ) -> Arc> { + let slot_base = self + .slots + .iter() + .filter(|e| e.revision <= revision.get()) + .reduce(|a, b| if a.revision > b.revision { a } else { b }); + + if let Some(slot) = slot_base { + if slot.revision == revision.get() { + return slot.clone(); + } + } + + let slot = Arc::new(RevisionSlot { + revision: revision.get(), + data: f(slot_base), + }); + self.slots.push(slot.clone()); + self.estimated = revision.get().max(self.estimated); + slot + } + + pub fn unlock(&mut self, rev: &mut RevisionLock) -> Option { + let rev = rev.estimated; + let revision_cnt = self + .locked + .entry(rev) + .or_insert_with(|| panic!("revision {rev} is not locked")); + *revision_cnt -= 1; + if *revision_cnt != 0 { + return None; + } + + self.locked.remove(&rev); + let existing = self.locked.keys().min().copied(); + existing.or_else(|| + // if there is no locked revision, we only keep the latest revision + self.slots + .iter() + .map(|e| e.revision) + .max()) + } +} + +pub trait RevisionManagerLike { + fn gc(&mut self, min_rev: usize); +} + +impl RevisionManagerLike for RevisionManager { + fn gc(&mut self, min_rev: usize) { + self.slots.retain(|r| r.revision >= min_rev); + } +} diff --git a/crates/tinymist-query/src/analysis.rs b/crates/tinymist-query/src/analysis.rs index 6b78c6de3..110e21e28 100644 --- a/crates/tinymist-query/src/analysis.rs +++ b/crates/tinymist-query/src/analysis.rs @@ -1,6 +1,8 @@ //! Semantic static and dynamic analysis of the source code. mod bib; +use std::path::Path; + pub(crate) use bib::*; pub mod call; pub use call::*; @@ -14,6 +16,10 @@ pub mod definition; pub use definition::*; pub mod signature; pub use signature::*; +pub mod semantic_tokens; +pub use semantic_tokens::*; +use typst::syntax::{Source, VirtualPath}; +use typst::World; mod post_tyck; mod tyck; pub(crate) use crate::ty::*; @@ -26,8 +32,14 @@ mod prelude; mod global; pub use global::*; +use ecow::eco_format; +use lsp_types::Url; +use reflexo_typst::{EntryReader, TypstFileId}; +use typst::diag::{FileError, FileResult}; use typst::foundations::{Func, Value}; +use crate::path_to_url; + pub(crate) trait ToFunc { fn to_func(&self) -> Option; } @@ -42,6 +54,46 @@ impl ToFunc for Value { } } +/// Extension trait for `typst::World`. +pub trait LspWorldExt { + /// Get file's id by its path + fn file_id_by_path(&self, p: &Path) -> FileResult; + + /// Get the source of a file by file path. + fn source_by_path(&self, p: &Path) -> FileResult; + + /// Resolve the uri for a file id. + fn uri_for_id(&self, id: TypstFileId) -> FileResult; +} + +impl LspWorldExt for tinymist_world::LspWorld { + fn file_id_by_path(&self, p: &Path) -> FileResult { + // todo: source in packages + let root = self.workspace_root().ok_or_else(|| { + let reason = eco_format!("workspace root not found"); + FileError::Other(Some(reason)) + })?; + let relative_path = p.strip_prefix(&root).map_err(|_| { + let reason = eco_format!("access denied, path: {p:?}, root: {root:?}"); + FileError::Other(Some(reason)) + })?; + + Ok(TypstFileId::new(None, VirtualPath::new(relative_path))) + } + + fn source_by_path(&self, p: &Path) -> FileResult { + // todo: source cache + self.source(self.file_id_by_path(p)?) + } + + fn uri_for_id(&self, id: TypstFileId) -> Result { + self.path_for_id(id).and_then(|e| { + path_to_url(&e) + .map_err(|e| FileError::Other(Some(eco_format!("convert to url: {e:?}")))) + }) + } +} + #[cfg(test)] mod matcher_tests { @@ -364,7 +416,7 @@ mod type_describe_tests { description => format!("Check on {text:?} ({pos:?})"), }, { let literal_type = literal_type.and_then(|e| e.describe()) - .unwrap_or_else(|| "".to_string()); + .unwrap_or_else(|| "".into()); assert_snapshot!(literal_type); }) }); diff --git a/crates/tinymist-query/src/analysis/definition.rs b/crates/tinymist-query/src/analysis/definition.rs index edccc3a01..4a8e93e6f 100644 --- a/crates/tinymist-query/src/analysis/definition.rs +++ b/crates/tinymist-query/src/analysis/definition.rs @@ -121,9 +121,12 @@ fn find_field_definition(ctx: &Arc, fa: ast::FieldAccess<'_>) -> log::debug!("field var: {:?} {:?}", v.def, v.def.span()); Some(Definition::new(v.def.clone(), None)) } - _src @ (DocSource::Builtin(..) | DocSource::Ins(..)) => { - todo!() + DocSource::Ins(v) if !v.span().is_detached() => { + let s = v.span(); + let source = ctx.source_by_id(s.id()?).ok()?; + DefResolver::new(ctx, &source)?.of_span(s) } + DocSource::Builtin(..) | DocSource::Ins(..) => None, } } diff --git a/crates/tinymist-query/src/analysis/global.rs b/crates/tinymist-query/src/analysis/global.rs index 44a15bfe0..29166e367 100644 --- a/crates/tinymist-query/src/analysis/global.rs +++ b/crates/tinymist-query/src/analysis/global.rs @@ -22,11 +22,13 @@ use typst::model::Document; use typst::syntax::package::PackageManifest; use typst::syntax::{package::PackageSpec, Span, VirtualPath}; +use crate::adt::revision::{RevisionLock, RevisionManager, RevisionManagerLike, RevisionSlot}; use crate::analysis::prelude::*; use crate::analysis::{ analyze_bib, analyze_expr_, analyze_import_, analyze_signature, definition, post_type_check, - AllocStats, AnalysisStats, BibInfo, Definition, PathPreference, QueryStatGuard, Signature, - SignatureTarget, Ty, TypeScheme, + AllocStats, AnalysisStats, BibInfo, Definition, PathPreference, QueryStatGuard, + SemanticTokenCache, SemanticTokenContext, SemanticTokens, Signature, SignatureTarget, Ty, + TypeScheme, }; use crate::docs::{DefDocs, TidyModuleDocs}; use crate::syntax::{ @@ -34,10 +36,10 @@ use crate::syntax::{ scan_workspace_files, Decl, DefKind, DerefTarget, ExprInfo, ExprRoute, LexicalScope, ModuleDependency, }; -use crate::upstream::{tooltip_, Tooltip}; +use crate::upstream::{tooltip_, CompletionFeat, Tooltip}; use crate::{ - lsp_to_typst, path_to_url, typst_to_lsp, ColorTheme, LspPosition, LspRange, PositionEncoding, - SemanticTokenContext, TypstRange, VersionedDocument, + lsp_to_typst, typst_to_lsp, ColorTheme, CompilerQueryRequest, LspPosition, LspRange, + LspWorldExt, PositionEncoding, TypstRange, VersionedDocument, }; use super::TypeEnv; @@ -47,18 +49,26 @@ use super::TypeEnv; pub struct Analysis { /// The position encoding for the workspace. pub position_encoding: PositionEncoding, + /// Whether to allow overlapping semantic tokens. + pub allow_overlapping_token: bool, + /// Whether to allow multiline semantic tokens. + pub allow_multiline_token: bool, + /// Whether to remove html from markup content in responses. + pub remove_html: bool, + /// Tinymist's completion features. + pub completion_feat: CompletionFeat, /// The editor's color theme. pub color_theme: ColorTheme, /// The periscope provider. pub periscope: Option>, - /// The semantic token context. - pub tokens_ctx: Arc, /// The global worker resources for analysis. pub workers: Arc, + /// The semantic token cache. + pub tokens_caches: Arc>, /// The global caches for analysis. pub caches: AnalysisGlobalCaches, - /// The global cache grid for analysis. - pub cache_grid: Arc>, + /// The revisioned cache for analysis. + pub analysis_rev_cache: Arc>, /// The statistics about the analyzers. pub stats: Arc, } @@ -66,10 +76,21 @@ pub struct Analysis { impl Analysis { /// Get a snapshot of the analysis data. pub fn snapshot(&self, world: LspWorld) -> LocalContextGuard { + self.snapshot_(world, self.lock_revision(None)) + } + + /// Get a snapshot of the analysis data. + pub fn snapshot_(&self, world: LspWorld, mut lg: AnalysisRevLock) -> LocalContextGuard { let lifetime = self.caches.lifetime.fetch_add(1, Ordering::SeqCst); - let slot = self.cache_grid.lock().find_revision(world.revision()); + let slot = self + .analysis_rev_cache + .lock() + .find_revision(world.revision(), &lg); + let tokens = lg.tokens.take(); LocalContextGuard { + rev_lock: lg, local: LocalContext { + tokens, caches: AnalysisCaches::default(), shared: Arc::new(SharedContext { slot, @@ -83,22 +104,36 @@ impl Analysis { /// Lock the revision in *main thread*. #[must_use] - pub fn lock_revision(&self) -> RevisionLock { - let mut grid = self.cache_grid.lock(); - let revision = grid.revision; - *grid.locked_revisions.entry(revision).or_default() += 1; - RevisionLock { - grid: self.cache_grid.clone(), - revision, + pub fn lock_revision(&self, q: Option<&CompilerQueryRequest>) -> AnalysisRevLock { + let mut grid = self.analysis_rev_cache.lock(); + + AnalysisRevLock { + tokens: match q { + Some(CompilerQueryRequest::SemanticTokensFull(f)) => Some( + SemanticTokenCache::acquire(self.tokens_caches.clone(), &f.path, None), + ), + Some(CompilerQueryRequest::SemanticTokensDelta(f)) => { + Some(SemanticTokenCache::acquire( + self.tokens_caches.clone(), + &f.path, + Some(&f.previous_result_id), + )) + } + _ => None, + }, + inner: grid.manager.lock_estimated(), + grid: self.analysis_rev_cache.clone(), } } /// Clear all cached resources. pub fn clear_cache(&self) { self.caches.signatures.clear(); + self.caches.def_signatures.clear(); self.caches.static_signatures.clear(); self.caches.terms.clear(); - self.cache_grid.lock().clear(); + self.tokens_caches.lock().clear(); + self.analysis_rev_cache.lock().clear(); } /// Report the statistics of the analysis. @@ -110,6 +145,36 @@ impl Analysis { pub fn report_alloc_stats(&self) -> String { AllocStats::report(self) } + + /// Get configured trigger parameter hints command. + pub fn trigger_parameter_hints(&self, context: bool) -> Option<&'static str> { + (self.completion_feat.trigger_parameter_hints && context) + .then_some("editor.action.triggerParameterHints") + } + + /// Get configured trigger after snippet command. + /// + /// > VS Code doesn't do that... Auto triggering suggestion only happens on + /// > typing (word starts or trigger characters). However, you can use + /// > editor.action.triggerSuggest as command on a suggestion to "manually" + /// > retrigger suggest after inserting one + pub fn trigger_on_snippet(&self, context: bool) -> Option<&'static str> { + if !self.completion_feat.trigger_on_snippet_placeholders { + return None; + } + + (self.completion_feat.trigger_suggest && context).then_some("editor.action.triggerSuggest") + } + + /// Get configured trigger on positional parameter hints command. + pub fn trigger_on_snippet_with_param_hint(&self, context: bool) -> Option<&'static str> { + if !self.completion_feat.trigger_on_snippet_placeholders { + return self.trigger_parameter_hints(context); + } + + (self.completion_feat.trigger_suggest_and_parameter_hints && context) + .then_some("tinymist.triggerSuggestAndParameterHints") + } } /// The periscope provider. @@ -140,6 +205,8 @@ pub struct AnalysisGlobalWorkers { pub struct LocalContextGuard { /// Constructed local context pub local: LocalContext, + /// The revision lock + pub rev_lock: AnalysisRevLock, } impl Deref for LocalContextGuard { @@ -185,27 +252,19 @@ impl LocalContextGuard { break; } - self.analysis - .caches - .def_signatures - .retain(|(l, _)| lifetime - *l < 60); - self.analysis - .caches - .static_signatures - .retain(|(l, _)| lifetime - *l < 60); - self.analysis - .caches - .terms - .retain(|(l, _)| lifetime - *l < 60); - self.analysis - .caches - .signatures - .retain(|(l, _)| lifetime - *l < 60); + let retainer = |l: u64| lifetime.saturating_sub(l) < 60; + let caches = &self.analysis.caches; + caches.def_signatures.retain(|(l, _)| retainer(*l)); + caches.static_signatures.retain(|(l, _)| retainer(*l)); + caches.terms.retain(|(l, _)| retainer(*l)); + caches.signatures.retain(|(l, _)| retainer(*l)); } } /// The local context for analyzers. pub struct LocalContext { + /// The created semantic token context. + pub(crate) tokens: Option, /// Local caches for analysis. pub caches: AnalysisCaches, /// The shared context @@ -336,6 +395,20 @@ impl LocalContext { self.analyze_import(mod_import_node.source().to_untyped()).1 } + pub(crate) fn cached_tokens(&mut self, source: &Source) -> (SemanticTokens, Option) { + let tokens = crate::analysis::semantic_tokens::get_semantic_tokens(self, source); + + let result_id = self.tokens.as_ref().map(|t| { + let id = t.next.revision; + t.next + .data + .set(tokens.clone()) + .unwrap_or_else(|_| panic!("unexpected slot overwrite {id}")); + id.to_string() + }); + (tokens, result_id) + } + /// Get the expression information of a source file. pub(crate) fn expr_stage_by_id(&mut self, fid: TypstFileId) -> Option> { Some(self.expr_stage(&self.source_by_id(fid).ok()?)) @@ -355,13 +428,33 @@ impl LocalContext { cache.get_or_init(|| self.shared.type_check(source)).clone() } + /// Get the type check information of a source file. + pub(crate) fn type_check_by_id(&mut self, id: TypstFileId) -> Arc { + let cache = &self.caches.modules.entry(id).or_default().type_check; + cache + .clone() + .get_or_init(|| { + let source = self.source_by_id(id).ok(); + source + .map(|s| self.shared.type_check(&s)) + .unwrap_or_default() + }) + .clone() + } + + pub(crate) fn type_of_span(&mut self, s: Span) -> Option { + let scheme = self.type_check_by_id(s.id()?); + let ty = scheme.type_of_span(s)?; + Some(scheme.simplify(ty, false)) + } + pub(crate) fn def_docs(&mut self, def: &Definition) -> Option { // let plain_docs = sym.head.docs.as_deref(); // let plain_docs = plain_docs.or(sym.head.oneliner.as_deref()); match def.decl.kind() { DefKind::Function => { let sig = self.sig_of_def(def.clone())?; - let docs = crate::docs::sig_docs(&sig, None)?; + let docs = crate::docs::sig_docs(&sig)?; Some(DefDocs::Function(Box::new(docs))) } DefKind::Struct | DefKind::Constant | DefKind::Variable => { @@ -387,8 +480,8 @@ pub struct SharedContext { pub world: LspWorld, /// The analysis data pub analysis: Analysis, - /// The using revision slot - slot: Arc, + /// The using analysis revision slot + slot: Arc>, } impl SharedContext { @@ -452,25 +545,12 @@ impl SharedContext { /// Resolve the uri for a file id. pub fn uri_for_id(&self, id: TypstFileId) -> Result { - self.path_for_id(id).and_then(|e| { - path_to_url(&e) - .map_err(|e| FileError::Other(Some(eco_format!("convert to url: {e:?}")))) - }) + self.world.uri_for_id(id) } /// Get file's id by its path pub fn file_id_by_path(&self, p: &Path) -> FileResult { - // todo: source in packages - let root = self.world.workspace_root().ok_or_else(|| { - let reason = eco_format!("workspace root not found"); - FileError::Other(Some(reason)) - })?; - let relative_path = p.strip_prefix(&root).map_err(|_| { - let reason = eco_format!("access denied, path: {p:?}, root: {root:?}"); - FileError::Other(Some(reason)) - })?; - - Ok(TypstFileId::new(None, VirtualPath::new(relative_path))) + self.world.file_id_by_path(p) } /// Get the content of a file by file id. @@ -485,7 +565,6 @@ impl SharedContext { /// Get the source of a file by file path. pub fn source_by_path(&self, p: &Path) -> FileResult { - // todo: source cache self.source_by_id(self.file_id_by_path(p)?) } @@ -693,7 +772,7 @@ impl SharedContext { return cached; } - let res = crate::analysis::term_value(self, val); + let res = crate::analysis::term_value(val); self.analysis .caches @@ -732,10 +811,6 @@ impl SharedContext { definition(self, source, doc, deref_target) } - pub(crate) fn type_of(self: &Arc, rr: &SyntaxNode) -> Option { - self.type_of_span(rr.span()) - } - pub(crate) fn type_of_span(self: &Arc, s: Span) -> Option { self.type_of_span_(&self.source_by_id(s.id()?).ok()?, s) } @@ -760,9 +835,8 @@ impl SharedContext { analyze_signature(self, SignatureTarget::Def(source, def)) } - pub(crate) fn sig_of_func(self: &Arc, func: Func) -> Signature { - log::debug!("check runtime func {func:?}"); - analyze_signature(self, SignatureTarget::Runtime(func)).unwrap() + pub(crate) fn sig_of_type(self: &Arc, ti: &TypeScheme, ty: Ty) -> Option { + super::sig_of_type(self, ti, ty) } /// Try to find imported target from the current source file. @@ -858,6 +932,20 @@ impl SharedContext { res.get_or_init(|| compute(self)).clone() } + /// Remove html tags from markup content if necessary. + pub fn remove_html(&self, markup: EcoString) -> EcoString { + if !self.analysis.remove_html { + return markup; + } + + static REMOVE_HTML_COMMENT_REGEX: LazyLock = + LazyLock::new(|| regex::Regex::new(r#""#).unwrap()); + REMOVE_HTML_COMMENT_REGEX + .replace_all(&markup, "") + .trim() + .into() + } + fn query_stat(&self, id: TypstFileId, query: &'static str) -> QueryStatGuard { let stats = &self.analysis.stats.query_stats; let entry = stats.entry(id).or_default(); @@ -1050,104 +1138,94 @@ pub struct ModuleAnalysisCache { /// The grid cache for all level of analysis results of a module. #[derive(Default)] -pub struct AnalysisGlobalCacheGrid { - revision: usize, - default_slot: RevisionSlot, - revisions: Vec>, - locked_revisions: HashMap, +pub struct AnalysisRevCache { + default_slot: AnalysisRevSlot, + manager: RevisionManager, } -impl AnalysisGlobalCacheGrid { - fn clear(&mut self) { - self.revisions.clear(); - } - +impl RevisionManagerLike for AnalysisRevCache { fn gc(&mut self, rev: usize) { - self.revisions.retain(|r| r.revision >= rev); - self.default_slot - .expr_stage - .global - .lock() - .retain(|_, r| r.0 + 60 >= rev); - self.default_slot - .type_check - .global - .lock() - .retain(|_, r| r.0 + 60 >= rev); - } - - /// Find the last revision slot by revision number. - fn find_revision(&mut self, revision: NonZeroUsize) -> Arc { - let slot_base = self - .revisions - .iter() - .filter(|e| e.revision <= revision.get()) - .reduce(|a, b| if a.revision > b.revision { a } else { b }); + self.manager.gc(rev); + + { + let mut max_ei = FxHashMap::default(); + let es = self.default_slot.expr_stage.global.lock(); + for r in es.iter() { + let rev: &mut usize = max_ei.entry(r.1.fid).or_default(); + *rev = (*rev).max(r.1.revision); + } + es.retain(|_, r| r.1.revision == *max_ei.get(&r.1.fid).unwrap_or(&0)); + } - if let Some(slot) = slot_base { - if slot.revision == revision.get() { - return slot.clone(); + { + let mut max_ti = FxHashMap::default(); + let ts = self.default_slot.type_check.global.lock(); + for r in ts.iter() { + let rev: &mut usize = max_ti.entry(r.1.fid).or_default(); + *rev = (*rev).max(r.1.revision); } + ts.retain(|_, r| r.1.revision == *max_ti.get(&r.1.fid).unwrap_or(&0)); } + } +} - let mut slot = slot_base - .map(|e| RevisionSlot { - revision: e.revision, - expr_stage: e.expr_stage.crawl(revision.get()), - type_check: e.type_check.crawl(revision.get()), - }) - .unwrap_or_else(|| self.default_slot.clone()); +impl AnalysisRevCache { + fn clear(&mut self) { + self.manager.clear(); + self.default_slot = Default::default(); + } - slot.revision = revision.get(); - let slot = Arc::new(slot); - self.revisions.push(slot.clone()); - self.revision = revision.get().max(self.revision); - slot + /// Find the last revision slot by revision number. + fn find_revision( + &mut self, + revision: NonZeroUsize, + lg: &AnalysisRevLock, + ) -> Arc> { + lg.inner.access(revision); + self.manager.find_revision(revision, |slot_base| { + log::info!("analysis revision {} is created", revision.get()); + slot_base + .map(|e| AnalysisRevSlot { + revision: e.revision, + expr_stage: e.data.expr_stage.crawl(revision.get()), + type_check: e.data.type_check.crawl(revision.get()), + }) + .unwrap_or_else(|| self.default_slot.clone()) + }) } } /// A lock for revision. -pub struct RevisionLock { - grid: Arc>, - revision: usize, +pub struct AnalysisRevLock { + inner: RevisionLock, + tokens: Option, + grid: Arc>, } -impl Drop for RevisionLock { +impl Drop for AnalysisRevLock { fn drop(&mut self) { - let mut grid = self.grid.lock(); - let revision_cnt = grid - .locked_revisions - .entry(self.revision) - .or_insert_with(|| panic!("revision {} is not locked", self.revision)); - *revision_cnt -= 1; - if *revision_cnt != 0 { - return; - } + let mut mu = self.grid.lock(); + let gc_revision = mu.manager.unlock(&mut self.inner); - grid.locked_revisions.remove(&self.revision); - if grid.revision <= self.revision { - return; + if let Some(gc_revision) = gc_revision { + let grid = self.grid.clone(); + rayon::spawn(move || { + grid.lock().gc(gc_revision); + }); } - let existing = grid.locked_revisions.keys().min().copied(); - let gc_revision = existing.unwrap_or(self.revision); - let grid = self.grid.clone(); - - rayon::spawn(move || { - grid.lock().gc(gc_revision); - }); } } #[derive(Default, Clone)] -struct RevisionSlot { +struct AnalysisRevSlot { revision: usize, expr_stage: IncrCacheMap>, type_check: IncrCacheMap>, } -impl Drop for RevisionSlot { +impl Drop for AnalysisRevSlot { fn drop(&mut self) { - log::info!("revision {} is dropped", self.revision) + log::info!("analysis revision {} is dropped", self.revision); } } diff --git a/crates/tinymist-query/src/analysis/link_exprs.rs b/crates/tinymist-query/src/analysis/link_exprs.rs index 64fa3d057..88e4db084 100644 --- a/crates/tinymist-query/src/analysis/link_exprs.rs +++ b/crates/tinymist-query/src/analysis/link_exprs.rs @@ -1,32 +1,75 @@ //! Analyze color expressions in a source file. +use std::str::FromStr; + use lsp_types::Url; +use reflexo_typst::package::PackageSpec; use super::prelude::*; -use crate::path_to_url; /// Get link expressions from a source. -pub fn get_link_exprs(ctx: &mut LocalContext, src: &Source) -> Option, Url)>> { +#[comemo::memoize] +pub fn get_link_exprs(src: &Source) -> Arc { let root = LinkedNode::new(src.root()); - get_link_exprs_in(ctx, &root) + Arc::new(get_link_exprs_in(&root).unwrap_or_default()) } /// Get link expressions in a source node. -pub fn get_link_exprs_in( - ctx: &mut LocalContext, - node: &LinkedNode, -) -> Option, Url)>> { - let mut worker = LinkStrWorker { ctx, links: vec![] }; +pub fn get_link_exprs_in(node: &LinkedNode) -> Option { + let mut worker = LinkStrWorker { + info: LinkInfo::default(), + }; worker.collect_links(node)?; - Some(worker.links) + Some(worker.info) +} + +/// A valid link target. +pub enum LinkTarget { + /// A package specification. + Package(Box), + /// A URL. + Url(Box), + /// A file path. + Path(TypstFileId, EcoString), +} + +impl LinkTarget { + pub(crate) fn resolve(&self, ctx: &mut LocalContext) -> Option { + match self { + LinkTarget::Package(..) => None, + LinkTarget::Url(url) => Some(url.as_ref().clone()), + LinkTarget::Path(id, path) => { + // Avoid creating new ids here. + let base = id.vpath().join(path.as_str()); + let root = ctx.path_for_id(id.join("/")).ok()?; + crate::path_to_url(&base.resolve(&root)?).ok() + } + } + } +} + +/// A link object in a source file. +pub struct LinkObject { + /// The range of the link expression. + pub range: Range, + /// The span of the link expression. + pub span: Span, + /// The target of the link. + pub target: LinkTarget, +} + +/// Link information in a source file. +#[derive(Default)] +pub struct LinkInfo { + /// The link objects in a source file. + pub objects: Vec, } -struct LinkStrWorker<'a> { - ctx: &'a mut LocalContext, - links: Vec<(Range, Url)>, +struct LinkStrWorker { + info: LinkInfo, } -impl<'a> LinkStrWorker<'a> { +impl LinkStrWorker { fn collect_links(&mut self, node: &LinkedNode) -> Option<()> { match node.kind() { // SyntaxKind::Link => { } @@ -36,6 +79,11 @@ impl<'a> LinkStrWorker<'a> { return Some(()); } } + SyntaxKind::Include => { + let inc = node.cast::()?; + let path = inc.source(); + self.analyze_path_exp(node, path); + } // early exit k if k.is_trivia() || k.is_keyword() || k.is_error() => return Some(()), _ => {} @@ -128,32 +176,28 @@ impl<'a> LinkStrWorker<'a> { fn analyze_path_str(&mut self, node: &LinkedNode, s: ast::Str<'_>) -> Option<()> { let str_node = node.find(s.span())?; let str_range = str_node.range(); - let content_range = str_range.start + 1..str_range.end - 1; - if content_range.is_empty() { + let range = str_range.start + 1..str_range.end - 1; + if range.is_empty() { return None; } - // Avoid creating new ids here. - let id = node.span().id()?; - let base = id.vpath().join(s.get().as_str()); - let root = self.ctx.path_for_id(id.join("/")).ok()?; - let path = base.resolve(&root)?; - if !path.exists() { - return None; + let content = s.get(); + if content.starts_with('@') { + let pkg_spec = PackageSpec::from_str(&content).ok()?; + self.info.objects.push(LinkObject { + range, + span: s.span(), + target: LinkTarget::Package(Box::new(pkg_spec)), + }); + return Some(()); } - self.push_path(content_range, path.as_path()) - } - - fn push_path(&mut self, range: Range, path: &Path) -> Option<()> { - self.push_link(range, path_to_url(path).ok()?) - } - - fn push_link(&mut self, range: Range, target: Url) -> Option<()> { - // let rng = self.ctx.to_lsp_range(range, &self.source); - - self.links.push((range, target)); - + let id = node.span().id()?; + self.info.objects.push(LinkObject { + range, + span: s.span(), + target: LinkTarget::Path(id, content), + }); Some(()) } } diff --git a/crates/tinymist-query/src/analysis/post_tyck.rs b/crates/tinymist-query/src/analysis/post_tyck.rs index 806821ddd..321e04f9b 100644 --- a/crates/tinymist-query/src/analysis/post_tyck.rs +++ b/crates/tinymist-query/src/analysis/post_tyck.rs @@ -3,10 +3,10 @@ use hashbrown::HashSet; use tinymist_derive::BindTyCtx; -use super::{prelude::*, SharedContext}; +use super::{prelude::*, ParamAttrs, ParamTy, SharedContext}; use super::{ - ArgsTy, FieldTy, Sig, SigChecker, SigShape, SigSurfaceKind, SigTy, Ty, TyCtx, TyCtxMut, - TypeBounds, TypeScheme, TypeVar, + ArgsTy, Sig, SigChecker, SigShape, SigSurfaceKind, SigTy, Ty, TyCtx, TyCtxMut, TypeBounds, + TypeScheme, TypeVar, }; use crate::syntax::{get_check_target, get_check_target_by_context, CheckTarget, ParamTarget}; @@ -17,7 +17,9 @@ pub(crate) fn post_type_check( info: &TypeScheme, node: LinkedNode, ) -> Option { - PostTypeChecker::new(ctx, info).check(&node) + let mut checker = PostTypeChecker::new(ctx, info); + let res = checker.check(&node); + checker.simplify(&res?) } #[derive(Default)] @@ -28,14 +30,14 @@ struct SignatureReceiver { } impl SignatureReceiver { - fn insert(&mut self, ty: &Ty, pol: bool) { + fn insert(&mut self, ty: Ty, pol: bool) { log::debug!("post check receive: {ty:?}"); if !pol { if self.lbs_dedup.insert(ty.clone()) { - self.bounds.lbs.push(ty.clone()); + self.bounds.lbs.push(ty); } } else if self.ubs_dedup.insert(ty.clone()) { - self.bounds.ubs.push(ty.clone()); + self.bounds.ubs.push(ty); } } @@ -49,13 +51,18 @@ fn check_signature<'a>( target: &'a ParamTarget, ) -> impl FnMut(&mut PostTypeChecker, Sig, &[Interned], bool) -> Option<()> + 'a { move |worker, sig, args, pol| { + let (sig, _is_partialize) = match sig { + Sig::Partialize(sig) => (*sig, true), + sig => (sig, false), + }; + let SigShape { sig: sig_ins, .. } = sig.shape(worker)?; match &target { ParamTarget::Named(n) => { let ident = n.cast::()?; let ty = sig_ins.named(&ident.into())?; - receiver.insert(ty, !pol); + receiver.insert(ty.clone(), !pol); Some(()) } @@ -70,20 +77,19 @@ fn check_signature<'a>( } // truncate args - let c = args + let bound_pos = args .iter() .map(|args| args.positional_params().len()) .sum::(); - let nth = sig_ins.pos(c + positional).or_else(|| sig_ins.rest_param()); - if let Some(nth) = nth { + if let Some(nth) = sig_ins.pos_or_rest(bound_pos + positional) { receiver.insert(nth, !pol); } // names for (name, _) in sig_ins.named_params() { // todo: reduce fields, fields ty - let field = FieldTy::new_untyped(name.clone()); - receiver.insert(&Ty::Field(field), !pol); + let field = ParamTy::new_untyped(name.clone(), ParamAttrs::named()); + receiver.insert(Ty::Param(field), !pol); } Some(()) @@ -160,17 +166,29 @@ impl<'a> PostTypeChecker<'a> { ty } + fn simplify(&mut self, ty: &Ty) -> Option { + Some(self.info.simplify(ty.clone(), false)) + } + fn check_(&mut self, node: &LinkedNode) -> Option { let context = node.parent()?; log::debug!("post check: {:?}::{:?}", context.kind(), node.kind()); - let checked_context = self.check_context(context, node); - let res = self.check_self(context, node, checked_context); + + let context_ty = self.check_context(context, node); + let self_ty = if !matches!(node.kind(), SyntaxKind::Label | SyntaxKind::Ref) { + self.info.type_of_span(node.span()) + } else { + None + }; + + let contextual_self_ty = self.check_target(get_check_target(node.clone()), context_ty); log::debug!( - "post check(res): {:?}::{:?} -> {res:?}", + "post check(res): {:?}::{:?} -> {self_ty:?}, {contextual_self_ty:?}", context.kind(), node.kind(), ); - res + + Ty::or(self_ty, contextual_self_ty) } fn check_context_or(&mut self, context: &LinkedNode, context_ty: Option) -> Option { @@ -201,12 +219,50 @@ impl<'a> PostTypeChecker<'a> { let callee = self.check_context_or(&callee, context_ty)?; log::debug!("post check call target: ({callee:?})::{target:?} is_set: {is_set}"); + let sig = self.ctx.sig_of_type(self.info, callee)?; + log::debug!("post check call sig: {target:?} {sig:?}"); let mut resp = SignatureReceiver::default(); - self.check_signatures(&callee, false, &mut check_signature(&mut resp, &target)); + match &target { + ParamTarget::Named(n) => { + let ident = n.cast::()?.into(); + let ty = sig.primary().get_named(&ident)?; + // todo: losing docs + resp.insert(ty.ty.clone(), false); + } + ParamTarget::Positional { + // todo: spreads + spreads: _, + positional, + is_spread, + } => { + if *is_spread { + return None; + } + + // truncate args + let c = sig.param_shift(); + let nth = sig + .primary() + .get_pos(c + positional) + .or_else(|| sig.primary().rest()); + if let Some(nth) = nth { + resp.insert(Ty::Param(nth.clone()), false); + } + + // names + for field in sig.primary().named() { + if is_set && !field.attrs.settable { + continue; + } + + resp.insert(Ty::Param(field.clone()), false); + } + } + } log::debug!("post check target iterated: {:?}", resp.bounds); - Some(self.info.simplify(resp.finalize(), false)) + Some(resp.finalize()) } CheckTarget::Element { container, target } => { let container_ty = self.check_context_or(&container, context_ty)?; @@ -222,7 +278,7 @@ impl<'a> PostTypeChecker<'a> { ); log::debug!("post check target iterated: {:?}", resp.bounds); - Some(self.info.simplify(resp.finalize(), false)) + Some(resp.finalize()) } CheckTarget::Paren { container, @@ -245,7 +301,7 @@ impl<'a> PostTypeChecker<'a> { ); log::debug!("post check target iterated: {:?}", resp.bounds); - Some(self.info.simplify(resp.finalize(), false)) + Some(resp.finalize()) } CheckTarget::Normal(target) => { let ty = self.check_context_or(&target, context_ty)?; @@ -282,28 +338,6 @@ impl<'a> PostTypeChecker<'a> { } } - fn check_self( - &mut self, - context: &LinkedNode, - node: &LinkedNode, - context_ty: Option, - ) -> Option { - match node.kind() { - SyntaxKind::Ident => { - let ty = self.info.type_of_span(node.span()); - log::debug!("post check ident: {node:?} -> {ty:?}"); - self.simplify(&ty?) - } - // todo: destructuring - SyntaxKind::FieldAccess => { - let ty = self.info.type_of_span(node.span()); - self.simplify(&ty?) - .or_else(|| self.check_context_or(context, context_ty)) - } - _ => self.check_target(get_check_target(node.clone()), context_ty), - } - } - fn destruct_let(&mut self, pattern: ast::Pattern, node: LinkedNode) -> Option { match pattern { ast::Pattern::Placeholder(_) => None, @@ -311,7 +345,7 @@ impl<'a> PostTypeChecker<'a> { let ast::Expr::Ident(ident) = n else { return None; }; - self.simplify(&self.info.type_of_span(ident.span())?) + self.info.type_of_span(ident.span()) } ast::Pattern::Parenthesized(p) => { self.destruct_let(p.expr().to_untyped().cast()?, node) @@ -324,11 +358,6 @@ impl<'a> PostTypeChecker<'a> { } } - fn check_signatures(&mut self, ty: &Ty, pol: bool, checker: &mut impl PostSigChecker) { - let mut checker = PostSigCheckWorker(self, checker); - ty.sig_surface(pol, SigSurfaceKind::Call, &mut checker); - } - fn check_element_of(&mut self, ty: &Ty, pol: bool, context: &LinkedNode, checker: &mut T) where T: PostSigChecker, @@ -336,10 +365,6 @@ impl<'a> PostTypeChecker<'a> { let mut checker = PostSigCheckWorker(self, checker); ty.sig_surface(pol, sig_context_of(context), &mut checker) } - - fn simplify(&mut self, ty: &Ty) -> Option { - Some(self.info.simplify(ty.clone(), false)) - } } trait PostSigChecker { diff --git a/crates/tinymist-query/src/analysis/prelude.rs b/crates/tinymist-query/src/analysis/prelude.rs index cb8f6bcb6..423f1e7d9 100644 --- a/crates/tinymist-query/src/analysis/prelude.rs +++ b/crates/tinymist-query/src/analysis/prelude.rs @@ -7,7 +7,6 @@ pub use std::sync::{Arc, LazyLock}; pub use comemo::Track; pub use ecow::*; -pub use serde::{Deserialize, Serialize}; pub use typst::foundations::{Func, Value}; pub use typst::syntax::ast::{self, AstNode}; pub use typst::syntax::{FileId as TypstFileId, LinkedNode, Source, Span, SyntaxKind, SyntaxNode}; diff --git a/crates/tinymist-query/src/semantic_tokens/mod.rs b/crates/tinymist-query/src/analysis/semantic_tokens.rs similarity index 62% rename from crates/tinymist-query/src/semantic_tokens/mod.rs rename to crates/tinymist-query/src/analysis/semantic_tokens.rs index 16fbdbb5b..295ed13e8 100644 --- a/crates/tinymist-query/src/semantic_tokens/mod.rs +++ b/crates/tinymist-query/src/analysis/semantic_tokens.rs @@ -1,92 +1,310 @@ -use std::{ops::Range, sync::Arc}; +//! Semantic tokens (highlighting) support for LSP. -use lsp_types::{SemanticToken, SemanticTokensEdit}; -use parking_lot::RwLock; +use std::{ + num::NonZeroUsize, + ops::Range, + path::Path, + sync::{Arc, OnceLock}, +}; + +use hashbrown::HashMap; +use lsp_types::SemanticToken; +use lsp_types::{SemanticTokenModifier, SemanticTokenType}; +use parking_lot::Mutex; +use reflexo::ImmutPath; +use strum::EnumIter; use typst::syntax::{ast, LinkedNode, Source, SyntaxKind}; use crate::{ + adt::revision::{RevisionLock, RevisionManager, RevisionManagerLike, RevisionSlot}, syntax::{Expr, ExprInfo}, ty::Ty, - LspPosition, PositionEncoding, + LocalContext, LspPosition, PositionEncoding, }; -use self::delta::token_delta; -use self::modifier_set::ModifierSet; +/// A shared semantic tokens object. +pub type SemanticTokens = Arc>; + +/// Get the semantic tokens for a source. +pub(crate) fn get_semantic_tokens(ctx: &mut LocalContext, source: &Source) -> SemanticTokens { + let mut tokenizer = Tokenizer::new( + source.clone(), + ctx.expr_stage(source), + ctx.analysis.allow_multiline_token, + ctx.analysis.position_encoding, + ); + tokenizer.tokenize_tree(&LinkedNode::new(source.root()), ModifierSet::empty()); + SemanticTokens::new(tokenizer.output) +} + +/// A shared semantic tokens cache. +#[derive(Default)] +pub struct SemanticTokenCache { + next_id: usize, + // todo: clear cache after didClose + manager: HashMap>>, +} -use self::delta::CacheInner as TokenCacheInner; +impl SemanticTokenCache { + pub(crate) fn clear(&mut self) { + self.next_id = 0; + self.manager.clear(); + } -mod delta; -mod modifier_set; -mod typst_tokens; -pub use self::typst_tokens::{Modifier, TokenType}; + /// Lock the token cache with an optional previous id in *main thread*. + pub(crate) fn acquire( + cache: Arc>, + p: &Path, + prev: Option<&str>, + ) -> SemanticTokenContext { + let that = cache.clone(); + let mut that = that.lock(); + + that.next_id += 1; + let prev = prev.and_then(|id| { + id.parse::() + .inspect_err(|_| { + log::warn!("invalid previous id: {id}"); + }) + .ok() + }); + let next = NonZeroUsize::new(that.next_id).expect("id overflow"); + + let path = ImmutPath::from(p); + let manager = that.manager.entry(path.clone()).or_default(); + let _rev_lock = manager.lock(prev.unwrap_or(next)); + let prev = prev.and_then(|prev| { + manager + .find_revision(prev, |_| OnceLock::new()) + .data + .get() + .cloned() + }); + let next = manager.find_revision(next, |_| OnceLock::new()); + + SemanticTokenContext { + _rev_lock, + cache, + path, + prev, + next, + } + } +} /// A semantic token context providing incremental semantic tokens rendering. -#[derive(Default)] -pub struct SemanticTokenContext { - cache: RwLock, - position_encoding: PositionEncoding, - /// Whether to allow overlapping tokens. - pub allow_overlapping_token: bool, - /// Whether to allow multiline tokens. - pub allow_multiline_token: bool, +pub(crate) struct SemanticTokenContext { + _rev_lock: RevisionLock, + cache: Arc>, + path: ImmutPath, + pub prev: Option, + pub next: Arc>>, } -impl SemanticTokenContext { - /// Create a new semantic token context. - pub fn new( - position_encoding: PositionEncoding, - allow_overlapping_token: bool, - allow_multiline_token: bool, - ) -> Self { - Self { - cache: RwLock::new(TokenCacheInner::default()), - position_encoding, - allow_overlapping_token, - allow_multiline_token, +impl Drop for SemanticTokenContext { + fn drop(&mut self) { + let mut cache = self.cache.lock(); + let manager = cache.manager.get_mut(&self.path); + if let Some(manager) = manager { + let min_rev = manager.unlock(&mut self._rev_lock); + if let Some(min_rev) = min_rev { + manager.gc(min_rev); + } } } +} - /// Get the semantic tokens for a source. - pub fn semantic_tokens_full( - &self, - source: &Source, - ei: Arc, - ) -> (Vec, String) { - let root = LinkedNode::new(source.root()); +const BOOL: SemanticTokenType = SemanticTokenType::new("bool"); +const PUNCTUATION: SemanticTokenType = SemanticTokenType::new("punct"); +const ESCAPE: SemanticTokenType = SemanticTokenType::new("escape"); +const LINK: SemanticTokenType = SemanticTokenType::new("link"); +const RAW: SemanticTokenType = SemanticTokenType::new("raw"); +const LABEL: SemanticTokenType = SemanticTokenType::new("label"); +const REF: SemanticTokenType = SemanticTokenType::new("ref"); +const HEADING: SemanticTokenType = SemanticTokenType::new("heading"); +const LIST_MARKER: SemanticTokenType = SemanticTokenType::new("marker"); +const LIST_TERM: SemanticTokenType = SemanticTokenType::new("term"); +const DELIMITER: SemanticTokenType = SemanticTokenType::new("delim"); +const INTERPOLATED: SemanticTokenType = SemanticTokenType::new("pol"); +const ERROR: SemanticTokenType = SemanticTokenType::new("error"); +const TEXT: SemanticTokenType = SemanticTokenType::new("text"); + +/// Very similar to `typst_ide::Tag`, but with convenience traits, and +/// extensible because we want to further customize highlighting +#[derive(Clone, Copy, Eq, PartialEq, EnumIter, Default)] +#[repr(u32)] +pub enum TokenType { + // Standard LSP types + /// A comment token. + Comment, + /// A string token. + String, + /// A keyword token. + Keyword, + /// An operator token. + Operator, + /// A number token. + Number, + /// A function token. + Function, + /// A decorator token. + Decorator, + /// A type token. + Type, + /// A namespace token. + Namespace, + // Custom types + /// A boolean token. + Bool, + /// A punctuation token. + Punctuation, + /// An escape token. + Escape, + /// A link token. + Link, + /// A raw token. + Raw, + /// A label token. + Label, + /// A markup reference token. + Ref, + /// A heading token. + Heading, + /// A list marker token. + ListMarker, + /// A list term token. + ListTerm, + /// A delimiter token. + Delimiter, + /// An interpolated token. + Interpolated, + /// An error token. + Error, + /// Any text in markup without a more specific token type, possible styled. + /// + /// We perform styling (like bold and italics) via modifiers. That means + /// everything that should receive styling needs to be a token so we can + /// apply a modifier to it. This token type is mostly for that, since + /// text should usually not be specially styled. + Text, + /// A token that is not recognized by the lexer + #[default] + None, +} - let mut tokenizer = Tokenizer::new( - source.clone(), - ei, - self.allow_multiline_token, - self.position_encoding, - ); - tokenizer.tokenize_tree(&root, ModifierSet::empty()); - let output = tokenizer.output; - - let result_id = self.cache.write().cache_result(output.clone()); - (output, result_id) +impl From for SemanticTokenType { + fn from(token_type: TokenType) -> Self { + use TokenType::*; + + match token_type { + Comment => Self::COMMENT, + String => Self::STRING, + Keyword => Self::KEYWORD, + Operator => Self::OPERATOR, + Number => Self::NUMBER, + Function => Self::FUNCTION, + Decorator => Self::DECORATOR, + Type => Self::TYPE, + Namespace => Self::NAMESPACE, + Bool => BOOL, + Punctuation => PUNCTUATION, + Escape => ESCAPE, + Link => LINK, + Raw => RAW, + Label => LABEL, + Ref => REF, + Heading => HEADING, + ListMarker => LIST_MARKER, + ListTerm => LIST_TERM, + Delimiter => DELIMITER, + Interpolated => INTERPOLATED, + Error => ERROR, + Text => TEXT, + None => unreachable!(), + } } +} - /// Get the semantic tokens delta for a source. - pub fn semantic_tokens_delta( - &self, - source: &Source, - ei: Arc, - result_id: &str, - ) -> (Result, Vec>, String) { - let cached = self.cache.write().try_take_result(result_id); +const STRONG: SemanticTokenModifier = SemanticTokenModifier::new("strong"); +const EMPH: SemanticTokenModifier = SemanticTokenModifier::new("emph"); +const MATH: SemanticTokenModifier = SemanticTokenModifier::new("math"); + +/// A modifier to some semantic token. +#[derive(Clone, Copy, EnumIter)] +#[repr(u8)] +pub enum Modifier { + /// Strong modifier. + Strong, + /// Emphasis modifier. + Emph, + /// Math modifier. + Math, + /// Read-only modifier. + ReadOnly, + /// Static modifier. + Static, + /// Default library modifier. + DefaultLibrary, +} + +impl Modifier { + /// Get the index of the modifier. + pub const fn index(self) -> u8 { + self as u8 + } - // this call will overwrite the cache, so need to read from cache first - let (tokens, result_id) = self.semantic_tokens_full(source, ei); + /// Get the bitmask of the modifier. + pub const fn bitmask(self) -> u32 { + 0b1 << self.index() + } +} - match cached { - Some(cached) => (Ok(token_delta(&cached, &tokens)), result_id), - None => (Err(tokens), result_id), +impl From for SemanticTokenModifier { + fn from(modifier: Modifier) -> Self { + use Modifier::*; + + match modifier { + Strong => STRONG, + Emph => EMPH, + Math => MATH, + ReadOnly => Self::READONLY, + Static => Self::STATIC, + DefaultLibrary => Self::DEFAULT_LIBRARY, } } } -struct Tokenizer { +#[derive(Default, Clone, Copy)] +pub(crate) struct ModifierSet(u32); + +impl ModifierSet { + pub fn empty() -> Self { + Self::default() + } + + pub fn new(modifiers: &[Modifier]) -> Self { + let bits = modifiers + .iter() + .copied() + .map(Modifier::bitmask) + .fold(0, |bits, mask| bits | mask); + Self(bits) + } + + pub fn bitset(self) -> u32 { + self.0 + } +} + +impl std::ops::BitOr for ModifierSet { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } +} + +pub(crate) struct Tokenizer { curr_pos: LspPosition, pos_offset: usize, output: Vec, @@ -100,7 +318,7 @@ struct Tokenizer { } impl Tokenizer { - fn new( + pub fn new( source: Source, ei: Arc, allow_multiline_token: bool, @@ -397,15 +615,20 @@ fn token_from_ident(ei: &ExprInfo, ident: &LinkedNode, modifier: &mut ModifierSe } let next = ident.next_leaf(); + let next_is_adjacent = next + .as_ref() + .map_or(false, |n| n.range().start == ident.range().end); let next_parent = next.as_ref().and_then(|n| n.parent_kind()); let next_kind = next.map(|n| n.kind()); - let lexical_function_call = matches!(next_kind, Some(SyntaxKind::LeftParen)) + let lexical_function_call = next_is_adjacent + && matches!(next_kind, Some(SyntaxKind::LeftParen)) && matches!(next_parent, Some(SyntaxKind::Args | SyntaxKind::Params)); if lexical_function_call { return TokenType::Function; } - let function_content = matches!(next_kind, Some(SyntaxKind::LeftBracket)) + let function_content = next_is_adjacent + && matches!(next_kind, Some(SyntaxKind::LeftBracket)) && matches!(next_parent, Some(SyntaxKind::ContentBlock)); if function_content { return TokenType::Function; @@ -489,3 +712,17 @@ fn token_from_hashtag( .as_ref() .and_then(|e| token_from_node(ei, e, modifier)) } + +#[cfg(test)] +mod tests { + use strum::IntoEnumIterator; + + use super::*; + + #[test] + fn ensure_not_too_many_modifiers() { + // Because modifiers are encoded in a 32 bit bitmask, we can't have more than 32 + // modifiers + assert!(Modifier::iter().len() <= 32); + } +} diff --git a/crates/tinymist-query/src/analysis/signature.rs b/crates/tinymist-query/src/analysis/signature.rs index 8cd3add26..f048b58d4 100644 --- a/crates/tinymist-query/src/analysis/signature.rs +++ b/crates/tinymist-query/src/analysis/signature.rs @@ -2,89 +2,19 @@ use itertools::Either; use tinymist_derive::BindTyCtx; -use typst::foundations::{Closure, ParamInfo}; +use typst::foundations::Closure; use super::{ - prelude::*, BoundChecker, Definition, DocSource, SharedContext, SigTy, SigWithTy, TypeVar, + prelude::*, BoundChecker, Definition, DocSource, ParamTy, SharedContext, SigTy, SigWithTy, + TypeScheme, TypeVar, }; use crate::analysis::PostTypeChecker; use crate::docs::{UntypedDefDocs, UntypedSignatureDocs, UntypedVarDocs}; use crate::syntax::get_non_strict_def_target; -use crate::ty::TypeBounds; use crate::ty::{InsTy, TyCtx}; +use crate::ty::{ParamAttrs, TypeBounds}; use crate::upstream::truncated_repr; -/// Describes a function parameter. -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)] -pub struct ParamAttrs { - /// Is the parameter positional? - pub positional: bool, - /// Is the parameter named? - /// - /// Can be true even if `positional` is true if the parameter can be given - /// in both variants. - pub named: bool, - /// Can the parameter be given any number of times? - pub variadic: bool, - /// Is the parameter settable with a set rule? - pub settable: bool, -} - -impl ParamAttrs { - pub(crate) fn positional() -> ParamAttrs { - ParamAttrs { - positional: true, - named: false, - variadic: false, - settable: false, - } - } - - pub(crate) fn named() -> ParamAttrs { - ParamAttrs { - positional: false, - named: true, - variadic: false, - settable: false, - } - } - - pub(crate) fn variadic() -> ParamAttrs { - ParamAttrs { - positional: true, - named: false, - variadic: true, - settable: false, - } - } -} - -impl From<&ParamInfo> for ParamAttrs { - fn from(param: &ParamInfo) -> Self { - ParamAttrs { - positional: param.positional, - named: param.named, - variadic: param.variadic, - settable: param.settable, - } - } -} - -/// Describes a function parameter. -#[derive(Debug, Clone)] -pub struct ParamSpec { - /// The name of the parameter. - pub name: StrRef, - /// The docstring of the parameter. - pub docs: Option, - /// The default value of the variable - pub default: Option, - /// The type of the parameter. - pub ty: Ty, - /// The attributes of the parameter. - pub attrs: ParamAttrs, -} - /// Describes a function signature. #[derive(Debug, Clone)] pub enum Signature { @@ -112,7 +42,7 @@ impl Signature { } /// Returns the all parameters of the function. - pub(crate) fn params(&self) -> impl Iterator)> { + pub(crate) fn params(&self) -> impl Iterator, Option<&Ty>)> { let primary = self.primary().params(); // todo: with stack primary @@ -124,7 +54,7 @@ impl Signature { primary } - pub(crate) fn param_shift(&self, _ctx: &mut LocalContext) -> usize { + pub(crate) fn param_shift(&self) -> usize { match self { Signature::Primary(_) => 0, Signature::Partial(sig) => sig @@ -142,7 +72,7 @@ pub struct PrimarySignature { /// The documentation of the function pub docs: Option, /// The documentation of the parameter. - pub param_specs: Vec, + pub param_specs: Vec>, /// Whether the function has fill, stroke, or size parameters. pub has_fill_or_size_or_stroke: bool, /// The associated signature type. @@ -151,33 +81,28 @@ pub struct PrimarySignature { } impl PrimarySignature { - /// Returns the type representation of the function. - pub(crate) fn ty(&self) -> Ty { - Ty::Func(self.sig_ty.clone()) - } - /// Returns the number of positional parameters of the function. pub fn pos_size(&self) -> usize { self.sig_ty.name_started as usize } /// Returns the positional parameters of the function. - pub fn pos(&self) -> &[ParamSpec] { + pub fn pos(&self) -> &[Interned] { &self.param_specs[..self.pos_size()] } /// Returns the positional parameters of the function. - pub fn get_pos(&self, offset: usize) -> Option<&ParamSpec> { + pub fn get_pos(&self, offset: usize) -> Option<&Interned> { self.pos().get(offset) } /// Returns the named parameters of the function. - pub fn named(&self) -> &[ParamSpec] { + pub fn named(&self) -> &[Interned] { &self.param_specs[self.pos_size()..self.pos_size() + self.sig_ty.names.names.len()] } /// Returns the named parameters of the function. - pub fn get_named(&self, name: &StrRef) -> Option<&ParamSpec> { + pub fn get_named(&self, name: &StrRef) -> Option<&Interned> { self.named().get(self.sig_ty.names.find(name)?) } @@ -187,13 +112,13 @@ impl PrimarySignature { } /// Returns the rest parameter of the function. - pub fn rest(&self) -> Option<&ParamSpec> { + pub fn rest(&self) -> Option<&Interned> { self.has_spread_right() .then(|| &self.param_specs[self.pos_size() + self.sig_ty.names.names.len()]) } /// Returns the all parameters of the function. - pub fn params(&self) -> impl Iterator)> { + pub fn params(&self) -> impl Iterator, Option<&Ty>)> { let pos = self.pos(); let named = self.named(); let rest = self.rest(); @@ -287,6 +212,14 @@ fn analyze_type_signature( } }?; + sig_of_type(ctx, &type_info, ty) +} + +pub(crate) fn sig_of_type( + ctx: &Arc, + type_info: &TypeScheme, + ty: Ty, +) -> Option { // todo multiple sources let mut srcs = ty.sources(); srcs.sort(); @@ -294,7 +227,7 @@ fn analyze_type_signature( let type_var = srcs.into_iter().next()?; match type_var { DocSource::Var(v) => { - let mut ty_ctx = PostTypeChecker::new(ctx.clone(), &type_info); + let mut ty_ctx = PostTypeChecker::new(ctx.clone(), type_info); let sig_ty = Ty::Func(ty.sig_repr(true, &mut ty_ctx)?); let sig_ty = type_info.simplify(sig_ty, false); let Ty::Func(sig_ty) = sig_ty else { @@ -330,13 +263,13 @@ fn analyze_type_signature( has_fill_or_size_or_stroke = true; } - param_specs.push(ParamSpec { + param_specs.push(Interned::new(ParamTy { name, docs: Some(doc.docs.clone()), default, ty, attrs: ParamAttrs::positional(), - }); + })); } for (name, ty) in sig_ty.named_params() { @@ -348,25 +281,25 @@ fn analyze_type_signature( has_fill_or_size_or_stroke = true; } - param_specs.push(ParamSpec { + param_specs.push(Interned::new(ParamTy { name: name.clone(), docs: Some(doc.docs.clone()), default, ty, attrs: ParamAttrs::named(), - }); + })); } if let Some(doc) = docstring.rest.as_ref() { let default = doc.default.clone(); - param_specs.push(ParamSpec { + param_specs.push(Interned::new(ParamTy { name: doc.name.clone(), docs: Some(doc.docs.clone()), default, ty: sig_ty.rest_param().cloned().unwrap_or(Ty::Any), attrs: ParamAttrs::variadic(), - }); + })); } let sig = Signature::Primary(Arc::new(PrimarySignature { @@ -526,6 +459,12 @@ fn analyze_dyn_signature( SignatureTarget::Convert(func) | SignatureTarget::Runtime(func) => func.clone(), }; + Some(func_signature(func)) +} + +/// Gets the signature of a function. +#[comemo::memoize] +pub fn func_signature(func: Func) -> Signature { use typst::foundations::func::Repr; let mut with_stack = eco_vec![]; let mut func = func; @@ -544,19 +483,6 @@ fn analyze_dyn_signature( func = f.0.clone(); } - let signature = analyze_dyn_signature_inner(func); - log::trace!("got signature {signature:?}"); - - if with_stack.is_empty() { - return Some(Signature::Primary(signature)); - } - Some(Signature::Partial(Arc::new(PartialSignature { - signature, - with_stack, - }))) -} - -fn analyze_dyn_signature_inner(func: Func) -> Arc { let mut pos_tys = vec![]; let mut named_tys = Vec::new(); let mut rest_ty = None; @@ -568,7 +494,7 @@ fn analyze_dyn_signature_inner(func: Func) -> Arc { let mut broken = false; let mut has_fill_or_size_or_stroke = false; - let mut add_param = |param: ParamSpec| { + let mut add_param = |param: Interned| { let name = param.name.clone(); if param.attrs.named { if matches!(name.as_ref(), "fill" | "stroke" | "size") { @@ -592,7 +518,6 @@ fn analyze_dyn_signature_inner(func: Func) -> Arc { } }; - use typst::foundations::func::Repr; let ret_ty = match func.inner() { Repr::With(..) => unreachable!(), Repr::Closure(c) => { @@ -601,13 +526,13 @@ fn analyze_dyn_signature_inner(func: Func) -> Arc { } Repr::Element(..) | Repr::Native(..) => { for p in func.params().unwrap() { - add_param(ParamSpec { + add_param(Interned::new(ParamTy { name: p.name.into(), docs: Some(p.docs.into()), default: p.default.map(|d| truncated_repr(&d())), ty: Ty::from_param_site(&func, p), attrs: p.into(), - }); + })); } func.returns().map(|r| Ty::from_return_site(&func, r)) @@ -623,16 +548,30 @@ fn analyze_dyn_signature_inner(func: Func) -> Arc { param_specs.push(doc); } - Arc::new(PrimarySignature { + let signature = Arc::new(PrimarySignature { docs: func.docs().map(From::from), param_specs, has_fill_or_size_or_stroke, sig_ty: sig_ty.into(), _broken: broken, - }) + }); + + log::trace!("got signature {signature:?}"); + + if with_stack.is_empty() { + return Signature::Primary(signature); + } + + Signature::Partial(Arc::new(PartialSignature { + signature, + with_stack, + })) } -fn analyze_closure_signature(c: Arc>, add_param: &mut impl FnMut(ParamSpec)) { +fn analyze_closure_signature( + c: Arc>, + add_param: &mut impl FnMut(Interned), +) { log::trace!("closure signature for: {:?}", c.node.kind()); let closure = &c.node; @@ -645,34 +584,34 @@ fn analyze_closure_signature(c: Arc>, add_param: &mut impl FnM match param { ast::Param::Pos(e) => { let name = format!("{}", PatternDisplay(&e)); - add_param(ParamSpec { + add_param(Interned::new(ParamTy { name: name.as_str().into(), docs: None, default: None, ty: Ty::Any, attrs: ParamAttrs::positional(), - }); + })); } // todo: pattern ast::Param::Named(n) => { let expr = unwrap_expr(n.expr()).to_untyped().clone().into_text(); - add_param(ParamSpec { + add_param(Interned::new(ParamTy { name: n.name().get().into(), docs: Some(eco_format!("Default value: {expr}")), default: Some(expr), ty: Ty::Any, attrs: ParamAttrs::named(), - }); + })); } ast::Param::Spread(n) => { let ident = n.sink_ident().map(|e| e.as_str()); - add_param(ParamSpec { + add_param(Interned::new(ParamTy { name: ident.unwrap_or_default().into(), docs: None, default: None, ty: Ty::Any, attrs: ParamAttrs::variadic(), - }); + })); } } } diff --git a/crates/tinymist-query/src/analysis/tyck.rs b/crates/tinymist-query/src/analysis/tyck.rs index a7d48d92d..2e36016fd 100644 --- a/crates/tinymist-query/src/analysis/tyck.rs +++ b/crates/tinymist-query/src/analysis/tyck.rs @@ -1,6 +1,8 @@ //! Type checking on source file -use rustc_hash::FxHashMap; +use std::sync::OnceLock; + +use rustc_hash::{FxHashMap, FxHashSet}; use tinymist_derive::BindTyCtx; use super::{ @@ -8,6 +10,7 @@ use super::{ TypeVarBounds, }; use crate::{ + log_never, syntax::{Decl, DeclExpr, Expr, ExprInfo, UnaryOp}, ty::*, }; @@ -22,18 +25,24 @@ pub(crate) use apply::*; pub(crate) use convert::*; pub(crate) use select::*; -pub type TypeEnv = FxHashMap>; +#[derive(Default)] +pub struct TypeEnv { + visiting: FxHashMap>, + exprs: FxHashMap>>, +} /// Type checking at the source unit level. pub(crate) fn type_check( ctx: Arc, ei: Arc, - route: &mut TypeEnv, + env: &mut TypeEnv, ) -> Arc { let mut info = TypeScheme::default(); + info.valid = true; + info.fid = Some(ei.fid); info.revision = ei.revision; - route.insert(ei.fid, Arc::new(TypeScheme::default())); + env.visiting.insert(ei.fid, Arc::new(TypeScheme::default())); // Retrieve expression information for the source. let root = ei.root.clone(); @@ -42,26 +51,48 @@ pub(crate) fn type_check( ctx, ei, info, - route, + env, + call_cache: Default::default(), + module_exports: Default::default(), }; let type_check_start = std::time::Instant::now(); checker.check(&root); + + let exports = checker + .ei + .exports + .clone() + .into_iter() + .map(|(k, v)| (k.clone(), checker.check(v))) + .collect(); + checker.info.exports = exports; + let elapsed = type_check_start.elapsed(); log::debug!("Type checking on {:?} took {elapsed:?}", checker.ei.fid); - checker.route.remove(&checker.ei.fid); + checker.env.visiting.remove(&checker.ei.fid); Arc::new(checker.info) } +type CallCacheDesc = ( + Interned, + Interned, + Option>>, +); + pub(crate) struct TypeChecker<'a> { ctx: Arc, ei: Arc, info: TypeScheme, - route: &'a mut TypeEnv, + module_exports: FxHashMap<(TypstFileId, Interned), OnceLock>>, + + call_cache: FxHashSet, + + env: &'a mut TypeEnv, } impl<'a> TyCtx for TypeChecker<'a> { @@ -98,15 +129,21 @@ impl<'a> TyCtxMut for TypeChecker<'a> { } fn check_module_item(&mut self, fid: TypstFileId, k: &StrRef) -> Option { - let ei = self.ctx.expr_stage_by_id(fid)?; - let item = ei.exports.get(k)?; - match item { - Expr::Decl(decl) => Some(self.check_decl(decl)), - Expr::Ref(r) => r.root.clone().map(|r| self.check(&r)), - _ => { - panic!("unexpected module item: {item:?}"); - } - } + self.module_exports + .entry((fid, k.clone())) + .or_default() + .clone() + .get_or_init(|| { + let ei = self + .env + .exprs + .entry(fid) + .or_insert_with(|| self.ctx.expr_stage_by_id(fid)) + .clone()?; + + Some(self.check(ei.exports.get(k)?)) + }) + .clone() } } @@ -148,10 +185,10 @@ impl<'a> TypeChecker<'a> { let ext_def_use_info = self.ctx.expr_stage_by_id(fid)?; let source = &ext_def_use_info.source; // todo: check types in cycle - let ext_type_info = if let Some(scheme) = self.route.get(&source.id()) { + let ext_type_info = if let Some(scheme) = self.env.visiting.get(&source.id()) { scheme.clone() } else { - self.ctx.clone().type_check_(source, self.route) + self.ctx.clone().type_check_(source, self.env) }; let ext_def = ext_def_use_info.exports.get(&name)?; @@ -190,6 +227,22 @@ impl<'a> TypeChecker<'a> { var } + fn constrain_call( + &mut self, + sig: &Interned, + args: &Interned, + withs: Option<&Vec>>, + ) { + let call_desc = (sig.clone(), args.clone(), withs.cloned()); + if !self.call_cache.insert(call_desc) { + return; + } + + for (arg_recv, arg_ins) in sig.matches(args, withs) { + self.constrain(arg_ins, arg_recv); + } + } + fn constrain(&mut self, lhs: &Ty, rhs: &Ty) { static FLOW_STROKE_DICT_TYPE: LazyLock = LazyLock::new(|| Ty::Dict(FLOW_STROKE_DICT.clone())); @@ -226,7 +279,7 @@ impl<'a> TypeChecker<'a> { let _ = w.def; } (Ty::Var(v), rhs) => { - log::debug!("constrain var {v:?} ⪯ {rhs:?}"); + log_never!("constrain var {v:?} ⪯ {rhs:?}"); let w = self.info.vars.get_mut(&v.def).unwrap(); // strict constraint on upper bound let bound = rhs.clone(); @@ -240,7 +293,7 @@ impl<'a> TypeChecker<'a> { (lhs, Ty::Var(v)) => { let w = self.info.vars.get(&v.def).unwrap(); let bound = self.weaken_constraint(lhs, &w.bounds); - log::debug!("constrain var {v:?} ⪰ {bound:?}"); + log_never!("constrain var {v:?} ⪰ {bound:?}"); match &w.bounds { FlowVarKind::Strong(v) | FlowVarKind::Weak(v) => { let mut v = v.write(); @@ -312,7 +365,7 @@ impl<'a> TypeChecker<'a> { } (Ty::Dict(lhs), Ty::Dict(rhs)) => { for (key, lhs, rhs) in lhs.common_iface_fields(rhs) { - log::debug!("constrain record item {key} {lhs:?} ⪯ {rhs:?}"); + log_never!("constrain record item {key} {lhs:?} ⪯ {rhs:?}"); self.constrain(lhs, rhs); // if !sl.is_detached() { // self.info.witness_at_most(*sl, rhs.clone()); @@ -328,32 +381,32 @@ impl<'a> TypeChecker<'a> { self.constrain(&lhs.lhs, &rhs.lhs); } (Ty::Unary(lhs), rhs) if lhs.op == UnaryOp::TypeOf && is_ty(rhs) => { - log::debug!("constrain type of {lhs:?} ⪯ {rhs:?}"); + log_never!("constrain type of {lhs:?} ⪯ {rhs:?}"); self.constrain(&lhs.lhs, rhs); } (lhs, Ty::Unary(rhs)) if rhs.op == UnaryOp::TypeOf && is_ty(lhs) => { - log::debug!( + log_never!( "constrain type of {lhs:?} ⪯ {rhs:?} {:?}", matches!(lhs, Ty::Builtin(..)) ); self.constrain(lhs, &rhs.lhs); } (Ty::Value(lhs), rhs) => { - log::debug!("constrain value {lhs:?} ⪯ {rhs:?}"); + log_never!("constrain value {lhs:?} ⪯ {rhs:?}"); let _ = TypeScheme::witness_at_most; // if !lhs.1.is_detached() { // self.info.witness_at_most(lhs.1, rhs.clone()); // } } (lhs, Ty::Value(rhs)) => { - log::debug!("constrain value {lhs:?} ⪯ {rhs:?}"); + log_never!("constrain value {lhs:?} ⪯ {rhs:?}"); // if !rhs.1.is_detached() { // self.info.witness_at_least(rhs.1, lhs.clone()); // } } _ => { - log::debug!("constrain {lhs:?} ⪯ {rhs:?}"); + log_never!("constrain {lhs:?} ⪯ {rhs:?}"); } } } @@ -399,8 +452,8 @@ impl<'a> TypeChecker<'a> { w.weaken(); } Ty::Any | Ty::Boolean(_) | Ty::Builtin(_) | Ty::Value(_) => {} - Ty::Field(v) => { - self.weaken(&v.field); + Ty::Param(v) => { + self.weaken(&v.ty); } Ty::Func(v) | Ty::Args(v) | Ty::Pattern(v) => { for ty in v.inputs() { @@ -540,8 +593,8 @@ impl Joiner { (Ty::Union(..), _) => self.definite = Ty::undef(), (Ty::Let(w), Ty::Builtin(BuiltinTy::None)) => self.definite = Ty::Let(w), (Ty::Let(..), _) => self.definite = Ty::undef(), - (Ty::Field(w), Ty::Builtin(BuiltinTy::None)) => self.definite = Ty::Field(w), - (Ty::Field(..), _) => self.definite = Ty::undef(), + (Ty::Param(w), Ty::Builtin(BuiltinTy::None)) => self.definite = Ty::Param(w), + (Ty::Param(..), _) => self.definite = Ty::undef(), (Ty::Boolean(b), Ty::Builtin(BuiltinTy::None)) => self.definite = Ty::Boolean(b), (Ty::Boolean(..), _) => self.definite = Ty::undef(), } diff --git a/crates/tinymist-query/src/analysis/tyck/apply.rs b/crates/tinymist-query/src/analysis/tyck/apply.rs index aebc3dbef..88bd6dbb4 100644 --- a/crates/tinymist-query/src/analysis/tyck/apply.rs +++ b/crates/tinymist-query/src/analysis/tyck/apply.rs @@ -142,9 +142,7 @@ impl<'a, 'b> ApplyChecker for ApplyTypeChecker<'a, 'b> { let Some(SigShape { sig, withs }) = sig.shape(self.base) else { return; }; - for (arg_recv, arg_ins) in sig.matches(args, withs) { - self.base.constrain(arg_ins, arg_recv); - } + self.base.constrain_call(&sig, args, withs); if let Some(callee) = callee.clone() { self.base.info.witness_at_least(self.call_site, callee); diff --git a/crates/tinymist-query/src/analysis/tyck/convert.rs b/crates/tinymist-query/src/analysis/tyck/convert.rs index 3ce8d8f1b..da134b0c2 100644 --- a/crates/tinymist-query/src/analysis/tyck/convert.rs +++ b/crates/tinymist-query/src/analysis/tyck/convert.rs @@ -1,9 +1,45 @@ +use crate::analysis::func_signature; + use super::*; -pub fn term_value(ctx: &Arc, value: &Value) -> Ty { +pub fn is_plain_value(value: &Value) -> bool { + matches!( + value, + Value::Label(..) + | Value::None + | Value::Auto + | Value::Bool(..) + | Value::Int(..) + | Value::Float(..) + | Value::Decimal(..) + | Value::Length(..) + | Value::Angle(..) + | Value::Ratio(..) + | Value::Relative(..) + | Value::Fraction(..) + | Value::Color(..) + | Value::Gradient(..) + | Value::Pattern(..) + | Value::Symbol(..) + | Value::Version(..) + | Value::Str(..) + | Value::Bytes(..) + | Value::Datetime(..) + | Value::Duration(..) + | Value::Content(..) + | Value::Styles(..) + ) +} + +/// Gets the type of a value. +#[comemo::memoize] +pub fn term_value(value: &Value) -> Ty { match value { Value::Array(a) => { - let values = a.iter().map(term_value_rec).collect::>(); + let values = a + .iter() + .map(|v| term_value_rec(v, Span::detached())) + .collect::>(); Ty::Tuple(values.into()) } // todo: term arguments @@ -19,7 +55,7 @@ pub fn term_value(ctx: &Arc, value: &Value) -> Ty { Value::Dict(d) => { let values = d .iter() - .map(|(k, v)| (k.as_str().into(), term_value_rec(v))) + .map(|(k, v)| (k.as_str().into(), term_value_rec(v, Span::detached()))) .collect(); Ty::Dict(RecordTy::new(values)) } @@ -27,42 +63,21 @@ pub fn term_value(ctx: &Arc, value: &Value) -> Ty { let values = m .scope() .iter() - .map(|(k, v, _)| (k.into(), term_value_rec(v))) + .map(|(k, v, s)| (k.into(), term_value_rec(v, s))) .collect(); Ty::Dict(RecordTy::new(values)) } - Value::Type(ty) => Ty::Builtin(BuiltinTy::Type(*ty)), + Value::Type(ty) => Ty::Builtin(BuiltinTy::TypeType(*ty)), Value::Dyn(v) => Ty::Builtin(BuiltinTy::Type(v.ty())), - Value::Func(func) => Ty::Func(ctx.type_of_func(func.clone()).type_sig()), - Value::Label(..) - | Value::None - | Value::Auto - | Value::Bool(..) - | Value::Int(..) - | Value::Float(..) - | Value::Decimal(..) - | Value::Length(..) - | Value::Angle(..) - | Value::Ratio(..) - | Value::Relative(..) - | Value::Fraction(..) - | Value::Color(..) - | Value::Gradient(..) - | Value::Pattern(..) - | Value::Symbol(..) - | Value::Version(..) - | Value::Str(..) - | Value::Bytes(..) - | Value::Datetime(..) - | Value::Duration(..) - | Value::Content(..) - | Value::Styles(..) => Ty::Value(InsTy::new(value.clone())), + Value::Func(func) => Ty::Func(func_signature(func.clone()).type_sig()), + _ if is_plain_value(value) => Ty::Value(InsTy::new(value.clone())), + _ => Ty::Any, } } -pub fn term_value_rec(value: &Value) -> Ty { +pub fn term_value_rec(value: &Value, s: Span) -> Ty { match value { - Value::Type(ty) => Ty::Builtin(BuiltinTy::Type(*ty)), + Value::Type(ty) => Ty::Builtin(BuiltinTy::TypeType(*ty)), Value::Dyn(v) => Ty::Builtin(BuiltinTy::Type(v.ty())), Value::None | Value::Auto @@ -92,6 +107,12 @@ pub fn term_value_rec(value: &Value) -> Ty { | Value::Datetime(..) | Value::Duration(..) | Value::Content(..) - | Value::Styles(..) => Ty::Value(InsTy::new(value.clone())), + | Value::Styles(..) => { + if !s.is_detached() { + Ty::Value(InsTy::new_at(value.clone(), s)) + } else { + Ty::Value(InsTy::new(value.clone())) + } + } } } diff --git a/crates/tinymist-query/src/analysis/tyck/syntax.rs b/crates/tinymist-query/src/analysis/tyck/syntax.rs index cd9bea4f1..65c4dcfbe 100644 --- a/crates/tinymist-query/src/analysis/tyck/syntax.rs +++ b/crates/tinymist-query/src/analysis/tyck/syntax.rs @@ -484,7 +484,8 @@ impl<'a> TypeChecker<'a> { Ty::Builtin(BuiltinTy::Content) } - fn check_import(&mut self, _import: &Interned) -> Ty { + fn check_import(&mut self, import: &Interned) -> Ty { + self.check_ref(&import.decl); Ty::Builtin(BuiltinTy::None) } @@ -527,8 +528,21 @@ impl<'a> TypeChecker<'a> { pub(crate) fn check_decl(&mut self, decl: &Interned) -> Ty { let v = Ty::Var(self.get_var(decl)); - if let Decl::Label(..) = decl.as_ref() { - self.constrain(&v, &Ty::Builtin(BuiltinTy::Label)); + match decl.kind() { + DefKind::Reference => { + self.constrain(&v, &Ty::Builtin(BuiltinTy::Label)); + } + DefKind::Module => { + let ty = if decl.is_def() { + Some(Ty::Builtin(BuiltinTy::Module(decl.clone()))) + } else { + self.ei.get_def(decl).map(|e| self.check(&e)) + }; + if let Some(ty) = ty { + self.constrain(&v, &ty); + } + } + _ => {} } v diff --git a/crates/tinymist-query/src/code_context.rs b/crates/tinymist-query/src/code_context.rs index 2c58989d1..465d7a771 100644 --- a/crates/tinymist-query/src/code_context.rs +++ b/crates/tinymist-query/src/code_context.rs @@ -76,19 +76,6 @@ impl InteractCodeContextRequest { // Get mode let root = LinkedNode::new(source.root()); - let leaf = root.leaf_at_compat(pos); - let mut leaf = leaf.as_ref(); - Some(loop { - log::debug!("leaf for context: {leaf:?}"); - if let Some(t) = leaf { - if let Some(mode) = interpret_mode_at(t.kind()) { - break mode; - } - - leaf = t.parent(); - } else { - break InterpretMode::Markup; - } - }) + Some(interpret_mode_at(root.leaf_at_compat(pos).as_ref())) } } diff --git a/crates/tinymist-query/src/completion.rs b/crates/tinymist-query/src/completion.rs index 2fd142612..21b91c1ab 100644 --- a/crates/tinymist-query/src/completion.rs +++ b/crates/tinymist-query/src/completion.rs @@ -48,12 +48,6 @@ pub struct CompletionRequest { pub explicit: bool, /// The character that triggered the completion, if any. pub trigger_character: Option, - /// Whether to trigger suggest completion, a.k.a. auto-completion. - pub trigger_suggest: bool, - /// Whether to trigger named parameter completion. - pub trigger_named_completion: bool, - /// Whether to trigger parameter hint, a.k.a. signature help. - pub trigger_parameter_hints: bool, } impl StatefulRequest for CompletionRequest { @@ -64,6 +58,15 @@ impl StatefulRequest for CompletionRequest { ctx: &mut LocalContext, doc: Option, ) -> Option { + // These trigger characters are for completion on positional arguments, + // which follows the configuration item + // `tinymist.completion.triggerOnSnippetPlaceholders`. + if matches!(self.trigger_character, Some('(' | ',' | ':')) + && !ctx.analysis.completion_feat.trigger_on_snippet_placeholders + { + return None; + } + let doc = doc.as_ref().map(|doc| doc.document.as_ref()); let source = ctx.source_by_path(&self.path).ok()?; let (cursor, deref_target) = ctx.deref_syntax_at_(&source, self.position, 0)?; @@ -148,9 +151,6 @@ impl StatefulRequest for CompletionRequest { cursor, explicit, self.trigger_character, - self.trigger_suggest, - self.trigger_parameter_hints, - self.trigger_named_completion, )?; // Exclude it self from auto completion @@ -242,7 +242,12 @@ impl StatefulRequest for CompletionRequest { } }), text_edit: Some(text_edit), + additional_text_edits: typst_completion.additional_text_edits.clone(), insert_text_format: Some(InsertTextFormat::SNIPPET), + commit_characters: typst_completion + .commit_char + .as_ref() + .map(|v| vec![v.to_string()]), command: typst_completion.command.as_ref().map(|c| Command { command: c.to_string(), ..Default::default() @@ -398,9 +403,6 @@ mod tests { position: ctx.to_lsp_pos(s, &source), explicit: false, trigger_character, - trigger_suggest: true, - trigger_parameter_hints: true, - trigger_named_completion: true, }; results.push(request.request(ctx, doc.clone()).map(|resp| match resp { CompletionResponse::List(l) => CompletionResponse::List(CompletionList { diff --git a/crates/tinymist-query/src/diagnostics.rs b/crates/tinymist-query/src/diagnostics.rs index b2e96d422..f71a3b344 100644 --- a/crates/tinymist-query/src/diagnostics.rs +++ b/crates/tinymist-query/src/diagnostics.rs @@ -1,19 +1,42 @@ use reflexo_typst::EntryReader; +use tinymist_world::LspWorld; -use crate::prelude::*; +use crate::{prelude::*, LspWorldExt}; /// Stores diagnostics for files. pub type DiagnosticsMap = HashMap>; +/// Context for converting Typst diagnostics to LSP diagnostics. +struct LocalDiagContext<'a> { + /// The world surface for Typst compiler. + pub world: &'a LspWorld, + /// The position encoding for the source. + pub position_encoding: PositionEncoding, +} + +impl std::ops::Deref for LocalDiagContext<'_> { + type Target = LspWorld; + + fn deref(&self) -> &Self::Target { + self.world + } +} + /// Converts a list of Typst diagnostics to LSP diagnostics. pub fn convert_diagnostics<'a>( - ctx: &LocalContext, + world: &LspWorld, errors: impl IntoIterator, + position_encoding: PositionEncoding, ) -> DiagnosticsMap { + let ctx = LocalDiagContext { + world, + position_encoding, + }; + errors .into_iter() .flat_map(|error| { - convert_diagnostic(ctx, error) + convert_diagnostic(&ctx, error) .map_err(move |conversion_err| { log::error!("could not convert Typst error to diagnostic: {conversion_err:?} error to convert: {error:?}"); }) @@ -24,18 +47,17 @@ pub fn convert_diagnostics<'a>( } fn convert_diagnostic( - ctx: &LocalContext, + ctx: &LocalDiagContext, typst_diagnostic: &TypstDiagnostic, ) -> anyhow::Result<(Url, LspDiagnostic)> { let uri; let lsp_range; if let Some((id, span)) = diagnostic_span_id(typst_diagnostic) { uri = ctx.uri_for_id(id)?; - let source = ctx.world().source(id)?; - lsp_range = diagnostic_range(&source, span, ctx.position_encoding()); + let source = ctx.source(id)?; + lsp_range = diagnostic_range(&source, span, ctx.position_encoding); } else { let root = ctx - .world .workspace_root() .ok_or_else(|| anyhow::anyhow!("no workspace root"))?; uri = path_to_url(&root)?; @@ -48,8 +70,7 @@ fn convert_diagnostic( let typst_hints = &typst_diagnostic.hints; let lsp_message = format!("{typst_message}{}", diagnostic_hints(typst_hints)); - let tracepoints = - diagnostic_related_information(ctx, typst_diagnostic, ctx.position_encoding())?; + let tracepoints = diagnostic_related_information(ctx, typst_diagnostic, ctx.position_encoding)?; let diagnostic = LspDiagnostic { range: lsp_range, @@ -64,13 +85,13 @@ fn convert_diagnostic( } fn tracepoint_to_relatedinformation( - project: &LocalContext, + ctx: &LocalDiagContext, tracepoint: &Spanned, position_encoding: PositionEncoding, ) -> anyhow::Result> { if let Some(id) = tracepoint.span.id() { - let uri = project.uri_for_id(id)?; - let source = project.world().source(id)?; + let uri = ctx.uri_for_id(id)?; + let source = ctx.source(id)?; if let Some(typst_range) = source.range(tracepoint.span) { let lsp_range = typst_to_lsp::range(typst_range, &source, position_encoding); @@ -89,7 +110,7 @@ fn tracepoint_to_relatedinformation( } fn diagnostic_related_information( - project: &LocalContext, + project: &LocalDiagContext, typst_diagnostic: &TypstDiagnostic, position_encoding: PositionEncoding, ) -> anyhow::Result> { diff --git a/crates/tinymist-query/src/docs/convert.rs b/crates/tinymist-query/src/docs/convert.rs index cd00b2e85..56da67e45 100644 --- a/crates/tinymist-query/src/docs/convert.rs +++ b/crates/tinymist-query/src/docs/convert.rs @@ -5,6 +5,7 @@ use parking_lot::Mutex; use tinymist_world::base::{EntryState, ShadowApi, TaskInputs}; use typlite::scopes::Scopes; use typlite::value::Value; +use typlite::TypliteFeat; use typst::foundations::Bytes; use typst::{ diag::StrResult, @@ -36,8 +37,13 @@ pub(crate) fn convert_docs(ctx: &SharedContext, content: &str) -> StrResult; -type ShowTypeRepr<'a> = &'a mut dyn FnMut(Option<&Ty>) -> TypeRepr; +type TypeRepr = Option<( + /* short */ EcoString, + /* long */ EcoString, + /* value */ EcoString, +)>; /// Documentation about a definition (without type information). pub type UntypedDefDocs = DefDocsT<()>; @@ -86,52 +89,68 @@ impl SignatureDocsT { /// Get full documentation for the signature. pub fn hover_docs(&self) -> &EcoString { self.hover_docs - .get_or_init(|| plain_docs_sentence(&format!("{}", SigDefDocs(self)))) + .get_or_init(|| plain_docs_sentence(&format!("{}", SigHoverDocs(self)))) } } -struct SigDefDocs<'a>(&'a SignatureDocs); +struct SigHoverDocs<'a>(&'a SignatureDocs); -impl fmt::Display for SigDefDocs<'_> { +impl fmt::Display for SigHoverDocs<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let docs = self.0; let base_docs = docs.docs.trim(); - let has_params_docs = !docs.pos.is_empty() || !docs.named.is_empty() || docs.rest.is_some(); - if !base_docs.is_empty() { f.write_str(base_docs)?; + } - if has_params_docs { - f.write_str("\n\n")?; + fn write_param_docs( + f: &mut fmt::Formatter<'_>, + p: &ParamDocsT, + kind: &str, + is_first: &mut bool, + ) -> fmt::Result { + if *is_first { + *is_first = false; + write!(f, "\n\n## {}\n\n", p.name)?; + } else { + write!(f, "\n\n## {} ({kind})\n\n", p.name)?; } + + // p.cano_type.0 + if let Some(t) = &p.cano_type { + write!(f, "```typc\ntype: {}\n```\n\n", t.2)?; + } + + f.write_str(p.docs.trim())?; + + Ok(()) } - if has_params_docs { - f.write_str("## Parameters")?; + if !docs.pos.is_empty() { + f.write_str("\n\n# Positional Parameters")?; + let mut is_first = true; for p in &docs.pos { - write!(f, "\n\n@positional `{}`", p.name)?; - if !p.docs.is_empty() { - f.write_str(" — ")?; - f.write_str(&p.docs)?; - } + write_param_docs(f, p, "positional", &mut is_first)?; } + } - for (name, p) in &docs.named { - write!(f, "\n\n@named `{name}`")?; - if !p.docs.is_empty() { - f.write_str(" — ")?; - f.write_str(&p.docs)?; - } - } + if docs.rest.is_some() { + f.write_str("\n\n# Rest Parameters")?; + let mut is_first = true; if let Some(rest) = &docs.rest { - write!(f, "\n\n@rest `{}`", rest.name)?; - if !rest.docs.is_empty() { - f.write_str(" — ")?; - f.write_str(&rest.docs)?; - } + write_param_docs(f, rest, "spread right", &mut is_first)?; + } + } + + if !docs.named.is_empty() { + f.write_str("\n\n# Named Parameters")?; + + let mut is_first = true; + for p in docs.named.values() { + write_param_docs(f, p, "named", &mut is_first)?; } } @@ -213,6 +232,31 @@ impl SignatureDocs { } } +/// Documentation about a variable (without type information). +pub type UntypedVarDocs = VarDocsT<()>; +/// Documentation about a variable. +pub type VarDocs = VarDocsT>; + +/// Describes a primary pattern binding. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct VarDocsT { + /// Documentation for the pattern binding. + pub docs: EcoString, + /// The inferred type of the pattern binding source. + pub return_ty: T, + /// Cached documentation for the definition. + #[serde(skip)] + pub def_docs: OnceLock, +} + +impl VarDocs { + /// Get the markdown representation of the documentation. + pub fn def_docs(&self) -> &String { + self.def_docs + .get_or_init(|| plain_docs_sentence(&self.docs).into()) + } +} + /// Documentation about a parameter (without type information). pub type TypelessParamDocs = ParamDocsT<()>; /// Documentation about a parameter. @@ -235,24 +279,24 @@ pub struct ParamDocsT { } impl ParamDocs { - fn new(param: &ParamSpec, ty: Option<&Ty>, doc_ty: Option<&mut ShowTypeRepr>) -> Self { + fn new(param: &ParamTy, ty: Option<&Ty>) -> Self { Self { name: param.name.as_ref().into(), docs: param.docs.clone().unwrap_or_default(), - cano_type: format_ty(ty.or(Some(¶m.ty)), doc_ty), + cano_type: format_ty(ty.or(Some(¶m.ty))), default: param.default.clone(), attrs: param.attrs, } } } -fn format_ty(ty: Option<&Ty>, doc_ty: Option<&mut ShowTypeRepr>) -> TypeRepr { - match doc_ty { - Some(doc_ty) => doc_ty(ty), - None => ty - .and_then(|ty| ty.repr()) - .map(|short| (short, format!("{ty:?}"))), - } +fn format_ty(ty: Option<&Ty>) -> TypeRepr { + let ty = ty?; + let short = ty.repr().unwrap_or_else(|| "any".into()); + let long = eco_format!("{ty:?}"); + let value = ty.value_repr().unwrap_or_else(|| "".into()); + + Some((short, long, value)) } pub(crate) fn var_docs(ctx: &mut LocalContext, pos: Span) -> Option { @@ -266,7 +310,7 @@ pub(crate) fn var_docs(ctx: &mut LocalContext, pos: Span) -> Option { log::info!("check variable docs of ty: {ty:?} => {srcs:?}"); let doc_source = srcs.into_iter().next()?; - let return_ty = ty.describe().map(|short| (short, format!("{ty:?}"))); + let return_ty = format_ty(Some(&ty)); match doc_source { DocSource::Var(var) => { let docs = type_info @@ -291,7 +335,7 @@ pub(crate) fn var_docs(ctx: &mut LocalContext, pos: Span) -> Option { } } -pub(crate) fn sig_docs(sig: &Signature, mut doc_ty: Option) -> Option { +pub(crate) fn sig_docs(sig: &Signature) -> Option { let type_sig = sig.type_sig().clone(); let pos_in = sig @@ -310,19 +354,14 @@ pub(crate) fn sig_docs(sig: &Signature, mut doc_ty: Option) -> Opt let ret_in = type_sig.body.as_ref(); let pos = pos_in - .map(|(param, ty)| ParamDocs::new(param, ty, doc_ty.as_mut())) + .map(|(param, ty)| ParamDocs::new(param, ty)) .collect(); let named = named_in - .map(|(param, ty)| { - ( - param.name.clone(), - ParamDocs::new(param, ty, doc_ty.as_mut()), - ) - }) + .map(|(param, ty)| (param.name.clone(), ParamDocs::new(param, ty))) .collect(); - let rest = rest_in.map(|(param, ty)| ParamDocs::new(param, ty, doc_ty.as_mut())); + let rest = rest_in.map(|(param, ty)| ParamDocs::new(param, ty)); - let ret_ty = format_ty(ret_in, doc_ty.as_mut()); + let ret_ty = format_ty(ret_in); Some(SignatureDocs { docs: sig.primary().docs.clone().unwrap_or_default(), diff --git a/crates/tinymist-query/src/docs/package.rs b/crates/tinymist-query/src/docs/package.rs index 93823e164..04e7601e5 100644 --- a/crates/tinymist-query/src/docs/package.rs +++ b/crates/tinymist-query/src/docs/package.rs @@ -124,36 +124,11 @@ pub fn package_docs(ctx: &mut LocalContext, spec: &PackageInfo) -> StrResult", "—>", // avoid markdown comment - // ); - // log::error!("{err}"); - // err - // }) - let docs = child.parsed_docs.clone(); - // Err(e) => { - // let err = format!("failed to convert docs: {e}").replace( - // "-->", "—>", // avoid markdown comment - // ); - // log::error!("{err}"); - // return Err(err); - // } let convert_err = None::; - match &docs { - Some(docs) => { - child.parsed_docs = Some(docs.clone()); - child.docs = None; - } - None => { - // let err = format!("failed to convert docs in {title}: - // {e}").replace( "-->", - // "—>", // avoid markdown comment - // ); - // log::error!("{err}"); - // convert_err = Some(err); - } + if let Some(docs) = &child.parsed_docs { + child.parsed_docs = Some(docs.clone()); + child.docs = None; } let ident = if !primary.is_empty() { @@ -204,6 +179,7 @@ pub fn package_docs(ctx: &mut LocalContext, spec: &PackageInfo) -> StrResult"); } + let mut printed_docs = false; match (&child.parsed_docs, convert_err) { (_, Some(err)) => { let err = format!("failed to convert docs in {title}: {err}").replace( @@ -212,14 +188,15 @@ pub fn package_docs(ctx: &mut LocalContext, spec: &PackageInfo) -> StrResult"); errors.push(err); } - (Some(docs), _) => { + (Some(docs), _) if !child.is_external => { let _ = writeln!(md, "{}", remove_list_annotations(docs.docs())); + printed_docs = true; if let DefDocs::Function(f) = docs { for param in f.pos.iter().chain(f.named.values()).chain(f.rest.as_ref()) { let _ = writeln!(md, "", param.name); let ty = match ¶m.cano_type { - Some((short, _)) => short, + Some((short, _, _)) => short, None => "unknown", }; let _ = writeln!( @@ -231,20 +208,22 @@ pub fn package_docs(ctx: &mut LocalContext, spec: &PackageInfo) -> StrResult {} + (_, None) => {} } - let plain_docs = child.docs.as_deref(); - let plain_docs = plain_docs.or(child.oneliner.as_deref()); + if !printed_docs { + let plain_docs = child.docs.as_deref(); + let plain_docs = plain_docs.or(child.oneliner.as_deref()); - if let Some(docs) = plain_docs { - let contains_code = docs.contains("```"); - if contains_code { - let _ = writeln!(md, "`````typ"); - } - let _ = writeln!(md, "{docs}"); - if contains_code { - let _ = writeln!(md, "`````"); + if let Some(docs) = plain_docs { + let contains_code = docs.contains("```"); + if contains_code { + let _ = writeln!(md, "`````typ"); + } + let _ = writeln!(md, "{docs}"); + if contains_code { + let _ = writeln!(md, "`````"); + } } } diff --git a/crates/tinymist-query/src/docs/tidy.rs b/crates/tinymist-query/src/docs/tidy.rs index c92ab1ecb..9b89c55b1 100644 --- a/crates/tinymist-query/src/docs/tidy.rs +++ b/crates/tinymist-query/src/docs/tidy.rs @@ -1,12 +1,8 @@ -use std::sync::OnceLock; - use ecow::EcoString; use itertools::Itertools; use serde::{Deserialize, Serialize}; use typst::diag::StrResult; -use crate::upstream::plain_docs_sentence; - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TidyParamDocs { pub name: EcoString, @@ -16,38 +12,18 @@ pub struct TidyParamDocs { } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TidyFuncDocs { +pub struct TidyPatDocs { pub docs: EcoString, pub return_ty: Option, pub params: Vec, } -/// Documentation about a variable (without type information). -pub type UntypedVarDocs = VarDocsT<()>; -/// Documentation about a variable. -pub type VarDocs = VarDocsT>; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct VarDocsT { - pub docs: EcoString, - pub return_ty: T, - #[serde(skip)] - pub def_docs: OnceLock, -} - -impl VarDocs { - pub fn def_docs(&self) -> &String { - self.def_docs - .get_or_init(|| plain_docs_sentence(&self.docs).into()) - } -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TidyModuleDocs { pub docs: EcoString, } -pub fn identify_func_docs(converted: &str) -> StrResult { +pub fn identify_pat_docs(converted: &str) -> StrResult { let lines = converted.lines().collect::>(); let mut matching_return_ty = true; @@ -76,6 +52,7 @@ pub fn identify_func_docs(converted: &str) -> StrResult { continue; }; + break_line = Some(i); return_ty = Some(w.trim().into()); break; } @@ -152,54 +129,13 @@ pub fn identify_func_docs(converted: &str) -> StrResult { }; params.reverse(); - Ok(TidyFuncDocs { + Ok(TidyPatDocs { docs, return_ty, params, }) } -pub fn identify_var_docs(converted: EcoString) -> StrResult { - let lines = converted.lines().collect::>(); - - let mut return_ty = None; - let mut break_line = None; - - let mut i = lines.len(); - loop { - if i == 0 { - break; - } - i -= 1; - - let line = lines[i]; - if line.is_empty() { - continue; - } - - let Some(w) = line.trim_start().strip_prefix("->") else { - break_line = Some(i + 1); - break; - }; - - // todo: convert me - return_ty = Some((w.trim().into(), String::new())); - break_line = Some(i); - break; - } - - let docs = match break_line { - Some(line_no) => (lines[..line_no]).iter().copied().join("\n").into(), - None => converted, - }; - - Ok(VarDocs { - docs, - return_ty, - def_docs: OnceLock::new(), - }) -} - pub fn identify_tidy_module_docs(docs: EcoString) -> StrResult { Ok(TidyModuleDocs { docs }) } @@ -235,7 +171,7 @@ mod tests { use super::TidyParamDocs; fn func(s: &str) -> String { - let f = super::identify_func_docs(s).unwrap(); + let f = super::identify_pat_docs(s).unwrap(); let mut res = format!(">> docs:\n{}\n<< docs", f.docs); if let Some(t) = f.return_ty { res.push_str(&format!("\n>>return\n{t}\n< String { - let f = super::identify_var_docs(s.into()).unwrap(); + let f = super::identify_pat_docs(s).unwrap(); let mut res = format!(">> docs:\n{}\n<< docs", f.docs); if let Some(t) = f.return_ty { - res.push_str(&format!("\n>>return\n{}\n<>return\n{t}\n< - preamble (string): Code to prepend to all code snippets shown with `#example()`. This can for instance be used to import something from the scope. --> string"###), @r###" +-> string"###), @r" >> docs: These again are dictionaries with the keys - `description` (optional): The description for the argument. @@ -314,7 +250,7 @@ See @@show-module() for outputting the results of this function. Code to prepend to all code snippets shown with `#example()`. This can for instance be used to import something from the scope. << arg - "###); + "); } #[test] @@ -329,7 +265,7 @@ See @@show-module() for outputting the results of this function. references. If `auto`, the label-prefix name will be the module name. - nested something - nested something 2 --> string"###), @r###" +-> string"###), @r" >> docs: These again are dictionaries with the keys - `description` (optional): The description for the argument. @@ -348,27 +284,27 @@ See @@show-module() for outputting the results of this function. - nested something - nested something 2 << arg - "###); + "); } #[test] fn test_identify_tidy_docs3() { insta::assert_snapshot!(var(r###"See @@show-module() for outputting the results of this function. --> string"###), @r###" +-> string"###), @r" >> docs: See @@show-module() for outputting the results of this function. << docs >>return string <name (string): The name for the module. --> string"###), @r###" +-> string"###), @r" >> docs: - name (string): The name for the module. @@ -376,6 +312,6 @@ See @@show-module() for outputting the results of this function. >>return string < Option { let source = ctx.source_by_path(&self.path).ok()?; - let links = get_link_exprs(ctx, &source); - links.map(|links| { - links - .into_iter() - .map(|(range, target)| DocumentLink { - range: ctx.to_lsp_range(range, &source), - target: Some(target), - tooltip: None, - data: None, - }) - .collect() - }) + let links = get_link_exprs(&source); + if links.objects.is_empty() { + return None; + } + + let links = links.objects.iter().map(|obj| DocumentLink { + range: ctx.to_lsp_range(obj.range.clone(), &source), + target: obj.target.resolve(ctx), + tooltip: None, + data: None, + }); + Some(links.collect()) } } diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin.typ.snap index 676016832..850195297 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: CallSnapshot(result.as_deref()) input_file: crates/tinymist-query/src/fixtures/call_info/builtin.typ +snapshot_kind: text --- 1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "angle" } diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly.typ.snap index 4600f47b8..4386fc303 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: CallSnapshot(result.as_deref()) input_file: crates/tinymist-query/src/fixtures/call_info/builtin_poly.typ +snapshot_kind: text --- 255 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "red" } 255 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "green" } diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly2.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly2.typ.snap index 8efac0c92..0e11ab01f 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly2.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly2.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: CallSnapshot(result.as_deref()) input_file: crates/tinymist-query/src/fixtures/call_info/builtin_poly2.typ +snapshot_kind: text --- "#fff" -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "red" } diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user.typ.snap index e7adb3386..ab7c29ba6 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: CallSnapshot(result.as_deref()) input_file: crates/tinymist-query/src/fixtures/call_info/user.typ +snapshot_kind: text --- 1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "x" } 1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "y" } diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named.typ.snap index 06c95de26..90e95270d 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: CallSnapshot(result.as_deref()) input_file: crates/tinymist-query/src/fixtures/call_info/user_named.typ +snapshot_kind: text --- y: 1 -> CallParamInfo { kind: Named, is_content_block: false, param_name: "y" } 1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "x" } diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with.typ.snap index 59a169cd8..2aea2a5e9 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: CallSnapshot(result.as_deref()) input_file: crates/tinymist-query/src/fixtures/call_info/user_named_with.typ +snapshot_kind: text --- 1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "x" } diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with2.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with2.typ.snap index 588fd9ff6..80fcbd9b4 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with2.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with2.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: CallSnapshot(result.as_deref()) input_file: crates/tinymist-query/src/fixtures/call_info/user_named_with2.typ +snapshot_kind: text --- y: 1 -> CallParamInfo { kind: Named, is_content_block: false, param_name: "y" } diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with.typ.snap index 4862953cf..053647433 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: CallSnapshot(result.as_deref()) input_file: crates/tinymist-query/src/fixtures/call_info/user_with.typ +snapshot_kind: text --- 1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "x" } diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with2.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with2.typ.snap index 976ebbfdb..f92a78700 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with2.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with2.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: CallSnapshot(result.as_deref()) input_file: crates/tinymist-query/src/fixtures/call_info/user_with2.typ +snapshot_kind: text --- diff --git a/crates/tinymist-query/src/fixtures/completion/bracket_plain.typ b/crates/tinymist-query/src/fixtures/completion/bracket_plain.typ new file mode 100644 index 000000000..d604c6a56 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/bracket_plain.typ @@ -0,0 +1,3 @@ +/// contains: box.bracket + +#[]/* range -1..-0 */ diff --git a/crates/tinymist-query/src/fixtures/completion/bracket_strong.typ b/crates/tinymist-query/src/fixtures/completion/bracket_strong.typ new file mode 100644 index 000000000..535319223 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/bracket_strong.typ @@ -0,0 +1,3 @@ +/// contains: strong, strong.bracket + +#(/* range after 1..2 */st); diff --git a/crates/tinymist-query/src/fixtures/completion/bracket_strong_delta.typ b/crates/tinymist-query/src/fixtures/completion/bracket_strong_delta.typ new file mode 100644 index 000000000..5b33fed4a --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/bracket_strong_delta.typ @@ -0,0 +1,3 @@ +/// contains: delta + +#strong(/* range after 1..2 */[]; diff --git a/crates/tinymist-query/src/fixtures/completion/bracket_strong_delta2.typ b/crates/tinymist-query/src/fixtures/completion/bracket_strong_delta2.typ new file mode 100644 index 000000000..a06df5efd --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/bracket_strong_delta2.typ @@ -0,0 +1,3 @@ +/// contains: delta + +#strong(/* range after 1..2 */[]); diff --git a/crates/tinymist-query/src/fixtures/completion/math_bold.typ b/crates/tinymist-query/src/fixtures/completion/math_bold.typ new file mode 100644 index 000000000..8317068a1 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/math_bold.typ @@ -0,0 +1,2 @@ +/// contains: box, box.bracket +#b/* range 0..1 */ \ No newline at end of file diff --git a/crates/tinymist-query/src/fixtures/completion/math_bold2.typ b/crates/tinymist-query/src/fixtures/completion/math_bold2.typ new file mode 100644 index 000000000..9584fe2f4 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/math_bold2.typ @@ -0,0 +1,2 @@ +/// contains: bold, bold[] +$ b/* range 0..1 */ $ \ No newline at end of file diff --git a/crates/tinymist-query/src/fixtures/completion/set.typ b/crates/tinymist-query/src/fixtures/completion/set.typ index 903c5064c..30b93e756 100644 --- a/crates/tinymist-query/src/fixtures/completion/set.typ +++ b/crates/tinymist-query/src/fixtures/completion/set.typ @@ -1,2 +1,2 @@ -/// contains: raw, read, raw.with, raw.where, read.with, read.where, replacement +/// contains: raw, read, raw.with, raw.where, read.with, read.where, replacement, red #set r/* range 0..1 */ diff --git a/crates/tinymist-query/src/fixtures/completion/set_block.typ b/crates/tinymist-query/src/fixtures/completion/set_block.typ new file mode 100644 index 000000000..445309579 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/set_block.typ @@ -0,0 +1,2 @@ +/// contains: block +#set b/* range 0..1 */ diff --git a/crates/tinymist-query/src/fixtures/completion/set_in_show.typ b/crates/tinymist-query/src/fixtures/completion/set_in_show.typ new file mode 100644 index 000000000..5d7e5561e --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/set_in_show.typ @@ -0,0 +1,5 @@ +/// contains: raw, read, raw.with, raw.where, read.with, read.where, replacement, red +#show figure: it => { + set /* range 0..1 */ + it +} diff --git a/crates/tinymist-query/src/fixtures/completion/set_param.typ b/crates/tinymist-query/src/fixtures/completion/set_param.typ new file mode 100644 index 000000000..ac23bee5c --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/set_param.typ @@ -0,0 +1,2 @@ +/// contains: body, fill +#set text(/* range 0..1 */ ) diff --git a/crates/tinymist-query/src/fixtures/completion/show.typ b/crates/tinymist-query/src/fixtures/completion/show.typ index 04282ee2b..928e49461 100644 --- a/crates/tinymist-query/src/fixtures/completion/show.typ +++ b/crates/tinymist-query/src/fixtures/completion/show.typ @@ -1,2 +1,2 @@ -/// contains: raw, read, raw.with, raw.where, read.with, read.where, replacement, regex selector +/// contains: raw, read, raw.with, raw.where, read.with, read.where, replacement, regex selector, red #show r/* range 0..1 */ diff --git a/crates/tinymist-query/src/fixtures/completion/show2.typ b/crates/tinymist-query/src/fixtures/completion/show2.typ index 13dab2ce7..5fb50bd2a 100644 --- a/crates/tinymist-query/src/fixtures/completion/show2.typ +++ b/crates/tinymist-query/src/fixtures/completion/show2.typ @@ -1,2 +1,2 @@ -/// contains: raw, read, raw.with, raw.where, read.with, read.where, replacement, regex selector +/// contains: raw, read, raw.with, raw.where, read.with, read.where, replacement, regex selector, red #show /* range 0..1 */ diff --git a/crates/tinymist-query/src/fixtures/completion/show3.typ b/crates/tinymist-query/src/fixtures/completion/show3.typ new file mode 100644 index 000000000..fe55bf872 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/show3.typ @@ -0,0 +1,2 @@ +/// contains: raw, read, raw.with, raw.where, read.with, read.where, replacement, regex selector +#show /* range 0..1 */: diff --git a/crates/tinymist-query/src/fixtures/completion/show_transform3.typ b/crates/tinymist-query/src/fixtures/completion/show_transform3.typ new file mode 100644 index 000000000..dfb380d88 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/show_transform3.typ @@ -0,0 +1,2 @@ +/// contains: raw, read, raw.with, raw.where, read.with, read.where, replacement +#show raw:/* range 0..1 */ diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@base.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@base.typ.snap index 67dece8c7..d1e475971 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@base.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on c( (98..100) +description: Completion on c( (99..101) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/base.typ +snapshot_kind: text --- [ { @@ -14,8 +15,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/base.typ "labelDetails": { "description": "() => 1" }, + "sortText": "000", "textEdit": { - "newText": "aa(${1:})", + "newText": "aa()${1:}", "range": { "end": { "character": 4, @@ -34,8 +36,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/base.typ "labelDetails": { "description": "() => 1" }, + "sortText": "001", "textEdit": { - "newText": "aab(${1:})", + "newText": "aab()${1:}", "range": { "end": { "character": 4, @@ -54,8 +57,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/base.typ "labelDetails": { "description": "() => 1" }, + "sortText": "002", "textEdit": { - "newText": "aabc(${1:})", + "newText": "aabc()${1:}", "range": { "end": { "character": 4, @@ -74,8 +78,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/base.typ "labelDetails": { "description": "() => 1" }, + "sortText": "003", "textEdit": { - "newText": "aac(${1:})", + "newText": "aac()${1:}", "range": { "end": { "character": 4, @@ -99,8 +104,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/base.typ "labelDetails": { "description": "() => 1" }, + "sortText": "002", "textEdit": { - "newText": "aabc(${1:})", + "newText": "aabc()${1:}", "range": { "end": { "character": 4, @@ -119,8 +125,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/base.typ "labelDetails": { "description": "() => 1" }, + "sortText": "003", "textEdit": { - "newText": "aac(${1:})", + "newText": "aac()${1:}", "range": { "end": { "character": 4, diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@bracket_plain.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@bracket_plain.typ.snap new file mode 100644 index 000000000..88b6815ad --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@bracket_plain.typ.snap @@ -0,0 +1,13 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: "Completion on ] (29..30)" +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/completion/bracket_plain.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [] + } +] diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@bracket_strong.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@bracket_strong.typ.snap new file mode 100644 index 000000000..620a7c204 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@bracket_strong.typ.snap @@ -0,0 +1,54 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: Completion on t (63..64) +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/completion/bracket_strong.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [ + { + "kind": 3, + "label": "strong", + "labelDetails": { + "description": "(content, delta: int) => strong" + }, + "textEdit": { + "newText": "strong(${1:})", + "range": { + "end": { + "character": 26, + "line": 2 + }, + "start": { + "character": 24, + "line": 2 + } + } + } + }, + { + "kind": 3, + "label": "strong.bracket", + "labelDetails": { + "description": "(content, delta: int) => strong" + }, + "textEdit": { + "newText": "strong[${1:}]", + "range": { + "end": { + "character": 26, + "line": 2 + }, + "start": { + "character": 24, + "line": 2 + } + } + } + } + ] + } +] diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@bracket_strong_delta.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@bracket_strong_delta.typ.snap new file mode 100644 index 000000000..04244e311 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@bracket_strong_delta.typ.snap @@ -0,0 +1,35 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: "Completion on ] (52..53)" +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/completion/bracket_strong_delta.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [ + { + "kind": 5, + "label": "delta", + "labelDetails": { + "description": "int" + }, + "sortText": "001", + "textEdit": { + "newText": "delta: ${1:})", + "range": { + "end": { + "character": 31, + "line": 2 + }, + "start": { + "character": 31, + "line": 2 + } + } + } + } + ] + } +] diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@bracket_strong_delta2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@bracket_strong_delta2.typ.snap new file mode 100644 index 000000000..97b1682ef --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@bracket_strong_delta2.typ.snap @@ -0,0 +1,35 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: "Completion on ] (52..53)" +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/completion/bracket_strong_delta2.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [ + { + "kind": 5, + "label": "delta", + "labelDetails": { + "description": "int" + }, + "sortText": "001", + "textEdit": { + "newText": "delta: ${1:}", + "range": { + "end": { + "character": 31, + "line": 2 + }, + "start": { + "character": 31, + "line": 2 + } + } + } + } + ] + } +] diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@bug_cite_function_infer.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@bug_cite_function_infer.typ.snap index 594d5f2d8..d4a5bb63d 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@bug_cite_function_infer.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@bug_cite_function_infer.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on > (257..258) +description: Completion on > (260..261) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/bug_cite_function_infer.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@bug_cite_function_infer2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@bug_cite_function_infer2.typ.snap index e12950791..c6cbc8508 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@bug_cite_function_infer2.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@bug_cite_function_infer2.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on > (272..273) +description: Completion on > (275..276) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/bug_cite_function_infer2.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@bug_mix_context_type.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@bug_mix_context_type.typ.snap index 64643faea..625fc61e7 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@bug_mix_context_type.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@bug_mix_context_type.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on (107..108) +description: Completion on (108..109) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/bug_mix_context_type.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@cite_heading.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@cite_heading.typ.snap index e0144ba69..5b1e71883 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@cite_heading.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@cite_heading.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on t (132..133) +description: Completion on t (135..136) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/cite_heading.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_markup.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_markup.typ.snap index c38a20108..d8c553f25 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_markup.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_markup.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on (22..23) +description: Completion on (23..24) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/colon_markup.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_markup2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_markup2.typ.snap index 5a6d0f5ba..764839341 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_markup2.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_markup2.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on (46..47) +description: Completion on (48..49) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/colon_markup2.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_math.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_math.typ.snap index ca0e98913..14d9e6827 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_math.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_math.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on (22..23) +description: Completion on (23..24) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/colon_math.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_math2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_math2.typ.snap index de7260c47..866417662 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_math2.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_math2.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on (46..47) +description: Completion on (48..49) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/colon_math2.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_param.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_param.typ.snap index dc644b9be..14ecad170 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_param.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@colon_param.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on (63..64) +description: Completion on (65..66) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/colon_param.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_purely_label.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_purely_label.typ.snap index f3e807a24..84990a052 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_purely_label.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_purely_label.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on t (100..101) +description: Completion on t (103..104) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/complete_purely_label.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_purely_ref.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_purely_ref.typ.snap index 227e85398..ccd6b16c3 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_purely_ref.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_purely_ref.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on t (99..100) +description: Completion on t (102..103) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/complete_purely_ref.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title.typ.snap index 1578382da..c526b0a77 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on @R (132..134) +description: Completion on @R (135..137) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/completion_title.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title2.typ.snap index 4cb5b6556..9f3db7b36 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title2.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title2.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on 9 (106..107) +description: Completion on 9 (109..110) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/completion_title2.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title3.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title3.typ.snap index 3ec14ab55..35e06b507 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title3.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title3.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on ) (136..137) +description: Completion on ) (139..140) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/completion_title3.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@element_where.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@element_where.typ.snap index 680b6c451..0fc94611d 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@element_where.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@element_where.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (36..37) +description: Completion on / (37..38) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/element_where.typ +snapshot_kind: text --- [ { @@ -11,6 +12,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/element_where.typ { "kind": 5, "label": "caption", + "labelDetails": { + "description": "content | none" + }, "sortText": "000", "textEdit": { "newText": "caption: ${1:}", diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@fp_dict_filter.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@fp_dict_filter.typ.snap index 9d405017a..2d22e09d5 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@fp_dict_filter.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@fp_dict_filter.typ.snap @@ -1,15 +1,16 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on (92..93) +description: Completion on (93..94) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/fp_dict_filter.typ +snapshot_kind: text --- [ { "isIncomplete": false, "items": [ { - "kind": 21, + "kind": 6, "label": "a", "textEdit": { "newText": "a", @@ -26,7 +27,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/fp_dict_filter.typ } }, { - "kind": 21, + "kind": 6, "label": "ab", "textEdit": { "newText": "ab", @@ -43,7 +44,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/fp_dict_filter.typ } }, { - "kind": 21, + "kind": 6, "label": "ac", "textEdit": { "newText": "ac", @@ -60,7 +61,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/fp_dict_filter.typ } }, { - "kind": 21, + "kind": 6, "label": "ad", "textEdit": { "newText": "ad", diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@func_args.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@func_args.typ.snap index 47caa3bc8..e782f2528 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@func_args.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@func_args.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (348..349) +description: Completion on / (349..350) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/func_args.typ +snapshot_kind: text --- [ { @@ -11,6 +12,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args.typ { "kind": 5, "label": "authors", + "labelDetails": { + "description": "array | str" + }, "sortText": "000", "textEdit": { "newText": "authors: ${1:}", @@ -29,6 +33,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args.typ { "kind": 5, "label": "class", + "labelDetails": { + "description": "\"article\" | \"letter\" | str" + }, "sortText": "001", "textEdit": { "newText": "class: ${1:}", @@ -47,6 +54,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args.typ { "kind": 5, "label": "font", + "labelDetails": { + "description": "array | none | text.font" + }, "sortText": "002", "textEdit": { "newText": "font: ${1:}", @@ -68,7 +78,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args.typ "labelDetails": { "description": "type" }, - "sortText": "050", + "sortText": "034", "textEdit": { "newText": "content", "range": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@func_args2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@func_args2.typ.snap index e69f98081..f6f939761 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@func_args2.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@func_args2.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (360..361) +description: Completion on / (361..362) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/func_args2.typ +snapshot_kind: text --- [ { @@ -11,6 +12,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args2.typ { "kind": 5, "label": "class", + "labelDetails": { + "description": "\"article\" | \"letter\" | str" + }, "sortText": "000", "textEdit": { "newText": " class: ${1:}", @@ -29,6 +33,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args2.typ { "kind": 5, "label": "font", + "labelDetails": { + "description": "array | none | text.font" + }, "sortText": "001", "textEdit": { "newText": " font: ${1:}", diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@func_args_after.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@func_args_after.typ.snap index 9e4449497..908fee4ae 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@func_args_after.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@func_args_after.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on u (371..372) +description: Completion on u (372..373) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/func_args_after.typ +snapshot_kind: text --- [ { @@ -11,6 +12,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args_after.typ { "kind": 5, "label": "class", + "labelDetails": { + "description": "\"article\" | \"letter\" | str" + }, "sortText": "000", "textEdit": { "newText": "class: ${1:}, ", diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@func_builtin_args.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@func_builtin_args.typ.snap index e7fa9294f..0eb5033cf 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@func_builtin_args.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@func_builtin_args.typ.snap @@ -3,6 +3,7 @@ source: crates/tinymist-query/src/completion.rs description: Completion on / (30..31) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/func_builtin_args.typ +snapshot_kind: text --- [ { @@ -11,6 +12,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_builtin_args.typ { "kind": 5, "label": "columns", + "labelDetails": { + "description": "array | auto | length | type" + }, "sortText": "002", "textEdit": { "newText": "columns: ${1:}", @@ -32,7 +36,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_builtin_args.typ "labelDetails": { "description": "(int, content, gutter: relative) => columns" }, - "sortText": "054", + "sortText": "040", "textEdit": { "newText": "columns(${1:})", "range": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@func_params.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@func_params.typ.snap index c68d1ed49..454de95a0 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@func_params.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@func_params.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on c( (62..64) +description: Completion on c( (63..65) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/func_params.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@func_with_args.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@func_with_args.typ.snap index 4e232d1ad..c2e08dadb 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@func_with_args.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@func_with_args.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (353..354) +description: Completion on / (354..355) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/func_with_args.typ +snapshot_kind: text --- [ { @@ -11,6 +12,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_with_args.typ { "kind": 5, "label": "authors", + "labelDetails": { + "description": "array | str" + }, "sortText": "000", "textEdit": { "newText": "authors: ${1:}", @@ -29,6 +33,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_with_args.typ { "kind": 5, "label": "class", + "labelDetails": { + "description": "\"article\" | \"letter\" | str" + }, "sortText": "001", "textEdit": { "newText": "class: ${1:}", @@ -47,6 +54,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_with_args.typ { "kind": 5, "label": "font", + "labelDetails": { + "description": "array | none | text.font" + }, "sortText": "002", "textEdit": { "newText": "font: ${1:}", @@ -68,7 +78,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_with_args.typ "labelDetails": { "description": "type" }, - "sortText": "050", + "sortText": "034", "textEdit": { "newText": "content", "range": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@half_completion.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@half_completion.typ.snap index 475e55d0c..510b36085 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@half_completion.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@half_completion.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on o (30..32) +description: Completion on o (31..33) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/half_completion.typ +snapshot_kind: text --- [ { @@ -11,7 +12,10 @@ input_file: crates/tinymist-query/src/fixtures/completion/half_completion.typ { "kind": 5, "label": "font", - "sortText": "014", + "labelDetails": { + "description": "array | text.font" + }, + "sortText": "011", "textEdit": { "newText": "font: ${1:}, ", "range": { @@ -34,7 +38,10 @@ input_file: crates/tinymist-query/src/fixtures/completion/half_completion.typ { "kind": 5, "label": "font", - "sortText": "014", + "labelDetails": { + "description": "array | text.font" + }, + "sortText": "011", "textEdit": { "newText": "font: ${1:}", "range": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@import.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@import.typ.snap index 1a85d7536..4a2081c0a 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@import.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@import.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on c( (83..85) +description: Completion on c( (84..86) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/import.typ +snapshot_kind: text --- [ { @@ -14,8 +15,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/import.typ "labelDetails": { "description": "() => 1" }, + "sortText": "000", "textEdit": { - "newText": "aab(${1:})", + "newText": "aab()${1:}", "range": { "end": { "character": 4, @@ -34,8 +36,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/import.typ "labelDetails": { "description": "() => 1" }, + "sortText": "001", "textEdit": { - "newText": "aac(${1:})", + "newText": "aac()${1:}", "range": { "end": { "character": 4, @@ -59,8 +62,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/import.typ "labelDetails": { "description": "() => 1" }, + "sortText": "001", "textEdit": { - "newText": "aac(${1:})", + "newText": "aac()${1:}", "range": { "end": { "character": 4, diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self.typ.snap index 4748138d6..025868f2a 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on c( (73..75) +description: Completion on c( (74..76) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/import_self.typ +snapshot_kind: text --- [ { @@ -12,7 +13,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_self.typ "kind": 9, "label": "base", "labelDetails": { - "description": "base.typ" + "description": "module(base)" }, "textEdit": { "newText": "base", diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self2.typ.snap index c00867dea..3569cd46c 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self2.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self2.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on c( (76..78) +description: Completion on c( (77..79) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/import_self2.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self3.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self3.typ.snap index b52117352..222ea81f8 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self3.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self3.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on c( (84..86) +description: Completion on c( (85..87) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/import_self3.typ +snapshot_kind: text --- [ { @@ -12,7 +13,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_self3.typ "kind": 9, "label": "baz", "labelDetails": { - "description": "base.typ" + "description": "module(base)" }, "textEdit": { "newText": "baz", diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self4.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self4.typ.snap index 19f80ac31..2377b6995 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self4.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@import_self4.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on c( (87..89) +description: Completion on c( (88..90) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/import_self4.typ +snapshot_kind: text --- [ { @@ -12,7 +13,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_self4.typ "kind": 9, "label": "baz", "labelDetails": { - "description": "base.typ" + "description": "module(base)" }, "textEdit": { "newText": "baz", diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@import_star.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@import_star.typ.snap index 48cb74e10..2d9574eef 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@import_star.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@import_star.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on c( (76..78) +description: Completion on c( (77..79) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/import_star.typ +snapshot_kind: text --- [ { @@ -12,30 +13,11 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_star.typ "kind": 3, "label": "aa", "labelDetails": { - "description": "() => 1" + "description": "() => any" }, + "sortText": "000", "textEdit": { - "newText": "aa(${1:})", - "range": { - "end": { - "character": 4, - "line": 2 - }, - "start": { - "character": 1, - "line": 2 - } - } - } - }, - { - "kind": 3, - "label": "aa.with", - "labelDetails": { - "description": "() => 1" - }, - "textEdit": { - "newText": "aa.with(${1:})", + "newText": "aa()${1:}", "range": { "end": { "character": 4, @@ -52,10 +34,11 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_star.typ "kind": 3, "label": "aab", "labelDetails": { - "description": "() => 1" + "description": "() => any" }, + "sortText": "001", "textEdit": { - "newText": "aab(${1:})", + "newText": "aab()${1:}", "range": { "end": { "character": 4, @@ -72,10 +55,11 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_star.typ "kind": 3, "label": "aabc", "labelDetails": { - "description": "() => 1" + "description": "() => any" }, + "sortText": "002", "textEdit": { - "newText": "aabc(${1:})", + "newText": "aabc()${1:}", "range": { "end": { "character": 4, @@ -92,10 +76,11 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_star.typ "kind": 3, "label": "aac", "labelDetails": { - "description": "() => 1" + "description": "() => any" }, + "sortText": "003", "textEdit": { - "newText": "aac(${1:})", + "newText": "aac()${1:}", "range": { "end": { "character": 4, @@ -117,10 +102,11 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_star.typ "kind": 3, "label": "aabc", "labelDetails": { - "description": "() => 1" + "description": "() => any" }, + "sortText": "002", "textEdit": { - "newText": "aabc(${1:})", + "newText": "aabc()${1:}", "range": { "end": { "character": 4, @@ -137,10 +123,11 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_star.typ "kind": 3, "label": "aac", "labelDetails": { - "description": "() => 1" + "description": "() => any" }, + "sortText": "003", "textEdit": { - "newText": "aac(${1:})", + "newText": "aac()${1:}", "range": { "end": { "character": 4, diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@item_shadow.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@item_shadow.typ.snap index fae406f8d..5ae813341 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@item_shadow.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@item_shadow.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on c( (69..71) +description: Completion on c( (70..72) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/item_shadow.typ +snapshot_kind: text --- [ { @@ -14,8 +15,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/item_shadow.typ "labelDetails": { "description": "() => 1" }, + "sortText": "000", "textEdit": { - "newText": "aa(${1:})", + "newText": "aa()${1:}", "range": { "end": { "character": 4, @@ -34,8 +36,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/item_shadow.typ "labelDetails": { "description": "() => 1" }, + "sortText": "001", "textEdit": { - "newText": "aac(${1:})", + "newText": "aac()${1:}", "range": { "end": { "character": 4, @@ -59,8 +62,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/item_shadow.typ "labelDetails": { "description": "() => 1" }, + "sortText": "001", "textEdit": { - "newText": "aac(${1:})", + "newText": "aac()${1:}", "range": { "end": { "character": 4, diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@keyword_ident.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@keyword_ident.typ.snap index afed66009..1b94364e4 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@keyword_ident.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@keyword_ident.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on n (31..32) +description: Completion on n (32..33) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/keyword_ident.typ +snapshot_kind: text --- [ { @@ -11,6 +12,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/keyword_ident.typ { "kind": 5, "label": "inset", + "labelDetails": { + "description": "inset" + }, "sortText": "007", "textEdit": { "newText": "inset: ${1:}", diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@let-context.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@let-context.typ.snap index 708f59a66..3673fa5ab 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@let-context.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@let-context.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on (60..61) +description: Completion on (61..62) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/let-context.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@let.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@let.typ.snap index 4bed62f11..6fdbd388b 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@let.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@let.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on c( (94..96) +description: Completion on c( (95..97) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/let.typ +snapshot_kind: text --- [ { @@ -14,8 +15,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/let.typ "labelDetails": { "description": "() => 1" }, + "sortText": "000", "textEdit": { - "newText": "aa(${1:})", + "newText": "aa()${1:}", "range": { "end": { "character": 4, @@ -34,6 +36,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/let.typ "labelDetails": { "description": "1" }, + "sortText": "001", "textEdit": { "newText": "aab", "range": { @@ -54,6 +57,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/let.typ "labelDetails": { "description": "1" }, + "sortText": "002", "textEdit": { "newText": "aabc", "range": { @@ -74,8 +78,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/let.typ "labelDetails": { "description": "() => 1" }, + "sortText": "003", "textEdit": { - "newText": "aac(${1:})", + "newText": "aac()${1:}", "range": { "end": { "character": 4, @@ -99,6 +104,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/let.typ "labelDetails": { "description": "1" }, + "sortText": "002", "textEdit": { "newText": "aabc", "range": { @@ -119,8 +125,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/let.typ "labelDetails": { "description": "() => 1" }, + "sortText": "003", "textEdit": { - "newText": "aac(${1:})", + "newText": "aac()${1:}", "range": { "end": { "character": 4, diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@math_bold.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@math_bold.typ.snap new file mode 100644 index 000000000..dd60d28cb --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@math_bold.typ.snap @@ -0,0 +1,54 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: Completion on / (33..34) +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/completion/math_bold.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [ + { + "kind": 3, + "label": "box", + "labelDetails": { + "description": "(content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box" + }, + "textEdit": { + "newText": "box(${1:})", + "range": { + "end": { + "character": 2, + "line": 1 + }, + "start": { + "character": 1, + "line": 1 + } + } + } + }, + { + "kind": 3, + "label": "box.bracket", + "labelDetails": { + "description": "(content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box" + }, + "textEdit": { + "newText": "box[${1:}]", + "range": { + "end": { + "character": 2, + "line": 1 + }, + "start": { + "character": 1, + "line": 1 + } + } + } + } + ] + } +] diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@math_bold2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@math_bold2.typ.snap new file mode 100644 index 000000000..57aa2dbe8 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@math_bold2.typ.snap @@ -0,0 +1,34 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: Completion on / (30..31) +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/completion/math_bold2.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [ + { + "kind": 3, + "label": "bold", + "labelDetails": { + "description": "(content) => content" + }, + "textEdit": { + "newText": "bold(${1:})", + "range": { + "end": { + "character": 3, + "line": 1 + }, + "start": { + "character": 2, + "line": 1 + } + } + } + } + ] + } +] diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@modify_string.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@modify_string.typ.snap index d90fa4fc9..69854280c 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@modify_string.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@modify_string.typ.snap @@ -1,15 +1,16 @@ --- source: crates/tinymist-query/src/completion.rs -description: "Completion on \"\" (52..54)" +description: "Completion on \"\" (53..55)" expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/modify_string.typ +snapshot_kind: text --- [ { "isIncomplete": false, "items": [ { - "kind": 21, + "kind": 6, "label": "\"New Computer Modern\"", "sortText": "003", "textEdit": { @@ -32,18 +33,18 @@ input_file: crates/tinymist-query/src/fixtures/completion/modify_string.typ "isIncomplete": false, "items": [ { - "kind": 21, + "kind": 6, "label": "\"New Computer Modern\"", "sortText": "003", "textEdit": { - "newText": "\"New Computer Modern", + "newText": "New Computer Modern", "range": { "end": { "character": 17, "line": 2 }, "start": { - "character": 16, + "character": 17, "line": 2 } } diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@modify_string_2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@modify_string_2.typ.snap index 977f62a89..04286f064 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@modify_string_2.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@modify_string_2.typ.snap @@ -1,15 +1,16 @@ --- source: crates/tinymist-query/src/completion.rs -description: "Completion on \"\" (53..55)" +description: "Completion on \"\" (54..56)" expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/modify_string_2.typ +snapshot_kind: text --- [ { "isIncomplete": false, "items": [ { - "kind": 21, + "kind": 6, "label": "\"New Computer Modern\"", "sortText": "003", "textEdit": { @@ -32,7 +33,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/modify_string_2.typ "isIncomplete": false, "items": [ { - "kind": 21, + "kind": 6, "label": "\"New Computer Modern\"", "sortText": "003", "textEdit": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@paren_string.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@paren_string.typ.snap index dd178e57f..729dcd10e 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@paren_string.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@paren_string.typ.snap @@ -3,6 +3,7 @@ source: crates/tinymist-query/src/completion.rs description: "Completion on \" (41..42)" expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/paren_string.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@set.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@set.typ.snap index 4b98ddb4c..977f4ec07 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@set.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@set.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (30..31) +description: Completion on / (92..93) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/set.typ +snapshot_kind: text --- [ { @@ -14,6 +15,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/set.typ "labelDetails": { "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" }, + "sortText": "052", "textEdit": { "newText": "raw(${1:})", "range": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@set2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@set2.typ.snap index 1ef96e25b..1d7ae5d41 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@set2.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@set2.typ.snap @@ -3,6 +3,7 @@ source: crates/tinymist-query/src/completion.rs description: Completion on / (86..87) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/set2.typ +snapshot_kind: text --- [ { @@ -14,6 +15,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/set2.typ "labelDetails": { "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" }, + "sortText": "052", "textEdit": { "newText": "raw(${1:})", "range": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@set_block.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@set_block.typ.snap new file mode 100644 index 000000000..49d08b62a --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@set_block.typ.snap @@ -0,0 +1,35 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: Completion on / (26..27) +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/completion/set_block.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [ + { + "kind": 3, + "label": "block", + "labelDetails": { + "description": "(content | none, above: auto | fraction | relative, below: auto | fraction | relative, breakable: bool, clip: bool, fill: color, height: auto | fraction | relative, inset: inset, outset: outset, radius: radius, spacing: fraction | relative, sticky: bool, stroke: stroke, width: auto | relative) => block" + }, + "sortText": "003", + "textEdit": { + "newText": "block(${1:})", + "range": { + "end": { + "character": 6, + "line": 1 + }, + "start": { + "character": 5, + "line": 1 + } + } + } + } + ] + } +] diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@set_in_show.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@set_in_show.typ.snap new file mode 100644 index 000000000..b5b62d07a --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@set_in_show.typ.snap @@ -0,0 +1,35 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: Completion on / (114..115) +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/completion/set_in_show.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [ + { + "kind": 3, + "label": "raw", + "labelDetails": { + "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" + }, + "sortText": "052", + "textEdit": { + "newText": "raw(${1:})", + "range": { + "end": { + "character": 6, + "line": 2 + }, + "start": { + "character": 6, + "line": 2 + } + } + } + } + ] + } +] diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@set_param.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@set_param.typ.snap new file mode 100644 index 000000000..5ea37c302 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@set_param.typ.snap @@ -0,0 +1,35 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: Completion on / (35..36) +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/completion/set_param.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [ + { + "kind": 5, + "label": "fill", + "labelDetails": { + "description": "color" + }, + "sortText": "010", + "textEdit": { + "newText": "fill: ${1:}", + "range": { + "end": { + "character": 10, + "line": 1 + }, + "start": { + "character": 10, + "line": 1 + } + } + } + } + ] + } +] diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@show.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@show.typ.snap index b93331ef7..a76cabda8 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@show.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@show.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (75..76) +description: Completion on / (109..110) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/show.typ +snapshot_kind: text --- [ { @@ -14,8 +15,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/show.typ "labelDetails": { "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" }, + "sortText": "094", "textEdit": { - "newText": "raw(${1:})", + "newText": "raw: ${1:}", "range": { "end": { "character": 7, @@ -34,8 +36,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/show.typ "labelDetails": { "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" }, + "sortText": "095", "textEdit": { - "newText": "raw.where(${1:})", + "newText": "raw.where(${1:}): ${2:}", "range": { "end": { "character": 7, @@ -49,53 +52,11 @@ input_file: crates/tinymist-query/src/fixtures/completion/show.typ } }, { - "kind": 3, - "label": "raw.with", - "labelDetails": { - "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" - }, - "textEdit": { - "newText": "raw.with(${1:})", - "range": { - "end": { - "character": 7, - "line": 1 - }, - "start": { - "character": 6, - "line": 1 - } - } - } - }, - { - "kind": 3, - "label": "read", - "labelDetails": { - "description": "([any], encoding: \"utf8\" | none) => bytes | str" - }, - "textEdit": { - "newText": "read(${1:})", - "range": { - "end": { - "character": 7, - "line": 1 - }, - "start": { - "character": 6, - "line": 1 - } - } - } - }, - { - "kind": 3, - "label": "read.with", - "labelDetails": { - "description": "([any], encoding: \"utf8\" | none) => bytes | str" - }, + "kind": 15, + "label": "regex selector", + "sortText": "100", "textEdit": { - "newText": "read.with(${1:})", + "newText": "regex(\"${1:regex}\"): ${2:}", "range": { "end": { "character": 7, diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@show2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@show2.typ.snap index 03636a94c..578c9700c 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@show2.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@show2.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (103..104) +description: Completion on / (108..109) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/show2.typ +snapshot_kind: text --- [ { @@ -14,8 +15,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/show2.typ "labelDetails": { "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" }, + "sortText": "094", "textEdit": { - "newText": "raw: ", + "newText": "raw: ${1:}", "range": { "end": { "character": 6, @@ -34,8 +36,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/show2.typ "labelDetails": { "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" }, + "sortText": "095", "textEdit": { - "newText": "raw.where(${1:}): ", + "newText": "raw.where(${1:}): ${2:}", "range": { "end": { "character": 6, @@ -51,6 +54,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/show2.typ { "kind": 15, "label": "regex selector", + "sortText": "100", "textEdit": { "newText": "regex(\"${1:regex}\"): ${2:}", "range": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@show3.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@show3.typ.snap new file mode 100644 index 000000000..5c667a78c --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@show3.typ.snap @@ -0,0 +1,74 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: Completion on / (103..104) +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/completion/show3.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [ + { + "kind": 3, + "label": "raw", + "labelDetails": { + "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" + }, + "sortText": "094", + "textEdit": { + "newText": "raw: ${1:}", + "range": { + "end": { + "character": 6, + "line": 1 + }, + "start": { + "character": 6, + "line": 1 + } + } + } + }, + { + "kind": 3, + "label": "raw.where", + "labelDetails": { + "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" + }, + "sortText": "095", + "textEdit": { + "newText": "raw.where(${1:}): ${2:}", + "range": { + "end": { + "character": 6, + "line": 1 + }, + "start": { + "character": 6, + "line": 1 + } + } + } + }, + { + "kind": 15, + "label": "regex selector", + "sortText": "100", + "textEdit": { + "newText": "regex(\"${1:regex}\"): ${2:}", + "range": { + "end": { + "character": 6, + "line": 1 + }, + "start": { + "character": 6, + "line": 1 + } + } + } + } + ] + } +] diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@show_transform.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@show_transform.typ.snap index e2903af20..c2cb38000 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@show_transform.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@show_transform.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (80..81) +description: Completion on / (93..94) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/show_transform.typ +snapshot_kind: text --- [ { @@ -14,6 +15,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/show_transform.typ "labelDetails": { "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" }, + "sortText": "173", "textEdit": { "newText": "raw(${1:})", "range": { @@ -30,12 +32,13 @@ input_file: crates/tinymist-query/src/fixtures/completion/show_transform.typ }, { "kind": 3, - "label": "raw.where", + "label": "raw.with", "labelDetails": { "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" }, + "sortText": "174", "textEdit": { - "newText": "raw.where(${1:})", + "newText": "raw.with(${1:})", "range": { "end": { "character": 12, @@ -50,12 +53,13 @@ input_file: crates/tinymist-query/src/fixtures/completion/show_transform.typ }, { "kind": 3, - "label": "raw.with", + "label": "read", "labelDetails": { - "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" + "description": "([any], encoding: \"utf8\" | none) => bytes | str" }, + "sortText": "175", "textEdit": { - "newText": "raw.with(${1:})", + "newText": "read(${1:})", "range": { "end": { "character": 12, @@ -70,12 +74,13 @@ input_file: crates/tinymist-query/src/fixtures/completion/show_transform.typ }, { "kind": 3, - "label": "read", + "label": "read.with", "labelDetails": { "description": "([any], encoding: \"utf8\" | none) => bytes | str" }, + "sortText": "176", "textEdit": { - "newText": "read(${1:})", + "newText": "read.with(${1:})", "range": { "end": { "character": 12, @@ -89,13 +94,11 @@ input_file: crates/tinymist-query/src/fixtures/completion/show_transform.typ } }, { - "kind": 3, - "label": "read.with", - "labelDetails": { - "description": "([any], encoding: \"utf8\" | none) => bytes | str" - }, + "kind": 15, + "label": "replacement", + "sortText": "187", "textEdit": { - "newText": "read.with(${1:})", + "newText": "[${1:content}]", "range": { "end": { "character": 12, diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@show_transform2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@show_transform2.typ.snap index ba2c9f48b..6f9273586 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@show_transform2.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@show_transform2.typ.snap @@ -3,6 +3,7 @@ source: crates/tinymist-query/src/completion.rs description: Completion on / (92..93) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/show_transform2.typ +snapshot_kind: text --- [ { @@ -14,8 +15,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/show_transform2.typ "labelDetails": { "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" }, + "sortText": "173", "textEdit": { - "newText": "raw", + "newText": "raw(${1:})", "range": { "end": { "character": 11, @@ -30,12 +32,55 @@ input_file: crates/tinymist-query/src/fixtures/completion/show_transform2.typ }, { "kind": 3, - "label": "raw.where", + "label": "raw.with", "labelDetails": { "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" }, + "sortText": "174", "textEdit": { - "newText": "raw.where(${1:})", + "newText": "raw.with(${1:})", + "range": { + "end": { + "character": 11, + "line": 1 + }, + "start": { + "character": 11, + "line": 1 + } + } + } + }, + { + "kind": 3, + "label": "read", + "labelDetails": { + "description": "([any], encoding: \"utf8\" | none) => bytes | str" + }, + "sortText": "175", + "textEdit": { + "newText": "read(${1:})", + "range": { + "end": { + "character": 11, + "line": 1 + }, + "start": { + "character": 11, + "line": 1 + } + } + } + }, + { + "kind": 3, + "label": "read.with", + "labelDetails": { + "description": "([any], encoding: \"utf8\" | none) => bytes | str" + }, + "sortText": "176", + "textEdit": { + "newText": "read.with(${1:})", "range": { "end": { "character": 11, @@ -51,6 +96,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/show_transform2.typ { "kind": 15, "label": "replacement", + "sortText": "187", "textEdit": { "newText": "[${1:content}]", "range": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@show_transform3.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@show_transform3.typ.snap new file mode 100644 index 000000000..633f80a3a --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@show_transform3.typ.snap @@ -0,0 +1,116 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: Completion on / (91..92) +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/completion/show_transform3.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [ + { + "kind": 3, + "label": "raw", + "labelDetails": { + "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" + }, + "sortText": "173", + "textEdit": { + "newText": "raw(${1:})", + "range": { + "end": { + "character": 10, + "line": 1 + }, + "start": { + "character": 10, + "line": 1 + } + } + } + }, + { + "kind": 3, + "label": "raw.with", + "labelDetails": { + "description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw" + }, + "sortText": "174", + "textEdit": { + "newText": "raw.with(${1:})", + "range": { + "end": { + "character": 10, + "line": 1 + }, + "start": { + "character": 10, + "line": 1 + } + } + } + }, + { + "kind": 3, + "label": "read", + "labelDetails": { + "description": "([any], encoding: \"utf8\" | none) => bytes | str" + }, + "sortText": "175", + "textEdit": { + "newText": "read(${1:})", + "range": { + "end": { + "character": 10, + "line": 1 + }, + "start": { + "character": 10, + "line": 1 + } + } + } + }, + { + "kind": 3, + "label": "read.with", + "labelDetails": { + "description": "([any], encoding: \"utf8\" | none) => bytes | str" + }, + "sortText": "176", + "textEdit": { + "newText": "read.with(${1:})", + "range": { + "end": { + "character": 10, + "line": 1 + }, + "start": { + "character": 10, + "line": 1 + } + } + } + }, + { + "kind": 15, + "label": "replacement", + "sortText": "187", + "textEdit": { + "newText": "[${1:content}]", + "range": { + "end": { + "character": 10, + "line": 1 + }, + "start": { + "character": 10, + "line": 1 + } + } + } + } + ] + } +] diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@sig_dict.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@sig_dict.typ.snap index 017e9e659..0340f0028 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@sig_dict.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@sig_dict.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on ) (62..63) +description: Completion on ) (63..64) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/sig_dict.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@sig_dict_rest.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@sig_dict_rest.typ.snap index 3024268ba..d538093cd 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@sig_dict_rest.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@sig_dict_rest.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on ) (74..75) +description: Completion on ) (75..76) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/sig_dict_rest.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/docs/snaps/docs@base.typ.snap b/crates/tinymist-query/src/fixtures/docs/snaps/docs@base.typ.snap index 574312d1a..b2b2a561b 100644 --- a/crates/tinymist-query/src/fixtures/docs/snaps/docs@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/docs/snaps/docs@base.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/docs/base.typ +snapshot_kind: text --- = docstings Pattern(..)@20..21 in /s0.typ -> DocString { docs: Some("This is X."), var_bounds: {}, vars: {}, res_ty: None } diff --git a/crates/tinymist-query/src/fixtures/docs/snaps/docs@blocky.typ.snap b/crates/tinymist-query/src/fixtures/docs/snaps/docs@blocky.typ.snap index 0d6666f62..e9e5212d1 100644 --- a/crates/tinymist-query/src/fixtures/docs/snaps/docs@blocky.typ.snap +++ b/crates/tinymist-query/src/fixtures/docs/snaps/docs@blocky.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/docs/blocky.typ +snapshot_kind: text --- = docstings Pattern(..)@21..22 in /s0.typ -> DocString { docs: Some("This is X"), var_bounds: {}, vars: {}, res_ty: None } diff --git a/crates/tinymist-query/src/fixtures/docs/snaps/docs@blocky2.typ.snap b/crates/tinymist-query/src/fixtures/docs/snaps/docs@blocky2.typ.snap index 1725b3c05..6cbe835fe 100644 --- a/crates/tinymist-query/src/fixtures/docs/snaps/docs@blocky2.typ.snap +++ b/crates/tinymist-query/src/fixtures/docs/snaps/docs@blocky2.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/docs/blocky2.typ +snapshot_kind: text --- = docstings Pattern(..)@41..42 in /s0.typ -> DocString { docs: Some("This is X\nNote: This is not Y"), var_bounds: {}, vars: {}, res_ty: None } diff --git a/crates/tinymist-query/src/fixtures/docs/snaps/docs@multiple_line.typ.snap b/crates/tinymist-query/src/fixtures/docs/snaps/docs@multiple_line.typ.snap index f5b380b36..a078ab505 100644 --- a/crates/tinymist-query/src/fixtures/docs/snaps/docs@multiple_line.typ.snap +++ b/crates/tinymist-query/src/fixtures/docs/snaps/docs@multiple_line.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/docs/multiple_line.typ +snapshot_kind: text --- = docstings Pattern(..)@45..46 in /s0.typ -> DocString { docs: Some("This is X.\nNote: this is not Y."), var_bounds: {}, vars: {}, res_ty: None } diff --git a/crates/tinymist-query/src/fixtures/docs/snaps/docs@no_comment.typ.snap b/crates/tinymist-query/src/fixtures/docs/snaps/docs@no_comment.typ.snap index cf0ae171d..ef79bbcc2 100644 --- a/crates/tinymist-query/src/fixtures/docs/snaps/docs@no_comment.typ.snap +++ b/crates/tinymist-query/src/fixtures/docs/snaps/docs@no_comment.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/docs/no_comment.typ +snapshot_kind: text --- = docstings diff --git a/crates/tinymist-query/src/fixtures/docs/snaps/docs@not_attach.typ.snap b/crates/tinymist-query/src/fixtures/docs/snaps/docs@not_attach.typ.snap index 1c84e30f0..ff135950a 100644 --- a/crates/tinymist-query/src/fixtures/docs/snaps/docs@not_attach.typ.snap +++ b/crates/tinymist-query/src/fixtures/docs/snaps/docs@not_attach.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/docs/not_attach.typ +snapshot_kind: text --- = docstings diff --git a/crates/tinymist-query/src/fixtures/docs/snaps/docs@not_attach2.typ.snap b/crates/tinymist-query/src/fixtures/docs/snaps/docs@not_attach2.typ.snap index d2a7db117..d6534aab8 100644 --- a/crates/tinymist-query/src/fixtures/docs/snaps/docs@not_attach2.typ.snap +++ b/crates/tinymist-query/src/fixtures/docs/snaps/docs@not_attach2.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/docs/not_attach2.typ +snapshot_kind: text --- = docstings diff --git a/crates/tinymist-query/src/fixtures/docs/snaps/docs@param.typ.snap b/crates/tinymist-query/src/fixtures/docs/snaps/docs@param.typ.snap index 90490d75f..1cca73155 100644 --- a/crates/tinymist-query/src/fixtures/docs/snaps/docs@param.typ.snap +++ b/crates/tinymist-query/src/fixtures/docs/snaps/docs@param.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/docs/param.typ +snapshot_kind: text --- = docstings Func(f)@21..22 in /s0.typ -> DocString { docs: Some("Docs for f."), var_bounds: {}, vars: {}, res_ty: None } diff --git a/crates/tinymist-query/src/fixtures/docs/snaps/docs@param_in_init.typ.snap b/crates/tinymist-query/src/fixtures/docs/snaps/docs@param_in_init.typ.snap index 772b06631..85ce8d596 100644 --- a/crates/tinymist-query/src/fixtures/docs/snaps/docs@param_in_init.typ.snap +++ b/crates/tinymist-query/src/fixtures/docs/snaps/docs@param_in_init.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/docs/param_in_init.typ +snapshot_kind: text --- = docstings Func(f)@21..22 in /s0.typ -> DocString { docs: Some("Docs for f."), var_bounds: {}, vars: {}, res_ty: None } diff --git a/crates/tinymist-query/src/fixtures/docs/snaps/docs@raw.typ.snap b/crates/tinymist-query/src/fixtures/docs/snaps/docs@raw.typ.snap index 662baa425..1d9ad9945 100644 --- a/crates/tinymist-query/src/fixtures/docs/snaps/docs@raw.typ.snap +++ b/crates/tinymist-query/src/fixtures/docs/snaps/docs@raw.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/docs/raw.typ +snapshot_kind: text --- = docstings Func(f)@109..110 in /s0.typ -> DocString { docs: Some(" Docs for f.\n\n ```typst\n #show raw: it => it {\n it\n }\n ```"), var_bounds: {}, vars: {}, res_ty: None } diff --git a/crates/tinymist-query/src/fixtures/document_color/snaps/test@advanced.typ.snap b/crates/tinymist-query/src/fixtures/document_color/snaps/test@advanced.typ.snap index a98da6f4b..c97bf9265 100644 --- a/crates/tinymist-query/src/fixtures/document_color/snaps/test@advanced.typ.snap +++ b/crates/tinymist-query/src/fixtures/document_color/snaps/test@advanced.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/document_color.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/document_color/advanced.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/document_color/snaps/test@base.typ.snap b/crates/tinymist-query/src/fixtures/document_color/snaps/test@base.typ.snap index b84f28eb2..271361415 100644 --- a/crates/tinymist-query/src/fixtures/document_color/snaps/test@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/document_color/snaps/test@base.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/document_color.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/document_color/base.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/document_color/snaps/test@rgb.typ.snap b/crates/tinymist-query/src/fixtures/document_color/snaps/test@rgb.typ.snap index 6e8b76692..df42cf25e 100644 --- a/crates/tinymist-query/src/fixtures/document_color/snaps/test@rgb.typ.snap +++ b/crates/tinymist-query/src/fixtures/document_color/snaps/test@rgb.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/document_color.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/document_color/rgb.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@base.typ.snap b/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@base.typ.snap index 21778c69c..1ab547d6d 100644 --- a/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@base.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/document_highlight.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/document_highlight/base.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@nest.typ.snap b/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@nest.typ.snap index 50cd0c199..aed320b57 100644 --- a/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@nest.typ.snap +++ b/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@nest.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/document_highlight.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/document_highlight/nest.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@nest2.typ.snap b/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@nest2.typ.snap index 909403c93..52abd6080 100644 --- a/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@nest2.typ.snap +++ b/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@nest2.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/document_highlight.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/document_highlight/nest2.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@syntax_error.typ.snap b/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@syntax_error.typ.snap index 4c3eb2d06..d3a02261a 100644 --- a/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@syntax_error.typ.snap +++ b/crates/tinymist-query/src/fixtures/document_highlight/snaps/test@syntax_error.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/document_highlight.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/document_highlight/syntax_error.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@base.typ.snap b/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@base.typ.snap index e894b4d4d..c996ee088 100644 --- a/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@base.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/document_symbol.rs expression: "JsonRepr::new_redacted(result.unwrap(), &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/document_symbols/base.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@func.typ.snap b/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@func.typ.snap index e5ef1cf96..c92f23373 100644 --- a/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@func.typ.snap +++ b/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@func.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/document_symbol.rs expression: "JsonRepr::new_redacted(result.unwrap(), &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/document_symbols/func.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@headings-in-blocks.typ.snap b/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@headings-in-blocks.typ.snap index 9477068d9..799d70360 100644 --- a/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@headings-in-blocks.typ.snap +++ b/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@headings-in-blocks.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/document_symbol.rs expression: "JsonRepr::new_redacted(result.unwrap(), &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/document_symbols/headings-in-blocks.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@nested-blocks.typ.snap b/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@nested-blocks.typ.snap index 42f2bc434..a077c6aee 100644 --- a/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@nested-blocks.typ.snap +++ b/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@nested-blocks.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/document_symbol.rs expression: "JsonRepr::new_redacted(result.unwrap(), &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/document_symbols/nested-blocks.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@nested-func.typ.snap b/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@nested-func.typ.snap index d369054dc..15731b5d1 100644 --- a/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@nested-func.typ.snap +++ b/crates/tinymist-query/src/fixtures/document_symbols/snaps/test@nested-func.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/document_symbol.rs expression: "JsonRepr::new_redacted(result.unwrap(), &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/document_symbols/nested-func.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@base.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@base.typ.snap index 8eac3906c..a3eea5b8a 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@base.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/base.typ +snapshot_kind: text --- = resolves Var(x)@34..35 in /s0.typ -> Var(x)@34..35 in /s0.typ, root Var(x)@34..35 in /s0.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@base2.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@base2.typ.snap index f4b3360cc..c4731fae0 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@base2.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@base2.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/base2.typ +snapshot_kind: text --- = resolves ModuleImport(..)@1..21 in /s0.typ -> Module(base)@0..0 in /base.typ, root Module(base)@0..0 in /base.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@destructing.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@destructing.typ.snap index c0ab0442c..1c896fadc 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@destructing.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@destructing.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/destructing.typ +snapshot_kind: text --- = resolves Var(a)@6..7 in /s0.typ -> Var(a)@6..7 in /s0.typ, root Var(a)@6..7 in /s0.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@dict.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@dict.typ.snap index 3aeba5073..1800d6ddb 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@dict.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@dict.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/dict.typ +snapshot_kind: text --- = resolves Var(z)@5..6 in /s0.typ -> Var(z)@5..6 in /s0.typ, root Var(z)@5..6 in /s0.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@for_loop.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@for_loop.typ.snap index 0920d8a40..5ff68316c 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@for_loop.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@for_loop.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/for_loop.typ +snapshot_kind: text --- = resolves Var(i)@5..6 in /s0.typ -> Var(i)@5..6 in /s0.typ, root Var(i)@5..6 in /s0.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@func.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@func.typ.snap index 449817d12..caf3c6683 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@func.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@func.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/func.typ +snapshot_kind: text --- = resolves Var(x)@5..6 in /s0.typ -> Var(x)@5..6 in /s0.typ, root Var(x)@5..6 in /s0.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import.typ.snap index 701e385c5..c46469140 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/import.typ +snapshot_kind: text --- = resolves PathStem(base)@8..18 in /s0.typ -> Module(base)@0..0 in /base.typ, root Module(base)@0..0 in /base.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_alias.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_alias.typ.snap index 9f5761668..d9e994e50 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_alias.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_alias.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/import_alias.typ +snapshot_kind: text --- = resolves PathStem(base)@8..18 in /s0.typ -> Module(base)@0..0 in /base.typ, root Module(base)@0..0 in /base.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_alias_both.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_alias_both.typ.snap index 65b9cee87..ed6d5b670 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_alias_both.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_alias_both.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/import_alias_both.typ +snapshot_kind: text --- = resolves PathStem(base)@8..18 in /s0.typ -> Module(base)@0..0 in /base.typ, root Module(base)@0..0 in /base.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_by_ident.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_by_ident.typ.snap index 957c2e2e5..8820d2a5a 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_by_ident.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_by_ident.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/import_by_ident.typ +snapshot_kind: text --- = resolves ModuleImport(..)@1..23 in /s2.typ -> Module(derive)@0..0 in /derive.typ, root Module(derive)@0..0 in /derive.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_ident.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_ident.typ.snap index 5a262d8b6..8737b4540 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_ident.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_ident.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/import_ident.typ +snapshot_kind: text --- = resolves PathStem(base)@8..18 in /s0.typ -> Module(base)@0..0 in /base.typ, root Module(base)@0..0 in /base.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_ident_alias.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_ident_alias.typ.snap index a27fc2282..1cf6369ab 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_ident_alias.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_ident_alias.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/import_ident_alias.typ +snapshot_kind: text --- = resolves PathStem(base)@8..18 in /s0.typ -> Module(base)@0..0 in /base.typ, root Module(base)@0..0 in /base.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_star.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_star.typ.snap index cea79ac7d..7468e64bf 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_star.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_star.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/import_star.typ +snapshot_kind: text --- = resolves PathStem(base)@8..18 in /s1.typ -> Module(base)@0..0 in /base.typ, root Module(base)@0..0 in /base.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_star_recursive.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_star_recursive.typ.snap index 75f3442a2..a9f1532ea 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_star_recursive.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@import_star_recursive.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/import_star_recursive.typ +snapshot_kind: text --- = resolves ModuleImport(..)@1..22 in /s2.typ -> Module(base2)@0..0 in /base2.typ, root Module(base2)@0..0 in /base2.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@param_scope.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@param_scope.typ.snap index c6f86df46..8589af323 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@param_scope.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@param_scope.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/param_scope.typ +snapshot_kind: text --- = resolves Func(term)@5..9 in /s0.typ -> Func(term)@5..9 in /s0.typ, root Func(term)@5..9 in /s0.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@redefine.typ.snap b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@redefine.typ.snap index e63974b17..bd50915a0 100644 --- a/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@redefine.typ.snap +++ b/crates/tinymist-query/src/fixtures/expr_of/snaps/scope@redefine.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "snap.join(\"\\n\")" input_file: crates/tinymist-query/src/fixtures/expr_of/redefine.typ +snapshot_kind: text --- = resolves Var(x)@5..6 in /s0.typ -> Var(x)@5..6 in /s0.typ, root Var(x)@5..6 in /s0.typ, val: None diff --git a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@array_folding.typ.snap b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@array_folding.typ.snap index 822f960e4..fc10e4192 100644 --- a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@array_folding.typ.snap +++ b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@array_folding.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/folding_range.rs expression: "JsonRepr::new_pure(json!({ \"false\": result_false, \"true\": result_true, }))" input_file: crates/tinymist-query/src/fixtures/folding_range/array_folding.typ +snapshot_kind: text --- { "false": [ diff --git a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@base.typ.snap b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@base.typ.snap index 46d5dc83e..662ca39ea 100644 --- a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@base.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/folding_range.rs expression: "JsonRepr::new_pure(json!({ \"false\": result_false, \"true\": result_true, }))" input_file: crates/tinymist-query/src/fixtures/folding_range/base.typ +snapshot_kind: text --- { "false": [ diff --git a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@heading-in-multiple-content.typ.snap b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@heading-in-multiple-content.typ.snap index 7b84665d6..f0fe28f1e 100644 --- a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@heading-in-multiple-content.typ.snap +++ b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@heading-in-multiple-content.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/folding_range.rs expression: "JsonRepr::new_pure(json!({ \"false\": result_false, \"true\": result_true, }))" input_file: crates/tinymist-query/src/fixtures/folding_range/heading-in-multiple-content.typ +snapshot_kind: text --- { "false": [ diff --git a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@headings-in-blocks.typ.snap b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@headings-in-blocks.typ.snap index becbf5ec9..9fe0bf1dd 100644 --- a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@headings-in-blocks.typ.snap +++ b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@headings-in-blocks.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/folding_range.rs expression: "JsonRepr::new_pure(json!({ \"false\": result_false, \"true\": result_true, }))" input_file: crates/tinymist-query/src/fixtures/folding_range/headings-in-blocks.typ +snapshot_kind: text --- { "false": [ diff --git a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@let-tuple.typ.snap b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@let-tuple.typ.snap index 17afad1a0..7e93b9d7a 100644 --- a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@let-tuple.typ.snap +++ b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@let-tuple.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/folding_range.rs expression: "JsonRepr::new_pure(json!({ \"false\": result_false, \"true\": result_true, }))" input_file: crates/tinymist-query/src/fixtures/folding_range/let-tuple.typ +snapshot_kind: text --- { "false": [ diff --git a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@multiple-content-2.typ.snap b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@multiple-content-2.typ.snap index 560c23024..dac4d1344 100644 --- a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@multiple-content-2.typ.snap +++ b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@multiple-content-2.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/folding_range.rs expression: "JsonRepr::new_pure(json!({ \"false\": result_false, \"true\": result_true, }))" input_file: crates/tinymist-query/src/fixtures/folding_range/multiple-content-2.typ +snapshot_kind: text --- { "false": [ diff --git a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@multiple-content.typ.snap b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@multiple-content.typ.snap index 56cb80ff7..bee25aba4 100644 --- a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@multiple-content.typ.snap +++ b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@multiple-content.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/folding_range.rs expression: "JsonRepr::new_pure(json!({ \"false\": result_false, \"true\": result_true, }))" input_file: crates/tinymist-query/src/fixtures/folding_range/multiple-content.typ +snapshot_kind: text --- { "false": [ diff --git a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@nested-blocks-2.typ.snap b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@nested-blocks-2.typ.snap index 0068ce73b..b182f186d 100644 --- a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@nested-blocks-2.typ.snap +++ b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@nested-blocks-2.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/folding_range.rs expression: "JsonRepr::new_pure(json!({ \"false\": result_false, \"true\": result_true, }))" input_file: crates/tinymist-query/src/fixtures/folding_range/nested-blocks-2.typ +snapshot_kind: text --- { "false": [ diff --git a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@nested-blocks.typ.snap b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@nested-blocks.typ.snap index 58d404794..9f28b60f5 100644 --- a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@nested-blocks.typ.snap +++ b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@nested-blocks.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/folding_range.rs expression: "JsonRepr::new_pure(json!({ \"false\": result_false, \"true\": result_true, }))" input_file: crates/tinymist-query/src/fixtures/folding_range/nested-blocks.typ +snapshot_kind: text --- { "false": [ diff --git a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@paren_folding.typ.snap b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@paren_folding.typ.snap index 5841c9c6b..aab8af682 100644 --- a/crates/tinymist-query/src/fixtures/folding_range/snaps/test@paren_folding.typ.snap +++ b/crates/tinymist-query/src/fixtures/folding_range/snaps/test@paren_folding.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/folding_range.rs expression: "JsonRepr::new_pure(json!({ \"false\": result_false, \"true\": result_true, }))" input_file: crates/tinymist-query/src/fixtures/folding_range/paren_folding.typ +snapshot_kind: text --- { "false": [ diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@at_def.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@at_def.typ.snap index be2f8b532..8ecbb5b35 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@at_def.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@at_def.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/at_def.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@base.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@base.typ.snap index 3dc32b31d..820477827 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@base.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/base.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@builtin.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@builtin.typ.snap index 159699ca4..76be41319 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@builtin.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@builtin.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/builtin.typ +snapshot_kind: text --- null diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_alias.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_alias.typ.snap index 76d12c079..357ba817a 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_alias.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_alias.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/import_alias.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_ident.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_ident.typ.snap index 4e90dd63c..6ac4a5ab9 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_ident.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_ident.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/import_ident.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_new_name.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_new_name.typ.snap index f6751f0a0..e0d512204 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_new_name.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_new_name.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/import_new_name.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_package.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_package.typ.snap index b2f1ebea1..1ce1bc505 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_package.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_package.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/import_package.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_package_self.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_package_self.typ.snap index 0acdfa5c5..a6072910c 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_package_self.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_package_self.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/import_package_self.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_path_inner.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_path_inner.typ.snap index aa760a3b5..e9c979d8e 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_path_inner.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_path_inner.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/import_path_inner.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_self.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_self.typ.snap index 70f90b9a4..408c2dc9b 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_self.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_self.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/import_self.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_star.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_star.typ.snap index f5d2d62f3..8bf65068d 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_star.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_star.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/import_star.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_star_variable.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_star_variable.typ.snap index 79bf172d9..4100100b9 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_star_variable.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@import_star_variable.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/import_star_variable.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_block.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_block.typ.snap index a31214517..302d7d7d1 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_block.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_block.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/inside_block.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_import.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_import.typ.snap index 71517a418..ff604acc4 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_import.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_import.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/inside_import.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_import_alias.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_import_alias.typ.snap index 0ededc764..ce7f16e28 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_import_alias.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_import_alias.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/inside_import_alias.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_import_alias2.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_import_alias2.typ.snap index 1fed72fbf..7a7ff51e3 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_import_alias2.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@inside_import_alias2.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/inside_import_alias2.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@label.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@label.typ.snap index 07331a9f4..342d0e055 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@label.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@label.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/label.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@label_indir.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@label_indir.typ.snap index fd73680fa..59028661c 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@label_indir.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@label_indir.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/label_indir.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@label_indir2.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@label_indir2.typ.snap index 84de7ea43..78ec4b8f0 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@label_indir2.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@label_indir2.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/label_indir2.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@module_select.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@module_select.typ.snap index 0bd2a3ce0..183abfe40 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@module_select.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@module_select.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/module_select.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@module_select_alias.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@module_select_alias.typ.snap index 3ccd196b1..43614daa6 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@module_select_alias.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@module_select_alias.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/module_select_alias.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@paren.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@paren.typ.snap index a6e63f91f..f36905a6d 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@paren.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@paren.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/paren.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@paren_lhs.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@paren_lhs.typ.snap index 5d65593bb..6b6535650 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@paren_lhs.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@paren_lhs.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/paren_lhs.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@variable.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@variable.typ.snap index 7520d1585..7a31a1a63 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@variable.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/snaps/test@variable.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/goto_definition.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/goto_definition/variable.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/hover/annotate_dict_param.typ b/crates/tinymist-query/src/fixtures/hover/annotate_dict_param.typ new file mode 100644 index 000000000..318c42006 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/hover/annotate_dict_param.typ @@ -0,0 +1,8 @@ +/// - inherited-scope (dictionary): Definitions that are made available to the entire parsed +/// module. This parameter is only used internally. +#let show-example( + inherited-scope: (:), + ..options, +) = none + +#(/* ident after */ show-example); diff --git a/crates/tinymist-query/src/fixtures/hover/annotate_dict_param2.typ b/crates/tinymist-query/src/fixtures/hover/annotate_dict_param2.typ new file mode 100644 index 000000000..b5413b838 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/hover/annotate_dict_param2.typ @@ -0,0 +1,9 @@ +/// - inherited-scope (dictionary): Definitions that are made available to the entire parsed +/// module. This parameter is only used internally. +#let show-example( + inherited-scope: (:), + ..options, +) = { + (/* ident after */ inherited-scope) +} + diff --git a/crates/tinymist-query/src/fixtures/hover/annotate_docs_error.typ b/crates/tinymist-query/src/fixtures/hover/annotate_docs_error.typ new file mode 100644 index 000000000..17b25bf3f --- /dev/null +++ b/crates/tinymist-query/src/fixtures/hover/annotate_docs_error.typ @@ -0,0 +1,12 @@ +/// Speaker notes are a way to add additional information to your slides that is not visible to the audience. This can be useful for providing additional context or reminders to yourself. +/// +/// == Example +/// +/// #example(```typ +/// #speaker-note[This is a speaker note] +/// ```) +#let speaker-note(mode: "typ", setting: it => it, note) = { + touying-fn-wrapper(utils.speaker-note, mode: mode, setting: setting, note) +} + +#(/* ident after */ speaker-note); diff --git a/crates/tinymist-query/src/fixtures/hover/annotate_ret.typ b/crates/tinymist-query/src/fixtures/hover/annotate_ret.typ new file mode 100644 index 000000000..8d521a8dd --- /dev/null +++ b/crates/tinymist-query/src/fixtures/hover/annotate_ret.typ @@ -0,0 +1,8 @@ + +/// -> content +#let _delayed-wrapper(body) = utils.label-it( + metadata((kind: "touying-delayed-wrapper", body: body)), + "touying-temporary-mark", +) + +#(/* ident after */ _delayed-wrapper); diff --git a/crates/tinymist-query/src/fixtures/hover/render_equation.typ b/crates/tinymist-query/src/fixtures/hover/render_equation.typ new file mode 100644 index 000000000..1589f460a --- /dev/null +++ b/crates/tinymist-query/src/fixtures/hover/render_equation.typ @@ -0,0 +1,13 @@ +/// Lambda constructor. +/// +/// Typing Rule: +/// +/// $ (Γ , x : A ⊢ M : B #h(2em) Γ ⊢ a:B)/(Γ ⊢ λ (x : A) → M : Ï€ (x : A) → B) $ +/// +/// - A (type): The type of the argument. +/// - It can be also regarded as the condition of the proposition. +/// - B (type): The type of the body. +/// - It can be also regarded as the conclusion of the proposition. +#let lam(A, B) = (kind: "lambda", args: A, body: B) + +#(/* ident after */ lam); diff --git a/crates/tinymist-query/src/fixtures/hover/render_equation_no_html.typ b/crates/tinymist-query/src/fixtures/hover/render_equation_no_html.typ new file mode 100644 index 000000000..d5a5f4615 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/hover/render_equation_no_html.typ @@ -0,0 +1,15 @@ +/// html: false + +/// Lambda constructor. +/// +/// Typing Rule: +/// +/// $ (Γ , x : A ⊢ M : B #h(2em) Γ ⊢ a:B)/(Γ ⊢ λ (x : A) → M : Ï€ (x : A) → B) $ +/// +/// - A (type): The type of the argument. +/// - It can be also regarded as the condition of the proposition. +/// - B (type): The type of the body. +/// - It can be also regarded as the conclusion of the proposition. +#let lam(A, B) = (kind: "lambda", args: A, body: B) + +#(/* ident after */ lam); diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_dict_param.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_dict_param.typ.snap new file mode 100644 index 000000000..02a82d41a --- /dev/null +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_dict_param.typ.snap @@ -0,0 +1,10 @@ +--- +source: crates/tinymist-query/src/hover.rs +expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" +input_file: crates/tinymist-query/src/fixtures/hover/annotate_dict_param.typ +snapshot_kind: text +--- +{ + "contents": "```typc\nlet show-example(\n ..options: arguments,\n inherited-scope: dictionary = (:),\n) = none;\n```\n\n---\n- inherited-scope (dictionary): Definitions that are made available to the entire parsed\n module. This parameter is only used internally.\n\n# Rest Parameters\n\n## options\n\n```typc\ntype: arguments\n```\n\n\n\n# Named Parameters\n\n## inherited-scope\n\n```typc\ntype: dictionary\n```\n\nDefinitions that are made available to the entire parsed\n module. This parameter is only used internally.", + "range": "7:20:7:32" +} diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_dict_param2.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_dict_param2.typ.snap new file mode 100644 index 000000000..660f98b2d --- /dev/null +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_dict_param2.typ.snap @@ -0,0 +1,10 @@ +--- +source: crates/tinymist-query/src/hover.rs +expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" +input_file: crates/tinymist-query/src/fixtures/hover/annotate_dict_param2.typ +snapshot_kind: text +--- +{ + "contents": "```typc\nlet inherited-scope = any;\n```\n\n---\nDefinitions that are made available to the entire parsed\n module. This parameter is only used internally.", + "range": "6:21:6:36" +} diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_docs_error.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_docs_error.typ.snap new file mode 100644 index 000000000..e99d4d13e --- /dev/null +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_docs_error.typ.snap @@ -0,0 +1,10 @@ +--- +source: crates/tinymist-query/src/hover.rs +expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" +input_file: crates/tinymist-query/src/fixtures/hover/annotate_docs_error.typ +snapshot_kind: text +--- +{ + "contents": "```typc\nlet speaker-note(\n note: any,\n mode: str = \"typ\",\n setting: (any) => any = Closure(..),\n) = none;\n```\n\n---\nSpeaker notes are a way to add additional information to your slides that is not visible to the audience. This can be useful for providing additional context or reminders to yourself.\n\n ## Example\n\n ```typ\n#speaker-note[This is a speaker note]\n\n```\n```\nRender Error\ncompiling node: error: unknown variable: speaker-note at \"/__render__.typ\":201..213\nHint: if you meant to use subtraction, try adding spaces around the minus sign: \\`speaker - note\\`\n\n```\n\n# Positional Parameters\n\n## note\n\n```typc\ntype: \n```\n\n\n\n# Named Parameters\n\n## mode\n\n```typc\ntype: \"typ\"\n```\n\n\n\n## setting (named)\n\n```typc\ntype: (any) => any\n```\n\n", + "range": "11:20:11:32" +} diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_fn.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_fn.typ.snap index 0df9b50eb..64418d073 100644 --- a/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_fn.typ.snap +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_fn.typ.snap @@ -2,8 +2,9 @@ source: crates/tinymist-query/src/hover.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/hover/annotate_fn.typ +snapshot_kind: text --- { - "contents": "```typc\nlet touying-fn-wrapper(\n fn: (..: []) => any | function,\n ..args: arguments,\n max-repetitions: int | none = none,\n repetitions: int | none = none,\n) = none;\n```\n\n---\n## Parameters\n\n@positional `fn` — The `fn`.\n\n@named `max-repetitions` — The `max-repetitions`.\n\n@named `repetitions` — The `repetitions`.\n\n@rest `args` — The `args`.", + "contents": "```typc\nlet touying-fn-wrapper(\n fn: (..: any) => any | function,\n ..args: arguments,\n max-repetitions: int | none = none,\n repetitions: int | none = none,\n) = none;\n```\n\n---\n\n\n# Positional Parameters\n\n## fn\n\n```typc\ntype: (..: any) => any | function\n```\n\nThe `fn`.\n\n# Rest Parameters\n\n## args\n\n```typc\ntype: arguments\n```\n\nThe `args`.\n\n# Named Parameters\n\n## max-repetitions\n\n```typc\ntype: int | none\n```\n\nThe `max-repetitions`.\n\n## repetitions (named)\n\n```typc\ntype: int | none\n```\n\nThe `repetitions`.", "range": "8:20:8:38" } diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_ret.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_ret.typ.snap new file mode 100644 index 000000000..50dfcbd8f --- /dev/null +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@annotate_ret.typ.snap @@ -0,0 +1,10 @@ +--- +source: crates/tinymist-query/src/hover.rs +expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" +input_file: crates/tinymist-query/src/fixtures/hover/annotate_ret.typ +snapshot_kind: text +--- +{ + "contents": "```typc\nlet _delayed-wrapper(\n body: any,\n) = content;\n```\n\n---\n\n\n# Positional Parameters\n\n## body\n\n```typc\ntype: \n```\n\n", + "range": "6:20:6:36" +} diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin.typ.snap index 10ce9e1a5..40280aac4 100644 --- a/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin.typ.snap +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin.typ.snap @@ -2,8 +2,9 @@ source: crates/tinymist-query/src/hover.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/hover/builtin.typ +snapshot_kind: text --- { - "contents": "```typc\nlet table(\n ..children: content,\n align: alignment | array | auto | function = auto,\n column-gutter: array | auto | length | type = (),\n columns: array | auto | length | type = (),\n fill: color = none,\n gutter: array | auto | length | type = (),\n inset: inset = 0% + 5pt,\n row-gutter: array | auto | length | type = (),\n rows: array | auto | length | type = (),\n stroke: stroke = 1pt + black,\n);\n```\n\n---\nA table of items.\n\nTables are used to arrange content in cells. Cells can contain arbitrary\ncontent, including multiple paragraphs and are specified in row-major order.\nFor a hands-on explanation of all the ways you can use and customize tables\nin Typst, check out the [table guide](https://typst.app/docs/guides/table-guide/).\n\nBecause tables are just grids with different defaults for some cell\nproperties (notably `stroke` and `inset`), refer to the [grid\ndocumentation](https://typst.app/docs/reference/layout/grid/) for more information on how to size the table tracks\nand specify the cell appearance properties.\n\nIf you are unsure whether you should be using a table or a grid, consider\nwhether the content you are arranging semantically belongs together as a set\nof related data points or similar or whether you are just want to enhance\nyour presentation by arranging unrelated content in a grid. In the former\ncase, a table is the right choice, while in the latter case, a grid is more\nappropriate. Furthermore, Typst will annotate its output in the future such\nthat screenreaders will announce content in `table` as tabular while a\ngrid's content will be announced no different than multiple content blocks\nin the document flow.\n\nNote that, to override a particular cell's properties or apply show rules on\ntable cells, you can use the [`table.cell`](https://typst.app/docs/reference/model/table/#definitions-cell) element. See its\ndocumentation for more information.\n\nAlthough the `table` and the `grid` share most properties, set and show\nrules on one of them do not affect the other.\n\nTo give a table a caption and make it [referenceable](https://typst.app/docs/reference/model/ref/), put it into a\n[figure].\n\n# Example\n\nThe example below demonstrates some of the most common table options.\n```typ\n#table(\n columns: (1fr, auto, auto),\n inset: 10pt,\n align: horizon,\n table.header(\n [], [*Volume*], [*Parameters*],\n ),\n image(\"cylinder.svg\"),\n $ pi h (D^2 - d^2) / 4 $,\n [\n $h$: height \\\n $D$: outer radius \\\n $d$: inner radius\n ],\n image(\"tetrahedron.svg\"),\n $ sqrt(2) / 12 a^3 $,\n [$a$: edge length]\n)\n```\n\nMuch like with grids, you can use [`table.cell`](https://typst.app/docs/reference/model/table/#definitions-cell) to customize\nthe appearance and the position of each cell.\n\n```typ\n>>> #set page(width: auto)\n>>> #set text(font: \"IBM Plex Sans\")\n>>> #let gray = rgb(\"#565565\")\n>>>\n#set table(\n stroke: none,\n gutter: 0.2em,\n fill: (x, y) =>\n if x == 0 or y == 0 { gray },\n inset: (right: 1.5em),\n)\n\n#show table.cell: it => {\n if it.x == 0 or it.y == 0 {\n set text(white)\n strong(it)\n } else if it.body == [] {\n // Replace empty cells with 'N/A'\n pad(..it.inset)[_N/A_]\n } else {\n it\n }\n}\n\n#let a = table.cell(\n fill: green.lighten(60%),\n)[A]\n#let b = table.cell(\n fill: aqua.lighten(60%),\n)[B]\n\n#table(\n columns: 4,\n [], [Exam 1], [Exam 2], [Exam 3],\n\n [John], [], a, [],\n [Mary], [], a, a,\n [Robert], b, a, b,\n)\n```\n\n## Parameters\n\n@named `align` — How to align the cells' content.\n\nThis can either be a single alignment, an array of alignments\n(corresponding to each column) or a function that returns an alignment.\nThe function receives the cells' column and row indices, starting from\nzero. If set to `auto`, the outer alignment is used.\n\n```typ\n#table(\n columns: 3,\n align: (left, center, right),\n [Hello], [Hello], [Hello],\n [A], [B], [C],\n)\n```\n\n@named `column-gutter` — The gaps between columns. Takes precedence over `gutter`. See the\n[grid documentation](https://typst.app/docs/reference/layout/grid/) for more information on gutters.\n\n@named `columns` — The column sizes. See the [grid documentation](https://typst.app/docs/reference/layout/grid/) for more\ninformation on track sizing.\n\n@named `fill` — How to fill the cells.\n\nThis can be a color or a function that returns a color. The function\nreceives the cells' column and row indices, starting from zero. This can\nbe used to implement striped tables.\n\n```typ\n#table(\n fill: (x, _) =>\n if calc.odd(x) { luma(240) }\n else { white },\n align: (x, y) =>\n if y == 0 { center }\n else if x == 0 { left }\n else { right },\n columns: 4,\n [], [*Q1*], [*Q2*], [*Q3*],\n [Revenue:], [1000 €], [2000 €], [3000 €],\n [Expenses:], [500 €], [1000 €], [1500 €],\n [Profit:], [500 €], [1000 €], [1500 €],\n)\n```\n\n@named `gutter` — The gaps between rows and columns. This is a shorthand for setting\n`column-gutter` and `row-gutter` to the same value. See the [grid\ndocumentation](https://typst.app/docs/reference/layout/grid/) for more information on gutters.\n\n@named `inset` — How much to pad the cells' content.\n\n```typ\n#table(\n inset: 10pt,\n [Hello],\n [World],\n)\n\n#table(\n columns: 2,\n inset: (\n x: 20pt,\n y: 10pt,\n ),\n [Hello],\n [World],\n)\n```\n\n@named `row-gutter` — The gaps between rows. Takes precedence over `gutter`. See the\n[grid documentation](https://typst.app/docs/reference/layout/grid/) for more information on gutters.\n\n@named `rows` — The row sizes. See the [grid documentation](https://typst.app/docs/reference/layout/grid/) for more information\non track sizing.\n\n@named `stroke` — How to [stroke] the cells.\n\nStrokes can be disabled by setting this to `none`.\n\nIf it is necessary to place lines which can cross spacing between cells\nproduced by the `gutter` option, or to override the stroke between\nmultiple specific cells, consider specifying one or more of\n[`table.hline`](https://typst.app/docs/reference/model/table/#definitions-hline) and [`table.vline`](https://typst.app/docs/reference/model/table/#definitions-vline)\nalongside your table cells.\n\nSee the [grid documentation](https://typst.app/docs/reference/layout/grid/#parameters-stroke) for more information on\nstrokes.\n\n@rest `children` — The contents of the table cells, plus any extra table lines specified\nwith the [`table.hline`](https://typst.app/docs/reference/model/table/#definitions-hline) and\n[`table.vline`](https://typst.app/docs/reference/model/table/#definitions-vline) elements.\n\n---\n[Open docs](https://typst.app/docs/reference/model/table/)", + "contents": "```typc\nlet table(\n ..children: content,\n align: alignment | array | auto | function = auto,\n column-gutter: array | auto | length | type = (),\n columns: array | auto | length | type = (),\n fill: color = none,\n gutter: array | auto | length | type = (),\n inset: inset = 0% + 5pt,\n row-gutter: array | auto | length | type = (),\n rows: array | auto | length | type = (),\n stroke: stroke = 1pt + black,\n);\n```\n\n---\nA table of items.\n\nTables are used to arrange content in cells. Cells can contain arbitrary\ncontent, including multiple paragraphs and are specified in row-major order.\nFor a hands-on explanation of all the ways you can use and customize tables\nin Typst, check out the [table guide](https://typst.app/docs/guides/table-guide/).\n\nBecause tables are just grids with different defaults for some cell\nproperties (notably `stroke` and `inset`), refer to the [grid\ndocumentation](https://typst.app/docs/reference/layout/grid/) for more information on how to size the table tracks\nand specify the cell appearance properties.\n\nIf you are unsure whether you should be using a table or a grid, consider\nwhether the content you are arranging semantically belongs together as a set\nof related data points or similar or whether you are just want to enhance\nyour presentation by arranging unrelated content in a grid. In the former\ncase, a table is the right choice, while in the latter case, a grid is more\nappropriate. Furthermore, Typst will annotate its output in the future such\nthat screenreaders will announce content in `table` as tabular while a\ngrid's content will be announced no different than multiple content blocks\nin the document flow.\n\nNote that, to override a particular cell's properties or apply show rules on\ntable cells, you can use the [`table.cell`](https://typst.app/docs/reference/model/table/#definitions-cell) element. See its\ndocumentation for more information.\n\nAlthough the `table` and the `grid` share most properties, set and show\nrules on one of them do not affect the other.\n\nTo give a table a caption and make it [referenceable](https://typst.app/docs/reference/model/ref/), put it into a\n[figure].\n\n# Example\n\nThe example below demonstrates some of the most common table options.\n```typ\n#table(\n columns: (1fr, auto, auto),\n inset: 10pt,\n align: horizon,\n table.header(\n [], [*Volume*], [*Parameters*],\n ),\n image(\"cylinder.svg\"),\n $ pi h (D^2 - d^2) / 4 $,\n [\n $h$: height \\\n $D$: outer radius \\\n $d$: inner radius\n ],\n image(\"tetrahedron.svg\"),\n $ sqrt(2) / 12 a^3 $,\n [$a$: edge length]\n)\n```\n\nMuch like with grids, you can use [`table.cell`](https://typst.app/docs/reference/model/table/#definitions-cell) to customize\nthe appearance and the position of each cell.\n\n```typ\n>>> #set page(width: auto)\n>>> #set text(font: \"IBM Plex Sans\")\n>>> #let gray = rgb(\"#565565\")\n>>>\n#set table(\n stroke: none,\n gutter: 0.2em,\n fill: (x, y) =>\n if x == 0 or y == 0 { gray },\n inset: (right: 1.5em),\n)\n\n#show table.cell: it => {\n if it.x == 0 or it.y == 0 {\n set text(white)\n strong(it)\n } else if it.body == [] {\n // Replace empty cells with 'N/A'\n pad(..it.inset)[_N/A_]\n } else {\n it\n }\n}\n\n#let a = table.cell(\n fill: green.lighten(60%),\n)[A]\n#let b = table.cell(\n fill: aqua.lighten(60%),\n)[B]\n\n#table(\n columns: 4,\n [], [Exam 1], [Exam 2], [Exam 3],\n\n [John], [], a, [],\n [Mary], [], a, a,\n [Robert], b, a, b,\n)\n```\n\n# Rest Parameters\n\n## children\n\n```typc\ntype: content\n```\n\nThe contents of the table cells, plus any extra table lines specified\nwith the [`table.hline`](https://typst.app/docs/reference/model/table/#definitions-hline) and\n[`table.vline`](https://typst.app/docs/reference/model/table/#definitions-vline) elements.\n\n# Named Parameters\n\n## align\n\n```typc\ntype: alignment | array | auto | function\n```\n\nHow to align the cells' content.\n\nThis can either be a single alignment, an array of alignments\n(corresponding to each column) or a function that returns an alignment.\nThe function receives the cells' column and row indices, starting from\nzero. If set to `auto`, the outer alignment is used.\n\n```typ\n#table(\n columns: 3,\n align: (left, center, right),\n [Hello], [Hello], [Hello],\n [A], [B], [C],\n)\n```\n\n## column-gutter (named)\n\n```typc\ntype: array | auto | length | type\n```\n\nThe gaps between columns. Takes precedence over `gutter`. See the\n[grid documentation](https://typst.app/docs/reference/layout/grid/) for more information on gutters.\n\n## columns (named)\n\n```typc\ntype: array | auto | length | type\n```\n\nThe column sizes. See the [grid documentation](https://typst.app/docs/reference/layout/grid/) for more\ninformation on track sizing.\n\n## fill (named)\n\n```typc\ntype: color\n```\n\nHow to fill the cells.\n\nThis can be a color or a function that returns a color. The function\nreceives the cells' column and row indices, starting from zero. This can\nbe used to implement striped tables.\n\n```typ\n#table(\n fill: (x, _) =>\n if calc.odd(x) { luma(240) }\n else { white },\n align: (x, y) =>\n if y == 0 { center }\n else if x == 0 { left }\n else { right },\n columns: 4,\n [], [*Q1*], [*Q2*], [*Q3*],\n [Revenue:], [1000 €], [2000 €], [3000 €],\n [Expenses:], [500 €], [1000 €], [1500 €],\n [Profit:], [500 €], [1000 €], [1500 €],\n)\n```\n\n## gutter (named)\n\n```typc\ntype: array | auto | length | type\n```\n\nThe gaps between rows and columns. This is a shorthand for setting\n`column-gutter` and `row-gutter` to the same value. See the [grid\ndocumentation](https://typst.app/docs/reference/layout/grid/) for more information on gutters.\n\n## inset (named)\n\n```typc\ntype: inset\n```\n\nHow much to pad the cells' content.\n\n```typ\n#table(\n inset: 10pt,\n [Hello],\n [World],\n)\n\n#table(\n columns: 2,\n inset: (\n x: 20pt,\n y: 10pt,\n ),\n [Hello],\n [World],\n)\n```\n\n## row-gutter (named)\n\n```typc\ntype: array | auto | length | type\n```\n\nThe gaps between rows. Takes precedence over `gutter`. See the\n[grid documentation](https://typst.app/docs/reference/layout/grid/) for more information on gutters.\n\n## rows (named)\n\n```typc\ntype: array | auto | length | type\n```\n\nThe row sizes. See the [grid documentation](https://typst.app/docs/reference/layout/grid/) for more information\non track sizing.\n\n## stroke (named)\n\n```typc\ntype: stroke\n```\n\nHow to [stroke] the cells.\n\nStrokes can be disabled by setting this to `none`.\n\nIf it is necessary to place lines which can cross spacing between cells\nproduced by the `gutter` option, or to override the stroke between\nmultiple specific cells, consider specifying one or more of\n[`table.hline`](https://typst.app/docs/reference/model/table/#definitions-hline) and [`table.vline`](https://typst.app/docs/reference/model/table/#definitions-vline)\nalongside your table cells.\n\nSee the [grid documentation](https://typst.app/docs/reference/layout/grid/#parameters-stroke) for more information on\nstrokes.\n\n---\n[Open docs](https://typst.app/docs/reference/model/table/)", "range": "0:20:0:25" } diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_module.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_module.typ.snap index db882c994..00fd9caf3 100644 --- a/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_module.typ.snap +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_module.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/hover.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/hover/builtin_module.typ +snapshot_kind: text --- { "contents": "```typc\n\n```\n\n---\n```typc\nlet sys;\n```", diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_var.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_var.typ.snap index e422b5b21..af0e8d449 100644 --- a/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_var.typ.snap +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_var.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/hover.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/hover/builtin_var.typ +snapshot_kind: text --- { "contents": "```typc\nrgb(\"#ff4136\")\n```", diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_var2.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_var2.typ.snap index 13f9509ed..1ec009e9e 100644 --- a/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_var2.typ.snap +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_var2.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/hover.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/hover/builtin_var2.typ +snapshot_kind: text --- { "contents": "```typc\n\n```\n\n---\n```typc\nlet sys;\n```", diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_var3.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_var3.typ.snap index d070755db..44c83d964 100644 --- a/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_var3.typ.snap +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@builtin_var3.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/hover.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/hover/builtin_var3.typ +snapshot_kind: text --- { "contents": "```typc\n\n```\n\n---\n```typc\nlet sys;\n```", diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@module_alias.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@module_alias.typ.snap index 6638d77a2..189784105 100644 --- a/crates/tinymist-query/src/fixtures/hover/snaps/test@module_alias.typ.snap +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@module_alias.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/hover.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/hover/module_alias.typ +snapshot_kind: text --- { "contents": "# The Module (Alias)", diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@module_path.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@module_path.typ.snap index 44ca5a9c6..602ff3137 100644 --- a/crates/tinymist-query/src/fixtures/hover/snaps/test@module_path.typ.snap +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@module_path.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/hover.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/hover/module_path.typ +snapshot_kind: text --- { "contents": "# Some Module", diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@module_var.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@module_var.typ.snap index 18eabfb3f..17037bbbc 100644 --- a/crates/tinymist-query/src/fixtures/hover/snaps/test@module_var.typ.snap +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@module_var.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/hover.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/hover/module_var.typ +snapshot_kind: text --- { "contents": "# The Module", diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@pagebreak.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@pagebreak.typ.snap index e7e47c3fe..e3e9d83b6 100644 --- a/crates/tinymist-query/src/fixtures/hover/snaps/test@pagebreak.typ.snap +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@pagebreak.typ.snap @@ -2,8 +2,9 @@ source: crates/tinymist-query/src/hover.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/hover/pagebreak.typ +snapshot_kind: text --- { - "contents": "```typc\nlet pagebreak(\n to: none | str = none,\n weak: bool = false,\n);\n```\n\n---\nA manual page break.\n\nMust not be used inside any containers.\n\n# Example\n```typ\nThe next page contains\nmore details on compound theory.\n#pagebreak()\n\n== Compound Theory\nIn 1984, the first ...\n```\n\n## Parameters\n\n@named `to` — If given, ensures that the next page will be an even/odd page, with an\nempty page in between if necessary.\n\n```typ\n#set page(height: 30pt)\n\nFirst.\n#pagebreak(to: \"odd\")\nThird.\n```\n\n@named `weak` — If `true`, the page break is skipped if the current page is already\nempty.\n\n---\n[Open docs](https://typst.app/docs/reference/layout/pagebreak/)", + "contents": "```typc\nlet pagebreak(\n to: none | str = none,\n weak: bool = false,\n);\n```\n\n---\nA manual page break.\n\nMust not be used inside any containers.\n\n# Example\n```typ\nThe next page contains\nmore details on compound theory.\n#pagebreak()\n\n== Compound Theory\nIn 1984, the first ...\n```\n\n# Named Parameters\n\n## to\n\n```typc\ntype: \"even\" | \"odd\" | none\n```\n\nIf given, ensures that the next page will be an even/odd page, with an\nempty page in between if necessary.\n\n```typ\n#set page(height: 30pt)\n\nFirst.\n#pagebreak(to: \"odd\")\nThird.\n```\n\n## weak (named)\n\n```typc\ntype: bool\n```\n\nIf `true`, the page break is skipped if the current page is already\nempty.\n\n---\n[Open docs](https://typst.app/docs/reference/layout/pagebreak/)", "range": "0:20:0:29" } diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@param.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@param.typ.snap index e8239dd74..ef954b2cb 100644 --- a/crates/tinymist-query/src/fixtures/hover/snaps/test@param.typ.snap +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@param.typ.snap @@ -2,8 +2,9 @@ source: crates/tinymist-query/src/hover.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/hover/param.typ +snapshot_kind: text --- { - "contents": "```typc\nlet param;\n```\n\n---\nThe `parameter`.", + "contents": "```typc\nlet param = any;\n```\n\n---\nThe `parameter`.", "range": "3:25:3:30" } diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@render_equation.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@render_equation.typ.snap new file mode 100644 index 000000000..0fbc6c203 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@render_equation.typ.snap @@ -0,0 +1,10 @@ +--- +source: crates/tinymist-query/src/hover.rs +expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" +input_file: crates/tinymist-query/src/fixtures/hover/render_equation.typ +snapshot_kind: text +--- +{ + "contents": "```typc\nlet lam(\n A: type,\n B: type,\n) = dictionary;\n```\n\n---\nLambda constructor.\n\n Typing Rule:\n\n

\"typst-block\"

\n\n# Positional Parameters\n\n## A\n\n```typc\ntype: type\n```\n\nThe type of the argument.\n - It can be also regarded as the condition of the proposition.\n\n## B (positional)\n\n```typc\ntype: type\n```\n\nThe type of the body.\n - It can be also regarded as the conclusion of the proposition.", + "range": "12:20:12:23" +} diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@render_equation_no_html.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@render_equation_no_html.typ.snap new file mode 100644 index 000000000..98a6eb888 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@render_equation_no_html.typ.snap @@ -0,0 +1,10 @@ +--- +source: crates/tinymist-query/src/hover.rs +expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" +input_file: crates/tinymist-query/src/fixtures/hover/render_equation_no_html.typ +snapshot_kind: text +--- +{ + "contents": "```typc\nlet lam(\n A: type,\n B: type,\n) = dictionary;\n```\n\n---\nLambda constructor.\n\n Typing Rule:\n\n ```typc\n$ (Γ , x : A ⊢ M : B #h(2em) Γ ⊢ a:B)/(Γ ⊢ λ (x : A) → M : Ï€ (x : A) → B) $\n```\n\n# Positional Parameters\n\n## A\n\n```typc\ntype: type\n```\n\nThe type of the argument.\n - It can be also regarded as the condition of the proposition.\n\n## B (positional)\n\n```typc\ntype: type\n```\n\nThe type of the body.\n - It can be also regarded as the conclusion of the proposition.", + "range": "14:20:14:23" +} diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@user.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@user.typ.snap index f817a5db0..66231c5a9 100644 --- a/crates/tinymist-query/src/fixtures/hover/snaps/test@user.typ.snap +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@user.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/hover.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/hover/user.typ +snapshot_kind: text --- { "contents": "```typc\nlet f() = int;\n```\n\n---\nTest", diff --git a/crates/tinymist-query/src/fixtures/hover/snaps/test@value_repr.typ.snap b/crates/tinymist-query/src/fixtures/hover/snaps/test@value_repr.typ.snap index df6314e7e..5ce2fe6ee 100644 --- a/crates/tinymist-query/src/fixtures/hover/snaps/test@value_repr.typ.snap +++ b/crates/tinymist-query/src/fixtures/hover/snaps/test@value_repr.typ.snap @@ -2,8 +2,9 @@ source: crates/tinymist-query/src/hover.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/hover/value_repr.typ +snapshot_kind: text --- { - "contents": "```typc\nlet reconstruct(\n it,\n ..new-body: arguments,\n body-name: str = \"body\",\n labeled: bool = true,\n max-depth: int = 9999,\n wrapper: () => box = Closure(..),\n) = none;\n```\n\n---\n## Parameters\n\n@positional `it`\n\n@named `body-name`\n\n@named `labeled`\n\n@named `max-depth`\n\n@named `wrapper`\n\n@rest `new-body`", - "range": "1:20:1:31" + "contents": "```typc\nlet f(\n x: any,\n y: any,\n z: any,\n w01: int = 1,\n w02: str = \"test\",\n w03: any = 1 + 2,\n w04: any = Label(test),\n w05: (content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box = (content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box,\n w06: any = (body-indent: length, indent: length, marker: array | content | function, spacing: auto | length, tight: bool, ..: content) => list.item,\n w07: content = Expr(..),\n w08: any = Expr(..),\n w09: any = 1 + 2,\n w10: array = (\n 1,\n 2,\n ),\n w11: array = (),\n w12: dictionary = (:),\n w13: dictionary = (a: 1),\n w14: dictionary = (a: (content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box),\n w15: dictionary = (a: (body-indent: length, indent: length, marker: array | content | function, spacing: auto | length, tight: bool, ..: content) => list.item),\n) = int;\n```\n\n---\n\n\n# Positional Parameters\n\n## x\n\n```typc\ntype: \n```\n\n\n\n## y (positional)\n\n```typc\ntype: \n```\n\n\n\n## z (positional)\n\n```typc\ntype: \n```\n\n\n\n# Named Parameters\n\n## w01\n\n```typc\ntype: 1\n```\n\n\n\n## w02 (named)\n\n```typc\ntype: \"test\"\n```\n\n\n\n## w03 (named)\n\n```typc\ntype: any\n```\n\n\n\n## w04 (named)\n\n```typc\ntype: \n```\n\n\n\n## w05 (named)\n\n```typc\ntype: (content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box\n```\n\n\n\n## w06 (named)\n\n```typc\ntype: any\n```\n\n\n\n## w07 (named)\n\n```typc\ntype: content\n```\n\n\n\n## w08 (named)\n\n```typc\ntype: any\n```\n\n\n\n## w09 (named)\n\n```typc\ntype: any\n```\n\n\n\n## w10 (named)\n\n```typc\ntype: array\n```\n\n\n\n## w11 (named)\n\n```typc\ntype: array\n```\n\n\n\n## w12 (named)\n\n```typc\ntype: dictionary\n```\n\n\n\n## w13 (named)\n\n```typc\ntype: dictionary\n```\n\n\n\n## w14 (named)\n\n```typc\ntype: dictionary\n```\n\n\n\n## w15 (named)\n\n```typc\ntype: dictionary\n```\n\n", + "range": "23:20:23:21" } diff --git a/crates/tinymist-query/src/fixtures/hover/value_repr.typ b/crates/tinymist-query/src/fixtures/hover/value_repr.typ index 417c95221..a5f246954 100644 --- a/crates/tinymist-query/src/fixtures/hover/value_repr.typ +++ b/crates/tinymist-query/src/fixtures/hover/value_repr.typ @@ -1,2 +1,24 @@ -#let reconstruct(body-name: "body", labeled: true, max-depth: 9999, wrapper: () => box(""), it, ..new-body) = { } -#(/* ident after */ reconstruct); +#let f( + x, + y, + z, + w01: 1, + w02: "test", + w03: 1 + 2, + w04: , + w05: box, + w06: list.item, + w07: [..], + w08: { + 1 + 2 + }, + w09: (1 + 2), + w10: (1, 2), + w11: (), + w12: (:), + w13: (a: 1), + w14: (a: box), + w15: (a: list.item), +) = 1 + +#(/* ident after */ f); diff --git a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@base.typ.snap b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@base.typ.snap index 73078538c..4947882e8 100644 --- a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@base.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/inlay_hint.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/inlay_hints/base.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@incomplete-expression.typ.snap b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@incomplete-expression.typ.snap index 0ef2638db..a0b9d51af 100644 --- a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@incomplete-expression.typ.snap +++ b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@incomplete-expression.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/inlay_hint.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/inlay_hints/incomplete-expression.typ +snapshot_kind: text --- [] diff --git a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@math_markup_mod.typ.snap b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@math_markup_mod.typ.snap index 5b4d32f02..73e92dc48 100644 --- a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@math_markup_mod.typ.snap +++ b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@math_markup_mod.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/inlay_hint.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/inlay_hints/math_markup_mod.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@math_mod.typ.snap b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@math_mod.typ.snap index c31096cc0..5e00b3a0f 100644 --- a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@math_mod.typ.snap +++ b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@math_mod.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/inlay_hint.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/inlay_hints/math_mod.typ +snapshot_kind: text --- [] diff --git a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@named.typ.snap b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@named.typ.snap index ad7148624..067aa35f5 100644 --- a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@named.typ.snap +++ b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@named.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/inlay_hint.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/inlay_hints/named.typ +snapshot_kind: text --- [] diff --git a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@named_or_pos.typ.snap b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@named_or_pos.typ.snap index 08868b6db..28bc0b0e7 100644 --- a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@named_or_pos.typ.snap +++ b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@named_or_pos.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/inlay_hint.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/inlay_hints/named_or_pos.typ +snapshot_kind: text --- [] diff --git a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@one_line_content.typ.snap b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@one_line_content.typ.snap index fa3b8a4e2..1f075862c 100644 --- a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@one_line_content.typ.snap +++ b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@one_line_content.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/inlay_hint.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/inlay_hints/one_line_content.typ +snapshot_kind: text --- [] diff --git a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@pos_rest.typ.snap b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@pos_rest.typ.snap index 88c7664c9..1dad66b99 100644 --- a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@pos_rest.typ.snap +++ b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@pos_rest.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/inlay_hint.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/inlay_hints/pos_rest.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@table.typ.snap b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@table.typ.snap index 3d014aaa9..ca4189884 100644 --- a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@table.typ.snap +++ b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@table.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/inlay_hint.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/inlay_hints/table.typ +snapshot_kind: text --- [] diff --git a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@unique_positional.typ.snap b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@unique_positional.typ.snap index 6fb56aad0..8a62979e7 100644 --- a/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@unique_positional.typ.snap +++ b/crates/tinymist-query/src/fixtures/inlay_hints/snaps/smart@unique_positional.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/inlay_hint.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/inlay_hints/unique_positional.typ +snapshot_kind: text --- [] diff --git a/crates/tinymist-query/src/fixtures/match_def/snaps/test@base.typ.snap b/crates/tinymist-query/src/fixtures/match_def/snaps/test@base.typ.snap index 536b9f411..afe24184c 100644 --- a/crates/tinymist-query/src/fixtures/match_def/snaps/test@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/match_def/snaps/test@base.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/match_def/base.typ +snapshot_kind: text --- 1..31 diff --git a/crates/tinymist-query/src/fixtures/match_def/snaps/test@ident_in_init.typ.snap b/crates/tinymist-query/src/fixtures/match_def/snaps/test@ident_in_init.typ.snap index b4bbebcad..855c176bd 100644 --- a/crates/tinymist-query/src/fixtures/match_def/snaps/test@ident_in_init.typ.snap +++ b/crates/tinymist-query/src/fixtures/match_def/snaps/test@ident_in_init.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/match_def/ident_in_init.typ +snapshot_kind: text --- diff --git a/crates/tinymist-query/src/fixtures/match_def/snaps/test@ident_in_init2.typ.snap b/crates/tinymist-query/src/fixtures/match_def/snaps/test@ident_in_init2.typ.snap index 19488be26..a702079e1 100644 --- a/crates/tinymist-query/src/fixtures/match_def/snaps/test@ident_in_init2.typ.snap +++ b/crates/tinymist-query/src/fixtures/match_def/snaps/test@ident_in_init2.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/match_def/ident_in_init2.typ +snapshot_kind: text --- diff --git a/crates/tinymist-query/src/fixtures/match_def/snaps/test@param.typ.snap b/crates/tinymist-query/src/fixtures/match_def/snaps/test@param.typ.snap index 558d1fc68..8e757fbb4 100644 --- a/crates/tinymist-query/src/fixtures/match_def/snaps/test@param.typ.snap +++ b/crates/tinymist-query/src/fixtures/match_def/snaps/test@param.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/match_def/param.typ +snapshot_kind: text --- diff --git a/crates/tinymist-query/src/fixtures/match_def/snaps/test@param_in_init.typ.snap b/crates/tinymist-query/src/fixtures/match_def/snaps/test@param_in_init.typ.snap index a6a008d55..61711d0b0 100644 --- a/crates/tinymist-query/src/fixtures/match_def/snaps/test@param_in_init.typ.snap +++ b/crates/tinymist-query/src/fixtures/match_def/snaps/test@param_in_init.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/match_def/param_in_init.typ +snapshot_kind: text --- diff --git a/crates/tinymist-query/src/fixtures/match_def/snaps/test@param_in_init2.typ.snap b/crates/tinymist-query/src/fixtures/match_def/snaps/test@param_in_init2.typ.snap index 83de83f14..e8cd8e1da 100644 --- a/crates/tinymist-query/src/fixtures/match_def/snaps/test@param_in_init2.typ.snap +++ b/crates/tinymist-query/src/fixtures/match_def/snaps/test@param_in_init2.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/match_def/param_in_init2.typ +snapshot_kind: text --- diff --git a/crates/tinymist-query/src/fixtures/modules/snaps/test@base.typ.snap b/crates/tinymist-query/src/fixtures/modules/snaps/test@base.typ.snap index d5ff71400..78209dcd5 100644 --- a/crates/tinymist-query/src/fixtures/modules/snaps/test@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/modules/snaps/test@base.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "JsonRepr::new_pure(dependencies)" input_file: crates/tinymist-query/src/fixtures/modules/base.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/modules/snaps/test@may_import.typ.snap b/crates/tinymist-query/src/fixtures/modules/snaps/test@may_import.typ.snap index ae13018c8..b899b22ea 100644 --- a/crates/tinymist-query/src/fixtures/modules/snaps/test@may_import.typ.snap +++ b/crates/tinymist-query/src/fixtures/modules/snaps/test@may_import.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: "JsonRepr::new_pure(dependencies)" input_file: crates/tinymist-query/src/fixtures/modules/may_import.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-core-slides.typ-2.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-core-slides.typ-2.snap new file mode 100644 index 000000000..19d21f418 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-core-slides.typ-2.snap @@ -0,0 +1,35 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: Completion on / (61..62) +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-core-slides.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [ + { + "kind": 3, + "label": "config-xxx", + "labelDetails": { + "description": "() => any" + }, + "sortText": "032", + "textEdit": { + "newText": "config-xxx()${1:}", + "range": { + "end": { + "character": 15, + "line": 2 + }, + "start": { + "character": 15, + "line": 2 + } + } + } + } + ] + } +] diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-core-slides.typ.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-core-slides.typ.snap new file mode 100644 index 000000000..17979a101 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-core-slides.typ.snap @@ -0,0 +1,77 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: Completion on / (57..58) +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-core-slides.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [ + { + "kind": 5, + "label": "config", + "labelDetails": { + "description": "dictionary" + }, + "sortText": "003", + "textEdit": { + "newText": "config: ${1:}", + "range": { + "end": { + "character": 7, + "line": 2 + }, + "start": { + "character": 7, + "line": 2 + } + } + } + }, + { + "kind": 5, + "label": "repeat", + "labelDetails": { + "description": "auto" + }, + "sortText": "004", + "textEdit": { + "newText": "repeat: ${1:}", + "range": { + "end": { + "character": 7, + "line": 2 + }, + "start": { + "character": 7, + "line": 2 + } + } + } + }, + { + "kind": 3, + "label": "repeat", + "labelDetails": { + "description": "(content, gap: length, justify: bool) => repeat" + }, + "sortText": "159", + "textEdit": { + "newText": "repeat(${1:})", + "range": { + "end": { + "character": 7, + "line": 2 + }, + "start": { + "character": 7, + "line": 2 + } + } + } + } + ] + } +] diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ-2.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ-2.snap index 7c6cf7b59..f4241b83a 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ-2.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ-2.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (65..66) +description: Completion on / (66..67) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-_size-to-pt.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-_size-to-pt.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ-3.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ-3.snap index bdf3cc2d1..aa52a319f 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ-3.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ-3.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (76..77) +description: Completion on / (77..78) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-_size-to-pt.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-_size-to-pt.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ-4.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ-4.snap index 2db95b79b..b69d15d12 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ-4.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ-4.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (70..71) +description: Completion on / (71..72) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-_size-to-pt.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-_size-to-pt.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ.snap index 2db95b79b..054e8dd80 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-_size-to-pt.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (70..71) +description: Completion on / (78..79) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-_size-to-pt.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-_size-to-pt.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-cover-with-rect.typ.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-cover-with-rect.typ.snap new file mode 100644 index 000000000..2e30942ac --- /dev/null +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-cover-with-rect.typ.snap @@ -0,0 +1,56 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: Completion on / (71..72) +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-cover-with-rect.typ +snapshot_kind: text +--- +[ + { + "isIncomplete": false, + "items": [ + { + "kind": 5, + "label": "fill", + "labelDetails": { + "description": "auto | color | int | ratio | type" + }, + "sortText": "001", + "textEdit": { + "newText": "fill: ${1:}", + "range": { + "end": { + "character": 17, + "line": 2 + }, + "start": { + "character": 17, + "line": 2 + } + } + } + }, + { + "kind": 3, + "label": "stroke", + "labelDetails": { + "description": "type" + }, + "sortText": "186", + "textEdit": { + "newText": "stroke(${1:})", + "range": { + "end": { + "character": 17, + "line": 2 + }, + "start": { + "character": 17, + "line": 2 + } + } + } + } + ] + } +] diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ-2.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ-2.snap index c95187693..1f3f81bf3 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ-2.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ-2.snap @@ -3,6 +3,7 @@ source: crates/tinymist-query/src/completion.rs description: Completion on / (63..64) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-current-heading.typ +snapshot_kind: text --- [ { @@ -27,14 +28,14 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-current-headin } }, { - "kind": 7, + "kind": 3, "label": "int", "labelDetails": { "description": "type" }, - "sortText": "125", + "sortText": "089", "textEdit": { - "newText": "int", + "newText": "int(${1:})", "range": { "end": { "character": 24, diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ-3.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ-3.snap index 79961ee01..cc5c8aca0 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ-3.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ-3.snap @@ -1,15 +1,16 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (76..77) +description: Completion on / (77..78) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-current-heading.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-current-heading.typ +snapshot_kind: text --- [ { "isIncomplete": false, "items": [ { - "kind": 21, + "kind": 6, "label": "true", "sortText": "000", "textEdit": { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ-4.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ-4.snap index 8ea3fdea9..918bc3813 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ-4.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ-4.snap @@ -1,15 +1,16 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (66..67) +description: Completion on / (67..68) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-current-heading.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-current-heading.typ +snapshot_kind: text --- [ { "isIncomplete": false, "items": [ { - "kind": 21, + "kind": 6, "label": "9999", "sortText": "000", "textEdit": { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ.snap index 1eb6319fd..806fe868f 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-current-heading.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (77..78) +description: Completion on / (78..79) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-current-heading.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-current-heading.typ +snapshot_kind: text --- [ { @@ -11,6 +12,9 @@ input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-cur { "kind": 5, "label": "depth", + "labelDetails": { + "description": "9999" + }, "sortText": "000", "textEdit": { "newText": "depth: ${1:}", @@ -29,6 +33,9 @@ input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-cur { "kind": 5, "label": "hierachical", + "labelDetails": { + "description": "true" + }, "sortText": "001", "textEdit": { "newText": "hierachical: ${1:}", @@ -47,6 +54,9 @@ input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-cur { "kind": 5, "label": "level", + "labelDetails": { + "description": "auto | int" + }, "sortText": "002", "textEdit": { "newText": "level: ${1:}", diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-fit-to-height.typ-2.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-fit-to-height.typ-2.snap index 5bd3454cb..2bff0b1e2 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-fit-to-height.typ-2.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-fit-to-height.typ-2.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (67..68) +description: Completion on / (68..69) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-fit-to-height.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-fit-to-height.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-fit-to-height.typ-3.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-fit-to-height.typ-3.snap index ff22f8dbb..6fa986672 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-fit-to-height.typ-3.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-fit-to-height.typ-3.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (59..60) +description: Completion on / (60..61) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-fit-to-height.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-fit-to-height.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-fit-to-height.typ.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-fit-to-height.typ.snap index ff22f8dbb..3942bb0ac 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-fit-to-height.typ.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-fit-to-height.typ.snap @@ -2,7 +2,8 @@ source: crates/tinymist-query/src/completion.rs description: Completion on / (59..60) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-fit-to-height.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-fit-to-height.typ +snapshot_kind: text --- [ { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-markup-text.typ-2.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-markup-text.typ-2.snap index e459e823c..d1518b791 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-markup-text.typ-2.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-markup-text.typ-2.snap @@ -3,13 +3,14 @@ source: crates/tinymist-query/src/completion.rs description: Completion on / (58..59) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-markup-text.typ +snapshot_kind: text --- [ { "isIncomplete": false, "items": [ { - "kind": 21, + "kind": 6, "label": "0", "sortText": "000", "textEdit": { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-markup-text.typ.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-markup-text.typ.snap index c5486a496..33cc1eb7c 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-markup-text.typ.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-markup-text.typ.snap @@ -1,12 +1,89 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (58..59) +description: Completion on / (71..72) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-markup-text.typ +snapshot_kind: text --- [ { "isIncomplete": false, - "items": [] + "items": [ + { + "kind": 6, + "label": "\"md\"", + "sortText": "000", + "textEdit": { + "newText": "\"md\"", + "range": { + "end": { + "character": 19, + "line": 2 + }, + "start": { + "character": 19, + "line": 2 + } + } + } + }, + { + "kind": 6, + "label": "\"typ\"", + "sortText": "001", + "textEdit": { + "newText": "\"typ\"", + "range": { + "end": { + "character": 19, + "line": 2 + }, + "start": { + "character": 19, + "line": 2 + } + } + } + }, + { + "kind": 15, + "label": "str", + "sortText": "002", + "textEdit": { + "newText": "${1:string}", + "range": { + "end": { + "character": 19, + "line": 2 + }, + "start": { + "character": 19, + "line": 2 + } + } + } + }, + { + "kind": 3, + "label": "str", + "labelDetails": { + "description": "type" + }, + "sortText": "180", + "textEdit": { + "newText": "str(${1:})", + "range": { + "end": { + "character": 19, + "line": 2 + }, + "start": { + "character": 19, + "line": 2 + } + } + } + } + ] } ] diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ-2.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ-2.snap index 2d0888d8f..aa1d5a613 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ-2.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ-2.snap @@ -1,15 +1,16 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (65..66) +description: Completion on / (66..67) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-reconstruct.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-reconstruct.typ +snapshot_kind: text --- [ { "isIncomplete": false, "items": [ { - "kind": 21, + "kind": 6, "label": "\"body\"", "sortText": "000", "textEdit": { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ-3.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ-3.snap index 64ddc3eae..a70cffd18 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ-3.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ-3.snap @@ -1,15 +1,16 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (68..69) +description: Completion on / (69..70) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-reconstruct.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-reconstruct.typ +snapshot_kind: text --- [ { "isIncomplete": false, "items": [ { - "kind": 21, + "kind": 6, "label": "true", "sortText": "000", "textEdit": { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ-4.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ-4.snap index 2522b66f5..42a5a3eea 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ-4.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ-4.snap @@ -1,15 +1,16 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (66..67) +description: Completion on / (67..68) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-reconstruct.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-reconstruct.typ +snapshot_kind: text --- [ { "isIncomplete": false, "items": [ { - "kind": 21, + "kind": 6, "label": "false", "sortText": "000", "textEdit": { diff --git a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ.snap b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ.snap index fca69725e..eb847c828 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ.snap +++ b/crates/tinymist-query/src/fixtures/pkgs/snaps/test@touying-utils-reconstruct.typ.snap @@ -1,8 +1,9 @@ --- source: crates/tinymist-query/src/completion.rs -description: Completion on / (87..88) +description: Completion on / (88..89) expression: "JsonRepr::new_pure(results)" -input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-reconstruct.typ +input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-reconstruct.typ +snapshot_kind: text --- [ { @@ -11,6 +12,9 @@ input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-rec { "kind": 5, "label": "body-name", + "labelDetails": { + "description": "\"body\"" + }, "sortText": "000", "textEdit": { "newText": "body-name: ${1:}", @@ -29,6 +33,9 @@ input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-rec { "kind": 5, "label": "labeled", + "labelDetails": { + "description": "true" + }, "sortText": "001", "textEdit": { "newText": "labeled: ${1:}", @@ -47,6 +54,9 @@ input_file: crates/tinymist-query/src/fixtures/completion-pkgs/touying-utils-rec { "kind": 5, "label": "named", + "labelDetails": { + "description": "false" + }, "sortText": "002", "textEdit": { "newText": "named: ${1:}", diff --git a/crates/tinymist-query/src/fixtures/pkgs/touying-core-slides.typ b/crates/tinymist-query/src/fixtures/pkgs/touying-core-slides.typ new file mode 100644 index 000000000..bbc28a06e --- /dev/null +++ b/crates/tinymist-query/src/fixtures/pkgs/touying-core-slides.typ @@ -0,0 +1,49 @@ +/// path: lib.typ +/// Touying slide function. +/// +/// #let composer = `int or array(length) or function` +/// #let bodies = `array(content)` +/// +/// - config (dict, tag(config)): The configuration of the slide. You can use `config-xxx` to set the configuration of the slide. For more configurations, you can use `utils.merge-dicts` to merge them. +/// +/// - repeat (auto): The number of subslides. Default is `auto`, which means touying will automatically calculate the number of subslides. +/// +/// The `repeat` argument is necessary when you use `#slide(repeat: 3, self => [ .. ])` style code to create a slide. The callback-style `uncover` and `only` cannot be detected by touying automatically. +/// +/// - setting (function): The setting of the slide. You can use it to add some set/show rules for the slide. +/// +/// - composer (function, array, int, composer): The composer of the slide. You can use it to set the layout of the slide. +/// +/// For example, `#slide(composer: (1fr, 2fr, 1fr))[A][B][C]` to split the slide into three parts. The first and last parts will take 1/4 of the slide, and the second part will take 1/2 of the slide. +/// +/// If you pass a non-function value like `(1fr, 2fr, 1fr)`, it will be assumed to be the first argument of the `components.side-by-side` function. +/// +/// The `components.side-by-side` function is a simple wrapper of the `grid` function. It means you can use the `grid.cell(colspan: 2, ..)` to make the cell take 2 columns. +/// +/// For example, `#slide(composer: 2)[A][B][#grid.cell(colspan: 2)[Footer]]` will make the `Footer` cell take 2 columns. +/// +/// If you want to customize the composer, you can pass a function to the `composer` argument. The function should receive the contents of the slide and return the content of the slide, like `#slide(composer: grid.with(columns: 2))[A][B]`. +/// +/// - bodies (array, bodies): The contents of the slide. You can call the `slide` function with syntax like `#slide[A][B][C]` to create a slide. +#let slide( + config: (:), + repeat: auto, + setting: body => body, + composer: auto, + ..bodies, +) = touying-slide-wrapper(self => { + touying-slide(self: self, config: config, repeat: repeat, setting: setting, composer: composer, ..bodies) +}) + +/// -> tag(config) +#let config-xxx() = { } + +----- +/// contains: config, repeat +#import "lib.typ": * +#slide(/* range 0..1 */)[]; + +----- +/// contains: config-xxx +#import "lib.typ": * +#slide(config: /* range 0..1 */)[]; diff --git a/crates/tinymist-query/src/fixtures/pkgs/touying-utils-cover-with-rect.typ b/crates/tinymist-query/src/fixtures/pkgs/touying-utils-cover-with-rect.typ new file mode 100644 index 000000000..e2b73c6f6 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/pkgs/touying-utils-cover-with-rect.typ @@ -0,0 +1,62 @@ +/// path: lib.typ + + +/// Cover content with a rectangle of a specified color. If you set the fill to the background color of the page, you can use this to create a semi-transparent overlay. +/// +/// Example: `#utils.cover-with-rect(fill: "red")[Hidden]` +/// +/// - cover-args (args): The arguments to pass to the rectangle. +/// +/// - fill (color): The color to fill the rectangle with. +/// +/// - inline (boolean): Indicates whether the content should be displayed inline. Default is `true`. +/// +/// - body (content): The content to cover. +#let cover-with-rect(..cover-args, fill: auto, inline: true, body) = { + if fill == auto { + panic("`auto` fill value is not supported until typst provides utilities to" + " retrieve the current page background") + } + if type(fill) == str { + fill = rgb(fill) + } + + let to-display = layout(layout-size => { + context { + let body-size = measure(body) + let bounding-width = calc.min(body-size.width, layout-size.width) + let wrapped-body-size = measure(box(body, width: bounding-width)) + let named = cover-args.named() + if "width" not in named { + named.insert("width", wrapped-body-size.width) + } + if "height" not in named { + named.insert("height", wrapped-body-size.height) + } + if "outset" not in named { + // This outset covers the tops of tall letters and the bottoms of letters with + // descenders. Alternatively, we could use + // `set text(top-edge: "bounds", bottom-edge: "bounds")` to get the same effect, + // but this changes text alignment and also misaligns bullets in enums/lists. + // In contrast, `outset` preserves spacing and alignment at the cost of adding + // a slight, visible border when the covered object is right next to the edge + // of a color change. + named.insert("outset", (top: 0.15em, bottom: 0.25em)) + } + stack( + spacing: -wrapped-body-size.height, + body, + rect(fill: fill, ..named, ..cover-args.pos()), + ) + } + }) + if inline { + box(to-display) + } else { + to-display + } +} + +----- +/// contains: body, fill, stroke +#import "lib.typ": * +#cover-with-rect(/* range 0..1 */)[]; diff --git a/crates/tinymist-query/src/fixtures/pkgs/touying-utils-markup-text.typ b/crates/tinymist-query/src/fixtures/pkgs/touying-utils-markup-text.typ index f53c2735f..92df051e4 100644 --- a/crates/tinymist-query/src/fixtures/pkgs/touying-utils-markup-text.typ +++ b/crates/tinymist-query/src/fixtures/pkgs/touying-utils-markup-text.typ @@ -2,10 +2,12 @@ /// Convert content to markup text, partly from /// [typst-examples-book](https://sitandr.github.io/typst-examples-book/book/typstonomicon/extract_markup_text.html). +/// +/// #let mode = `"typ" or "md"` /// -/// - it (content): The content to convert. +/// - it (content, str): The content to convert. /// -/// - mode (string): The mode of the markup text, either `typ` or `md`. +/// - mode (str, mode): The mode of the markup text, either `typ` or `md`. /// /// - indent (int): The number of spaces to indent. Default is `0`. #let markup-text(it, mode: "typ", indent: 0) = { @@ -85,7 +87,7 @@ } } ----- -/// contains: typ +/// contains: str, "typ", "md" #import "lib.typ": * #markup-text(mode: /* range 0..1 */)[]; ----- diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font.typ.snap index acc4857fe..12ee3442a 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"\\\"Test\\\"\" (30)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_font.typ +snapshot_kind: text --- ( ⪰ "Test" ⪯ (TextFont | Array)) diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font2.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font2.typ.snap index 9449a7757..099be546f 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font2.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font2.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (30)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_font2.typ +snapshot_kind: text --- -( ⪯ Array) +TextFont diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font3.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font3.typ.snap index a14d75c2d..860ee5308 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font3.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font3.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (33)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_font3.typ +snapshot_kind: text --- -( ⪯ Array) +TextFont diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font4.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font4.typ.snap index ea8a3a26c..eb7536771 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font4.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font4.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (31)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_font4.typ +snapshot_kind: text --- -( ⪯ Array) +TextFont diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font5.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font5.typ.snap index 48a044f5c..040d840c0 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font5.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font5.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (47)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_font5.typ +snapshot_kind: text --- -( ⪯ Array) +TextFont diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element.typ.snap index e1bd32c3d..4fa3bb6da 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"\\\"Test\\\"\" (34)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_font_element.typ +snapshot_kind: text --- -( ⪰ ( ⪯ (TextFont | Array)) ⪯ Array) +( ⪰ TextFont | (TextFont | Array)) diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element2.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element2.typ.snap index ed7639523..8fb22501c 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element2.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element2.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"\\\"Test\\\"\" (31)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_font_element2.typ +snapshot_kind: text --- -( ⪰ ( ⪰ "Test" ⪯ (TextFont | Array)) ⪯ Array) +( ⪰ ( ⪰ "Test" ⪯ (TextFont | Array)) ⪯ TextFont) diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element3.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element3.typ.snap index c0056c07b..6a344e493 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element3.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element3.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"\\\"Test\\\"\" (34)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_font_element3.typ +snapshot_kind: text --- -( ⪯ Array) +TextFont diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element4.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element4.typ.snap index ede940083..0bc9ddf8e 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element4.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_font_element4.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"\\\"Test\\\"\" (31)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_font_element4.typ +snapshot_kind: text --- -( ⪯ Array) +TextFont diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke.typ.snap index ebcf47a0f..f61da882a 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \")\" (82)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_stroke.typ +snapshot_kind: text --- -( ⪯ "cap": Any & "dash": Any & "join": Any & "miter-limit": Any & "paint": Any & "thickness": Any) +( ⪰ "cap": Any | "dash": Any | "join": Any | "miter-limit": Any | "paint": Any | "thickness": Any) diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke1.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke1.typ.snap index cc8160dc5..c965a0574 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke1.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke1.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (61)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_stroke1.typ +snapshot_kind: text --- -( ⪯ "cap": Any & "dash": Any & "join": Any & "miter-limit": Any & "paint": Any & "thickness": Any) +( ⪰ "cap": Any | "dash": Any | "join": Any | "miter-limit": Any | "paint": Any | "thickness": Any) diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke2.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke2.typ.snap index a8a6aed29..cd01ba93e 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke2.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke2.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \")\" (69)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_stroke2.typ +snapshot_kind: text --- -( ⪯ ( ⪯ Stroke)) +"stroke": Stroke diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke3.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke3.typ.snap index d7880ebe6..a5889d865 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke3.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke3.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (49)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_stroke3.typ +snapshot_kind: text --- -( ⪯ "cap": Any & "dash": Any & "join": Any & "miter-limit": Any & "paint": Any & "thickness": Any) +( ⪰ "cap": Any | "dash": Any | "join": Any | "miter-limit": Any | "paint": Any | "thickness": Any) diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke4.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke4.typ.snap index 3145fafe8..369479a55 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke4.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@text_stroke4.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (48)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/text_stroke4.typ +snapshot_kind: text --- -( ⪯ ( ⪯ Stroke)) +"stroke": Stroke diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_external.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_external.typ.snap index b7ba45c7d..58edb5519 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_external.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_external.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (56)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/user_external.typ +snapshot_kind: text --- -( ⪯ Array) +TextFont diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_external_alias.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_external_alias.typ.snap index 10f3f6e23..2ab976ba8 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_external_alias.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_external_alias.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (59)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/user_external_alias.typ +snapshot_kind: text --- -( ⪯ Array) +TextFont diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_external_ever.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_external_ever.typ.snap index 9e94ef653..964e1f5a6 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_external_ever.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_external_ever.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \":\" (34)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/user_external_ever.typ +snapshot_kind: text --- -( ⪯ ( ⪰ "article" | "article" | "letter" | "article" | "letter")) +( ⪰ "article" | "letter") diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_func.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_func.typ.snap index 6cd54aa21..1f417aa27 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_func.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_func.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (105)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/user_func.typ +snapshot_kind: text --- -( ⪯ Array) +TextFont diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_func_pos.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_func_pos.typ.snap index faa1adc44..603568ef3 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_func_pos.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_func_pos.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \",\" (83)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/user_func_pos.typ +snapshot_kind: text --- -( ⪯ ( ⪯ Stroke)) +"stroke": Stroke diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_func_pos2.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_func_pos2.typ.snap index ab86aeafc..ed4d89f8c 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_func_pos2.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_func_pos2.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (85)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/user_func_pos2.typ +snapshot_kind: text --- -( ⪯ "cap": Any & "dash": Any & "join": Any & "miter-limit": Any & "paint": Any & "thickness": Any) +( ⪰ "cap": Any | "dash": Any | "join": Any | "miter-limit": Any | "paint": Any | "thickness": Any) diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_named.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_named.typ.snap index be1b50d5e..25eeb8483 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_named.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@user_named.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \")\" (98)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/user_named.typ +snapshot_kind: text --- -( ⪯ None & "font": Any) +( ⪰ "content": None | "font": ( ⪰ None ⪯ (TextFont | Array))) diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@with_builtin.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@with_builtin.typ.snap index 0a26cafb5..c3abed564 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@with_builtin.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@with_builtin.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (17)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/with_builtin.typ +snapshot_kind: text --- -( ⪯ (Type(int) | Type(ratio))) +"red": (Type(int) | Type(ratio)) diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@with_element.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@with_element.typ.snap index 1fd6af090..38dd8872f 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@with_element.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@with_element.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (18)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/with_element.typ +snapshot_kind: text --- -( ⪯ Type(content) & "alternates": Any & "baseline": Any & "bottom-edge": Any & "cjk-latin-spacing": Any & "costs": Any & "dir": Any & "discretionary-ligatures": Any & "fallback": Any & "features": Any & "fill": Any & "font": Any & "fractions": Any & "historical-ligatures": Any & "hyphenate": Any & "kerning": Any & "lang": Any & "ligatures": Any & "number-type": Any & "number-width": Any & "overhang": Any & "region": Any & "script": Any & "size": Any & "slashed-zero": Any & "spacing": Any & "stretch": Any & "stroke": Any & "style": Any & "stylistic-set": Any & "top-edge": Any & "tracking": Any & "weight": Any) +( ⪰ "alternates": Type(bool) | "baseline": Type(length) | "body": Type(content) | "bottom-edge": (Type(length) | "baseline" | "bounds" | "descender") | "cjk-latin-spacing": (Type(auto) | Type(none)) | "costs": Type(dictionary) | "dir": Dir | "discretionary-ligatures": Type(bool) | "fallback": Type(bool) | "features": (Type(array) | Type(dictionary)) | "fill": Color | "font": (TextFont | Array) | "fractions": Type(bool) | "historical-ligatures": Type(bool) | "hyphenate": (Type(auto) | Type(bool)) | "kerning": Type(bool) | "lang": TextLang | "ligatures": Type(bool) | "number-type": (Type(auto) | "lining" | "old-style") | "number-width": (Type(auto) | "proportional" | "tabular") | "overhang": Type(bool) | "region": TextRegion | "script": (Type(auto) | Type(str)) | "size": TextSize | "slashed-zero": Type(bool) | "spacing": Type(relative) | "stretch": Type(ratio) | "stroke": Stroke | "style": ("italic" | "normal" | "oblique") | "stylistic-set": (Type(array) | Type(int) | Type(none)) | "top-edge": (Type(length) | "ascender" | "baseline" | "bounds" | "cap-height" | "x-height") | "tracking": Type(length) | "weight": (Type(int) | "black" | "bold" | "extrabold" | "extralight" | "light" | "medium" | "regular" | "semibold" | "thin")) diff --git a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@with_user_func.typ.snap b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@with_user_func.typ.snap index 157ea12e0..f1185f37b 100644 --- a/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@with_user_func.typ.snap +++ b/crates/tinymist-query/src/fixtures/post_type_check/snaps/test@with_user_func.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"(\" (72)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/post_type_check/with_user_func.typ +snapshot_kind: text --- -( ⪯ ( ⪯ (TextFont | Array))) +"font": (TextFont | Array) diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@at_def.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@at_def.typ.snap index 080aecfc3..c450c48dc 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@at_def.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@at_def.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/at_def.typ +snapshot_kind: text --- [ "/s0.typ@0:23:0:24", diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@base.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@base.typ.snap index a1254d9ee..5d2af28d2 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@base.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/base.typ +snapshot_kind: text --- [ "/s0.typ@0:5:0:6", diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_file_ref_label.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_file_ref_label.typ.snap index ef1ac67e9..234655e13 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_file_ref_label.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_file_ref_label.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/cross_file_ref_label.typ +snapshot_kind: text --- [ "/base1.typ@1:10:1:13", diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module.typ.snap index 2f80f1c8a..d6c34cec1 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/cross_module.typ +snapshot_kind: text --- [ "/base.typ@0:23:0:24", diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module2.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module2.typ.snap index 46dcd28b2..901dc4e85 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module2.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module2.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/cross_module2.typ +snapshot_kind: text --- [ "/base.typ@0:23:0:24", diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_absolute.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_absolute.typ.snap index 781d90891..77b2ffc03 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_absolute.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_absolute.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/cross_module_absolute.typ +snapshot_kind: text --- [ "/out/base.typ@0:23:0:24", diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_alias.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_alias.typ.snap index 9e03b96c8..45142fcd1 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_alias.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_alias.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/cross_module_alias.typ +snapshot_kind: text --- [ "/base.typ@0:5:0:6", diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_alias2.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_alias2.typ.snap index 87bc8741e..00dc7d52e 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_alias2.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_alias2.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/cross_module_alias2.typ +snapshot_kind: text --- [ "/base.typ@0:23:0:24", diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_relative.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_relative.typ.snap index 240788115..6cdb66507 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_relative.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@cross_module_relative.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/cross_module_relative.typ +snapshot_kind: text --- [ "/out/base.typ@0:23:0:24", diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@label.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@label.typ.snap index 25c5be57c..9ecb0f9d2 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@label.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@label.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/label.typ +snapshot_kind: text --- [ "/s0.typ@5:0:5:12" diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@recursive_import.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@recursive_import.typ.snap index 63d2d7bff..1a2712890 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@recursive_import.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@recursive_import.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/recursive_import.typ +snapshot_kind: text --- [ "/base.typ@0:23:0:24", diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@recursive_import_star.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@recursive_import_star.typ.snap index 2ba4c49c1..e142f050a 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@recursive_import_star.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@recursive_import_star.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/recursive_import_star.typ +snapshot_kind: text --- [ "/base.typ@0:23:0:24", diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@redefine.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@redefine.typ.snap index 661c45928..7b57143ac 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@redefine.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@redefine.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/redefine.typ +snapshot_kind: text --- [ "/s0.typ@0:23:0:24", diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@ref_label.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@ref_label.typ.snap index fe900f1f1..10b96c2b6 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@ref_label.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@ref_label.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/ref_label.typ +snapshot_kind: text --- [ "/s0.typ@5:0:5:12", diff --git a/crates/tinymist-query/src/fixtures/references/snaps/test@rename_issue_exercise.typ.snap b/crates/tinymist-query/src/fixtures/references/snaps/test@rename_issue_exercise.typ.snap index 007c28e3c..4dc638fad 100644 --- a/crates/tinymist-query/src/fixtures/references/snaps/test@rename_issue_exercise.typ.snap +++ b/crates/tinymist-query/src/fixtures/references/snaps/test@rename_issue_exercise.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/references.rs expression: "JsonRepr::new_pure(result)" input_file: crates/tinymist-query/src/fixtures/references/rename_issue_exercise.typ +snapshot_kind: text --- [ "/basic/mod.typ@0:22:0:30", diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@builtin.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@builtin.typ.snap index b254d8145..f471aebc7 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@builtin.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@builtin.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/prepare_rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/builtin.typ +snapshot_kind: text --- null diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@cross-module.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@cross-module.typ.snap index 0f3d106a0..78f380db0 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@cross-module.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@cross-module.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/prepare_rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/cross-module.typ +snapshot_kind: text --- { "placeholder": "f", diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path.typ.snap index f5804e437..7a70cfed9 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/prepare_rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/module_path.typ +snapshot_kind: text --- { "placeholder": "variable.typ", diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path_alias.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path_alias.typ.snap index 92c2f307b..8f0e421d0 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path_alias.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path_alias.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/prepare_rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/module_path_alias.typ +snapshot_kind: text --- { "placeholder": "variable.typ", diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path_non_cano.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path_non_cano.typ.snap index fd714f5b9..8fcef403e 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path_non_cano.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path_non_cano.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/prepare_rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/module_path_non_cano.typ +snapshot_kind: text --- { "placeholder": "test/../variable.typ", diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path_star.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path_star.typ.snap index 4e93ddfb0..4e718d270 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path_star.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@module_path_star.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/prepare_rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/module_path_star.typ +snapshot_kind: text --- { "placeholder": "variable.typ", diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@user.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@user.typ.snap index 93834abe2..0b48f458a 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/prepare@user.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/prepare@user.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/prepare_rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/user.typ +snapshot_kind: text --- { "placeholder": "f", diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/test@builtin.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/test@builtin.typ.snap index 9c01880d0..de9df66bc 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/test@builtin.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/test@builtin.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/builtin.typ +snapshot_kind: text --- null diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/test@cross-module.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/test@cross-module.typ.snap index f32e24334..3a5a7ace4 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/test@cross-module.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/test@cross-module.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/cross-module.typ +snapshot_kind: text --- { "changes": { diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path.typ.snap index 779e8280e..81e788db4 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/module_path.typ +snapshot_kind: text --- { "documentChanges": [ diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path_alias.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path_alias.typ.snap index 00541c7bb..54a4523f7 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path_alias.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path_alias.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/module_path_alias.typ +snapshot_kind: text --- { "documentChanges": [ diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path_non_cano.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path_non_cano.typ.snap index c43f7a41a..0778bb22d 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path_non_cano.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path_non_cano.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/module_path_non_cano.typ +snapshot_kind: text --- { "documentChanges": [ diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path_star.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path_star.typ.snap index 9a3aec581..3e18c71e7 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path_star.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/test@module_path_star.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/module_path_star.typ +snapshot_kind: text --- { "documentChanges": [ diff --git a/crates/tinymist-query/src/fixtures/rename/snaps/test@user.typ.snap b/crates/tinymist-query/src/fixtures/rename/snaps/test@user.typ.snap index 47eb16975..91d0b6566 100644 --- a/crates/tinymist-query/src/fixtures/rename/snaps/test@user.typ.snap +++ b/crates/tinymist-query/src/fixtures/rename/snaps/test@user.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/rename.rs expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" input_file: crates/tinymist-query/src/fixtures/rename/user.typ +snapshot_kind: text --- { "changes": { diff --git a/crates/tinymist-query/src/fixtures/semantic_tokens/fn3.typ b/crates/tinymist-query/src/fixtures/semantic_tokens/fn3.typ new file mode 100644 index 000000000..30e266d9d --- /dev/null +++ b/crates/tinymist-query/src/fixtures/semantic_tokens/fn3.typ @@ -0,0 +1,7 @@ + +#let test = [] + +#{ + test + [] +} diff --git a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@base.typ.snap b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@base.typ.snap index f02471a5f..8bb055209 100644 --- a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@base.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/semantic_tokens_full.rs expression: "serde_json::to_string(&result).unwrap()" input_file: crates/tinymist-query/src/fixtures/semantic_tokens/base.typ +snapshot_kind: text --- {"data":[0,0,1,2,0,0,1,3,2,0,0,3,1,22,0,0,1,1,20,0,0,1,1,22,0,0,1,1,3,0,0,1,1,22,0,0,1,1,4,0,0,1,1,10,0]} diff --git a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@content-block.typ.snap b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@content-block.typ.snap index 1674defb3..b19a611a9 100644 --- a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@content-block.typ.snap +++ b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@content-block.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/semantic_tokens_full.rs expression: "serde_json::to_string(&result).unwrap()" input_file: crates/tinymist-query/src/fixtures/semantic_tokens/content-block.typ +snapshot_kind: text --- {"data":[0,0,1,10,0,0,1,1,10,0,0,1,1,10,0,0,1,1,22,0,1,0,1,10,0,0,1,1,10,0,0,1,1,22,0,0,1,1,10,0,0,1,1,22,0,1,0,1,10,0,0,1,1,10,0,0,1,1,10,0,0,1,1,10,0,0,1,1,22,0,0,1,1,10,0,0,1,1,10,0,0,1,1,10,0,0,1,1,10,0,0,1,1,10,0,0,1,3,22,0,0,3,1,10,0,0,1,1,10,0,0,1,1,10,0,0,1,1,22,0]} diff --git a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@fn.typ.snap b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@fn.typ.snap index 62c46aac1..f4d14e61f 100644 --- a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@fn.typ.snap +++ b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@fn.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/semantic_tokens_full.rs expression: "serde_json::to_string(&result).unwrap()" input_file: crates/tinymist-query/src/fixtures/semantic_tokens/fn.typ +snapshot_kind: text --- {"data":[0,0,1,2,0,0,1,3,2,0,0,3,1,22,0,0,1,1,5,0,0,1,1,10,0,0,1,1,20,0,0,1,1,10,0,0,1,1,22,0,0,1,1,20,0,0,1,1,10,0,0,1,1,22,0,0,1,1,3,0,0,1,1,22,0,0,1,1,10,0,0,1,1,22,0,0,1,1,20,0,0,1,1,22,0,0,1,2,3,0,0,2,1,22,0,0,1,1,20,0,0,1,1,22,0,0,1,1,10,0]} diff --git a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@fn2.typ.snap b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@fn2.typ.snap index 4f7e1e5bd..91278204c 100644 --- a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@fn2.typ.snap +++ b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@fn2.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/semantic_tokens_full.rs expression: "serde_json::to_string(&result).unwrap()" input_file: crates/tinymist-query/src/fixtures/semantic_tokens/fn2.typ +snapshot_kind: text --- {"data":[0,0,1,2,0,0,1,3,2,0,0,3,1,22,0,0,1,2,5,0,0,2,1,10,0,0,1,1,10,0,0,1,1,22,0,0,1,1,3,0,0,1,1,22,0,0,1,1,10,0,0,1,1,22,0,1,0,2,22,0,0,2,3,5,0,0,3,1,10,0,0,1,7,1,0,0,7,1,10,0,0,1,1,22,0,0,1,4,20,0,0,4,1,10,0,0,1,1,22,0,0,1,5,1,0,0,5,1,10,0,0,1,1,22,0,1,0,2,22,0,0,2,3,22,0,0,3,3,22,0,0,3,1,22,0,1,0,2,22,0,0,2,1,22,0,0,1,1,22,0,1,0,2,22,0,0,2,1,22,0,0,1,1,22,0,1,0,2,22,0,0,2,3,22,0,0,3,1,22,0,1,0,2,22,0,0,2,1,10,0,0,1,1,22,0,0,1,1,10,0,0,1,1,22,0,1,0,1,10,0]} diff --git a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@fn3.typ.snap b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@fn3.typ.snap new file mode 100644 index 000000000..f8b5f6355 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@fn3.typ.snap @@ -0,0 +1,7 @@ +--- +source: crates/tinymist-query/src/semantic_tokens_full.rs +expression: "serde_json::to_string(&result).unwrap()" +input_file: crates/tinymist-query/src/fixtures/semantic_tokens/fn3.typ +snapshot_kind: text +--- +{"data":[0,0,1,2,0,0,1,3,2,0,0,3,1,22,0,0,1,4,20,0,0,4,1,22,0,0,1,1,3,0,0,1,1,22,0,0,1,1,10,0,0,1,1,10,0,0,1,1,22,0,1,0,1,22,0,1,0,1,10,0,0,1,1,10,0,0,1,1,22,0,1,0,2,22,0,0,2,4,20,0,0,4,1,22,0,1,0,2,22,0,0,2,1,10,0,0,1,1,10,0,0,1,1,22,0,1,0,1,10,0,0,1,1,22,0]} diff --git a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@for-loop.typ.snap b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@for-loop.typ.snap index 881398369..0df304cf0 100644 --- a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@for-loop.typ.snap +++ b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@for-loop.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/semantic_tokens_full.rs expression: "serde_json::to_string(&result).unwrap()" input_file: crates/tinymist-query/src/fixtures/semantic_tokens/for-loop.typ +snapshot_kind: text --- {"data":[0,0,1,2,0,0,1,3,2,0,0,3,1,22,0,0,1,1,20,0,0,1,1,22,0,0,1,2,2,0,0,2,1,22,0,0,1,5,5,0,0,5,1,10,0,0,1,1,4,0,0,1,1,10,0,0,1,1,22,0,0,1,1,10,0,0,1,1,22,0,0,1,1,20,0,0,1,1,22,0,0,1,2,3,0,0,2,1,22,0,0,1,1,4,0,0,1,1,22,0,0,1,1,10,0]} diff --git a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@heading.typ.snap b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@heading.typ.snap index 326d7714a..a6525ee45 100644 --- a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@heading.typ.snap +++ b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@heading.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/semantic_tokens_full.rs expression: "serde_json::to_string(&result).unwrap()" input_file: crates/tinymist-query/src/fixtures/semantic_tokens/heading.typ +snapshot_kind: text --- {"data":[0,0,3,16,0,0,3,1,22,0,0,1,1,5,0,0,1,4,5,0,0,4,1,10,0,0,1,17,1,0,0,17,1,10,0]} diff --git a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@tinymist_issue_601.typ.snap b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@tinymist_issue_601.typ.snap index 544f16ad2..110e15689 100644 --- a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@tinymist_issue_601.typ.snap +++ b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@tinymist_issue_601.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/semantic_tokens_full.rs expression: "serde_json::to_string(&result).unwrap()" input_file: crates/tinymist-query/src/fixtures/semantic_tokens/tinymist_issue_601.typ +snapshot_kind: text --- {"data":[0,0,1,21,4,0,1,3,5,4,0,3,1,10,4,0,1,1,22,4,0,1,1,3,4,0,1,1,22,4,0,1,1,22,4,1,0,1,22,4,0,1,1,22,4,1,0,1,22,4]} diff --git a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@tinymist_issue_638.typ.snap b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@tinymist_issue_638.typ.snap index 4a4dee994..2e2d50cf8 100644 --- a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@tinymist_issue_638.typ.snap +++ b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@tinymist_issue_638.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/semantic_tokens_full.rs expression: "serde_json::to_string(&result).unwrap()" input_file: crates/tinymist-query/src/fixtures/semantic_tokens/tinymist_issue_638.typ +snapshot_kind: text --- {"data":[0,0,9,22,0,0,9,1,22,0]} diff --git a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@typst_lsp_issue_264.typ.snap b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@typst_lsp_issue_264.typ.snap index 39dec4a23..610c4ee45 100644 --- a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@typst_lsp_issue_264.typ.snap +++ b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@typst_lsp_issue_264.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/semantic_tokens_full.rs expression: "serde_json::to_string(&result).unwrap()" input_file: crates/tinymist-query/src/fixtures/semantic_tokens/typst_lsp_issue_264.typ +snapshot_kind: text --- {"data":[0,0,3,0,0,1,0,4,0,0,1,0,3,0,0,1,0,2,0,0,0,2,1,22,0,1,0,1,22,0,1,0,3,22,0,0,3,4,22,0,0,4,1,22,0,1,0,17,22,0,0,17,1,22,0,1,0,3,22,0]} diff --git a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@typst_lsp_issue_401.typ.snap b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@typst_lsp_issue_401.typ.snap index 9de3a4626..6e44d1893 100644 --- a/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@typst_lsp_issue_401.typ.snap +++ b/crates/tinymist-query/src/fixtures/semantic_tokens/snaps/test@typst_lsp_issue_401.typ.snap @@ -2,5 +2,6 @@ source: crates/tinymist-query/src/semantic_tokens_full.rs expression: "serde_json::to_string(&result).unwrap()" input_file: crates/tinymist-query/src/fixtures/semantic_tokens/typst_lsp_issue_401.typ +snapshot_kind: text --- {"data":[0,0,1,1,0,0,1,6,1,0,1,0,1,1,0,1,0,6,1,0]} diff --git a/crates/tinymist-query/src/fixtures/signature/snaps/test@builtin.typ.snap b/crates/tinymist-query/src/fixtures/signature/snaps/test@builtin.typ.snap index e8fac195c..42e57b0a2 100644 --- a/crates/tinymist-query/src/fixtures/signature/snaps/test@builtin.typ.snap +++ b/crates/tinymist-query/src/fixtures/signature/snaps/test@builtin.typ.snap @@ -1,7 +1,8 @@ --- source: crates/tinymist-query/src/analysis.rs -expression: SignatureSnapshot(result.as_deref()) +expression: SignatureSnapshot(result.as_ref()) input_file: crates/tinymist-query/src/fixtures/signature/builtin.typ +snapshot_kind: text --- fn( red, diff --git a/crates/tinymist-query/src/fixtures/signature/snaps/test@builtin_with.typ.snap b/crates/tinymist-query/src/fixtures/signature/snaps/test@builtin_with.typ.snap index e2f5d3d39..3b039e8d0 100644 --- a/crates/tinymist-query/src/fixtures/signature/snaps/test@builtin_with.typ.snap +++ b/crates/tinymist-query/src/fixtures/signature/snaps/test@builtin_with.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: SignatureSnapshot(result.as_ref()) input_file: crates/tinymist-query/src/fixtures/signature/builtin_with.typ +snapshot_kind: text --- with red: 50%, green: 50%, blue: 50%, fn( diff --git a/crates/tinymist-query/src/fixtures/signature/snaps/test@import.typ.snap b/crates/tinymist-query/src/fixtures/signature/snaps/test@import.typ.snap index 6075b6102..bb74625d1 100644 --- a/crates/tinymist-query/src/fixtures/signature/snaps/test@import.typ.snap +++ b/crates/tinymist-query/src/fixtures/signature/snaps/test@import.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: SignatureSnapshot(result.as_ref()) input_file: crates/tinymist-query/src/fixtures/signature/import.typ +snapshot_kind: text --- fn( u, diff --git a/crates/tinymist-query/src/fixtures/signature/snaps/test@import_ident.typ.snap b/crates/tinymist-query/src/fixtures/signature/snaps/test@import_ident.typ.snap index d58f419aa..8dc81083e 100644 --- a/crates/tinymist-query/src/fixtures/signature/snaps/test@import_ident.typ.snap +++ b/crates/tinymist-query/src/fixtures/signature/snaps/test@import_ident.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: SignatureSnapshot(result.as_ref()) input_file: crates/tinymist-query/src/fixtures/signature/import_ident.typ +snapshot_kind: text --- fn( u, diff --git a/crates/tinymist-query/src/fixtures/signature/snaps/test@user.typ.snap b/crates/tinymist-query/src/fixtures/signature/snaps/test@user.typ.snap index a6dbabf3e..d985803d7 100644 --- a/crates/tinymist-query/src/fixtures/signature/snaps/test@user.typ.snap +++ b/crates/tinymist-query/src/fixtures/signature/snaps/test@user.typ.snap @@ -1,7 +1,8 @@ --- source: crates/tinymist-query/src/analysis.rs -expression: SignatureSnapshot(result.as_deref()) +expression: SignatureSnapshot(result.as_ref()) input_file: crates/tinymist-query/src/fixtures/signature/user.typ +snapshot_kind: text --- fn( u, diff --git a/crates/tinymist-query/src/fixtures/signature/snaps/test@user_with.typ.snap b/crates/tinymist-query/src/fixtures/signature/snaps/test@user_with.typ.snap index f3998d82a..c6a01218b 100644 --- a/crates/tinymist-query/src/fixtures/signature/snaps/test@user_with.typ.snap +++ b/crates/tinymist-query/src/fixtures/signature/snaps/test@user_with.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: SignatureSnapshot(result.as_ref()) input_file: crates/tinymist-query/src/fixtures/signature/user_with.typ +snapshot_kind: text --- with u: 1, fn( diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_fn.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_fn.typ.snap index bca10d4a6..db22e1bd7 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_fn.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_fn.typ.snap @@ -2,8 +2,9 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/annotation_fn.typ +snapshot_kind: text --- -"touying-fn-wrapper" = ((( ⪯ Type(function)), "max-repetitions": ( ⪯ Type(int)), "repetitions": ( ⪯ Type(int)), ...: ( ⪯ Any)) => None).with(..("max-repetitions": None, "repetitions": None) => any) +"touying-fn-wrapper" = ((Type(function), "max-repetitions": Type(int), "repetitions": Type(int), ...: Any) => None).with(..("max-repetitions": None, "repetitions": None) => any) "fn" = Any "max-repetitions" = None "repetitions" = None diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_fn2.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_fn2.typ.snap index 9c7186c56..e6e27bf5e 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_fn2.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_fn2.typ.snap @@ -2,9 +2,10 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/annotation_fn2.typ +snapshot_kind: text --- "args" = Any -"fn-wrapper" = (( ⪯ (Type(function) | (...: Any) => Any)), ...: ( ⪯ Any)) => None +"fn-wrapper" = ((Type(function) | (...: Any) => Any), ...: Any) => None "fn" = Any "args" = Args --- diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_sum.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_sum.typ.snap index f644caa3b..86586d5c7 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_sum.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_sum.typ.snap @@ -2,8 +2,9 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/annotation_sum.typ +snapshot_kind: text --- -"sum" = (...: ( ⪯ Array)) => None +"sum" = (...: Array) => None "args" = Args --- 65..68 -> @sum diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_tag.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_tag.typ.snap index 3db66de23..b216f9a07 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_tag.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_tag.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/annotation_tag.typ +snapshot_kind: text --- "config-common" = () => None --- diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_var.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_var.typ.snap index 2d4c04fe9..712ce6323 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_var.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_var.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/annotation_var.typ +snapshot_kind: text --- "x" = Any "y" = Any diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@base.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@base.typ.snap index f0dec3682..6f6b30e72 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@base.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/base.typ +snapshot_kind: text --- "f" = () => 1 --- diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@bug_cite_func_infer.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@bug_cite_func_infer.typ.snap index 0c9ca030b..54cfae1e9 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@bug_cite_func_infer.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@bug_cite_func_infer.typ.snap @@ -2,10 +2,11 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/bug_cite_func_infer.typ +snapshot_kind: text --- -"cite_prose" = (( ⪯ (RefLabel))) => Element(ref) +"cite_prose" = (RefLabel) => Element(ref) "labl" = Any -"cite_prose_different_name" = (( ⪯ (RefLabel))) => Element(ref) +"cite_prose_different_name" = (RefLabel) => Element(ref) "labl" = Any --- 5..15 -> @cite_prose diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@confusing-name.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@confusing-name.typ.snap index e10f2e803..2bdcd22bb 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@confusing-name.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@confusing-name.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/confusing-name.typ +snapshot_kind: text --- "x" = (Any) => Any "date" = Any diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@constants.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@constants.typ.snap index 99b829997..2bc7b55b7 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@constants.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@constants.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/constants.typ +snapshot_kind: text --- "f" = (Any) => TypeBinary { operands: (1, 1), op: Add } "x" = Any diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@control_flow.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@control_flow.typ.snap index d0e426d42..ab87f03cc 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@control_flow.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@control_flow.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/control_flow.typ +snapshot_kind: text --- "x0" = IfTy { cond: true, then: 1, else_: None } "x1" = IfTy { cond: false, then: 2, else_: None } diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@dict_infer.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@dict_infer.typ.snap index 3d2a14bdd..004a4d27f 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@dict_infer.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@dict_infer.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/dict_infer.typ +snapshot_kind: text --- "a" = {"a": "1"} "b" = ("1" | {"a": "1"}.a) diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@external.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@external.typ.snap index 3cc58c439..33060648a 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@external.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@external.typ.snap @@ -2,12 +2,15 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/external.typ +snapshot_kind: text --- +"base" = Any "bad-instantiate" = Any -"prefix" = (("title": ( ⪯ Any)) => TypeBinary { operands: (TypeBinary { operands: (TypeBinary { operands: (Any, None), op: Add }, None), op: Add }, None), op: Add }).with(..("title": None) => any) +"prefix" = (("title": Any) => TypeBinary { operands: (TypeBinary { operands: (TypeBinary { operands: (Any, None), op: Add }, None), op: Add }, None), op: Add }).with(..("title": None) => any) "title" = None --- 0..0 -> @bad-instantiate +1..21 -> @base 27..33 -> @prefix 34..39 -> @title 53..68 -> @bad-instantiate diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named.typ.snap index d6c04f64e..b76455bb9 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named.typ.snap @@ -2,9 +2,10 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/fn_named.typ +snapshot_kind: text --- "foo" = (("d": Any) => Any).with(..("d": 3) => any) -"d" = ( ⪰ 3 | Type(int)) +"d" = ( ⪰ Type(int) | 3) "x" = 3 --- 5..8 -> @foo diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named2.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named2.typ.snap index 35bc50c0a..804cdf211 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named2.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named2.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/fn_named2.typ +snapshot_kind: text --- "val" = 1 "foo" = (("a": Any) => Any).with(..("a": 1) => any) diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named3.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named3.typ.snap index fa5920476..911bb444a 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named3.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named3.typ.snap @@ -2,10 +2,11 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/fn_named3.typ +snapshot_kind: text --- "fun" = () => TypeUnary { lhs: 2, op: Return } "foo" = (("b": Any) => Any).with(..("b": TypeUnary { lhs: 2, op: Return }) => any) -"b" = ( ⪰ TypeUnary { lhs: 2, op: Return } | TypeUnary { lhs: 2, op: Return }) +"b" = TypeUnary { lhs: 2, op: Return } "x" = TypeUnary { lhs: 2, op: Return } --- 5..8 -> @fun diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named4.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named4.typ.snap index 03f34d8be..d9b2f90a8 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named4.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@fn_named4.typ.snap @@ -2,10 +2,11 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/fn_named4.typ +snapshot_kind: text --- "dict" = {"x": 3} "foo" = (("c": Any) => Any).with(..("c": (3 | {"x": 3}.x)) => any) -"c" = ( ⪰ (3 | {"x": 3}.x) | (3 | {"x": 3}.x)) +"c" = (3 | {"x": 3}.x) "x" = (3 | {"x": 3}.x) --- 5..9 -> @dict diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@infer.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@infer.typ.snap index 9d840342a..d049b18f5 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@infer.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@infer.typ.snap @@ -2,6 +2,8 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/infer.typ +snapshot_kind: text +--- --- 1..6 -> Func(image) 1..18 -> Element(image) diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@infer2.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@infer2.typ.snap index 3fdea8f37..1c9a950fc 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@infer2.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@infer2.typ.snap @@ -2,6 +2,8 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/infer2.typ +snapshot_kind: text +--- --- 1..5 -> Func(text) 1..52 -> Element(text) diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@infer_stroke_dict.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@infer_stroke_dict.typ.snap index 8e8c909b7..f5e29e91d 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@infer_stroke_dict.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@infer_stroke_dict.typ.snap @@ -2,6 +2,8 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/infer_stroke_dict.typ +snapshot_kind: text +--- --- 1..5 -> Func(text) 1..54 -> Element(text) diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@op_contains.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@op_contains.typ.snap index 5535a6cff..a461fc456 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@op_contains.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@op_contains.typ.snap @@ -2,8 +2,9 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/op_contains.typ +snapshot_kind: text --- -"f" = (( ⪯ ("line" | "number"))) => Type(none) +"f" = (("line" | "number")) => Type(none) "x" = Any --- 5..6 -> @f diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@op_contains_str.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@op_contains_str.typ.snap index 82020f4a4..729bd21ab 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@op_contains_str.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@op_contains_str.typ.snap @@ -2,8 +2,9 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/op_contains_str.typ +snapshot_kind: text --- -"f" = (( ⪯ TypeUnary { lhs: "abc", op: ElementOf })) => Type(none) +"f" = (TypeUnary { lhs: "abc", op: ElementOf }) => Type(none) "x" = Any --- 5..6 -> @f diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@op_type_of.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@op_type_of.typ.snap index b63db242d..eee483204 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@op_type_of.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@op_type_of.typ.snap @@ -2,8 +2,9 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/op_type_of.typ +snapshot_kind: text --- -"f" = (( ⪯ Any)) => Type(none) +"f" = (Any) => Type(none) "x" = Type(integer) --- 5..6 -> @f diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@recursive.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@recursive.typ.snap index df9c7a25b..494058a1a 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@recursive.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@recursive.typ.snap @@ -2,11 +2,14 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/recursive.typ +snapshot_kind: text --- +"base" = Any "a" = Any "f" = () => Any --- 0..0 -> @a +1..21 -> @base 27..28 -> @f 33..34 -> @a 33..36 -> Any diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@recursive_use.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@recursive_use.typ.snap index 587da8545..e8d3e3cce 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@recursive_use.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@recursive_use.typ.snap @@ -2,11 +2,14 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/recursive_use.typ +snapshot_kind: text --- +"base" = Any "a" = Any "f" = () => Any --- 0..0 -> @a +1..21 -> @base 27..28 -> @f 33..34 -> @a 33..37 -> Any diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@set_font.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@set_font.typ.snap index ac1f22f26..9676704b4 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@set_font.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@set_font.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/set_font.typ +snapshot_kind: text --- "font" = "Times New Roman" --- diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@sig_template.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@sig_template.typ.snap index d12ca4be8..90d5705ae 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@sig_template.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@sig_template.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/sig_template.typ +snapshot_kind: text --- "tmpl" = (Any) => Any "content" = Any diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@sig_template_set.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@sig_template_set.typ.snap index 7483c349e..b094c225e 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@sig_template_set.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@sig_template_set.typ.snap @@ -2,12 +2,13 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/sig_template_set.typ +snapshot_kind: text --- -"tmpl" = ((Any, "authors": ( ⪯ (Type(array) | Type(str))), "class": Any, "font": ( ⪯ (TextFont | Array))) => Any).with(..("authors": (), "class": "article", "font": None) => any) +"tmpl" = ((Any, "authors": (Type(array) | Type(str)), "class": Any, "font": (TextFont | Array)) => Any).with(..("authors": (), "class": "article", "font": None) => any) "content" = Any "authors" = () "font" = None -"class" = ( ⪰ "article" | "article" | "letter" | "article" | "letter") +"class" = ( ⪰ "article" | "letter") --- 5..9 -> @tmpl 10..17 -> @content diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@text_font.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@text_font.typ.snap index a86cd3a76..9b55767e8 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@text_font.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@text_font.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/text_font.typ +snapshot_kind: text --- "x" = "Test" "y" = ("Test", ) diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@tuple_at.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@tuple_at.typ.snap index 692ada510..d39dcae0a 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@tuple_at.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@tuple_at.typ.snap @@ -2,6 +2,7 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/tuple_at.typ +snapshot_kind: text --- "a" = (1, 2, 3, ) "b" = 2 diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@tuple_map.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@tuple_map.typ.snap index 62199ac19..f3482ac03 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@tuple_map.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@tuple_map.typ.snap @@ -2,10 +2,11 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/tuple_map.typ +snapshot_kind: text --- "a" = (1, ) -"f" = (( ⪯ (Type(bytes) | Type(decimal) | Type(float) | Type(int) | Type(label) | Type(str) | Type(type) | Type(version)))) => Type(str) -"" = (( ⪯ (Type(bytes) | Type(decimal) | Type(float) | Type(int) | Type(label) | Type(str) | Type(type) | Type(version)))) => Type(str) +"f" = ((Type(bytes) | Type(decimal) | Type(float) | Type(int) | Type(label) | Type(str) | Type(type) | Type(version))) => Type(str) +"" = ((Type(bytes) | Type(decimal) | Type(float) | Type(int) | Type(label) | Type(str) | Type(type) | Type(version))) => Type(str) "x" = Any "b" = (Type(str), ) --- diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@with.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@with.typ.snap index 5ec762c75..1b00febd9 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@with.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@with.typ.snap @@ -2,9 +2,10 @@ source: crates/tinymist-query/src/analysis.rs expression: result input_file: crates/tinymist-query/src/fixtures/type_check/with.typ +snapshot_kind: text --- "f" = (Any) => Any -"x" = ( ⪰ Type(int) | Type(int)) +"x" = Type(int) "g" = ((Any) => Any).with(..(1) => any) "x" = 1 --- diff --git a/crates/tinymist-query/src/fixtures/type_describe/snaps/test@ever_call.typ.snap b/crates/tinymist-query/src/fixtures/type_describe/snaps/test@ever_call.typ.snap index b2887cbc0..4e1f33d62 100644 --- a/crates/tinymist-query/src/fixtures/type_describe/snaps/test@ever_call.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_describe/snaps/test@ever_call.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"tmpl\" (93)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/type_describe/ever_call.typ +snapshot_kind: text --- (int) => int diff --git a/crates/tinymist-query/src/fixtures/type_describe/snaps/test@ever_intern_use.typ.snap b/crates/tinymist-query/src/fixtures/type_describe/snaps/test@ever_intern_use.typ.snap index 857a91447..00f04d305 100644 --- a/crates/tinymist-query/src/fixtures/type_describe/snaps/test@ever_intern_use.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_describe/snaps/test@ever_intern_use.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"tmpl\" (113)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/type_describe/ever_intern_use.typ +snapshot_kind: text --- (1 | 2 | 3 | int) => 1 | 2 | 3 | int diff --git a/crates/tinymist-query/src/fixtures/type_describe/snaps/test@user_named.typ.snap b/crates/tinymist-query/src/fixtures/type_describe/snaps/test@user_named.typ.snap index 529b9af9b..7c07410c0 100644 --- a/crates/tinymist-query/src/fixtures/type_describe/snaps/test@user_named.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_describe/snaps/test@user_named.typ.snap @@ -3,5 +3,6 @@ source: crates/tinymist-query/src/analysis.rs description: "Check on \"tmpl\" (95)" expression: literal_type input_file: crates/tinymist-query/src/fixtures/type_describe/user_named.typ +snapshot_kind: text --- (any, font: array | none | text.font) => any diff --git a/crates/tinymist-query/src/hover.rs b/crates/tinymist-query/src/hover.rs index cffac1718..bf355f449 100644 --- a/crates/tinymist-query/src/hover.rs +++ b/crates/tinymist-query/src/hover.rs @@ -235,15 +235,22 @@ fn link_tooltip( node = node.parent()?; } - let mut links = get_link_exprs_in(ctx, node)?; - links.retain(|link| link.0.contains(&cursor)); + let links = get_link_exprs_in(node)?; + let links = links + .objects + .iter() + .filter(|link| link.range.contains(&cursor)) + .collect::>(); if links.is_empty() { return None; } let mut results = vec![]; let mut actions = vec![]; - for (_, target) in links { + for obj in links { + let Some(target) = obj.target.resolve(ctx) else { + continue; + }; // open file in tab or system application actions.push(CommandLink { title: Some("Open in Tab".to_string()), @@ -272,8 +279,12 @@ fn link_tooltip( Some(HoverContents::Array(results)) } -fn push_result_ty(name: &str, ty_repr: Option<&(String, String)>, type_doc: &mut String) { - let Some((short, _)) = ty_repr else { +fn push_result_ty( + name: &str, + ty_repr: Option<&(EcoString, EcoString, EcoString)>, + type_doc: &mut String, +) { + let Some((short, _, _)) = ty_repr else { return; }; if short == name { diff --git a/crates/tinymist-query/src/lib.rs b/crates/tinymist-query/src/lib.rs index de3d77436..5f6ee776f 100644 --- a/crates/tinymist-query/src/lib.rs +++ b/crates/tinymist-query/src/lib.rs @@ -15,8 +15,8 @@ pub mod syntax; pub mod ty; mod upstream; -pub use analysis::{LocalContext, LocalContextGuard}; -pub use upstream::with_vm; +pub use analysis::{LocalContext, LocalContextGuard, LspWorldExt}; +pub use upstream::{with_vm, CompletionFeat, PostfixSnippet}; mod diagnostics; pub use diagnostics::*; @@ -60,8 +60,6 @@ mod rename; pub use rename::*; mod selection_range; pub use selection_range::*; -mod semantic_tokens; -pub use semantic_tokens::*; mod semantic_tokens_full; pub use semantic_tokens_full::*; mod semantic_tokens_delta; @@ -79,8 +77,6 @@ pub use references::*; mod lsp_typst_boundary; pub use lsp_typst_boundary::*; -mod lsp_features; -pub use lsp_features::*; mod prelude; @@ -138,6 +134,21 @@ pub trait StatefulRequest { ) -> Option; } +/// Completely disabled log +#[macro_export] +macro_rules! log_never { + // debug!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // debug!(target: "my_target", "a {} event", "log") + (target: $target:expr, $($arg:tt)+) => { + let _ = format_args!($target, $($arg)+); + }; + + // debug!("a {} event", "log") + ($($arg:tt)+) => { + let _ = format_args!($($arg)+); + }; +} + #[allow(missing_docs)] mod polymorphic { use lsp_types::TextEdit; @@ -212,8 +223,12 @@ mod polymorphic { #[derive(Debug, Clone)] pub struct OnExportRequest { + /// The path of the document to export. pub path: PathBuf, + /// The kind of the export. pub kind: ExportKind, + /// Whether to open the exported file(s) after the export is done. + pub open: bool, } #[derive(Debug, Clone)] diff --git a/crates/tinymist-query/src/lsp_features.rs b/crates/tinymist-query/src/lsp_features.rs deleted file mode 100644 index eda503408..000000000 --- a/crates/tinymist-query/src/lsp_features.rs +++ /dev/null @@ -1,49 +0,0 @@ -// todo: remove this -#![allow(missing_docs)] - -use lsp_types::{ - Registration, SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions, - Unregistration, -}; -use strum::IntoEnumIterator; - -use crate::{Modifier, TokenType}; - -fn get_legend() -> SemanticTokensLegend { - SemanticTokensLegend { - token_types: TokenType::iter() - .filter(|e| *e != TokenType::None) - .map(Into::into) - .collect(), - token_modifiers: Modifier::iter().map(Into::into).collect(), - } -} - -const SEMANTIC_TOKENS_REGISTRATION_ID: &str = "semantic_tokens"; -const SEMANTIC_TOKENS_METHOD_ID: &str = "textDocument/semanticTokens"; - -pub fn get_semantic_tokens_registration(options: SemanticTokensOptions) -> Registration { - Registration { - id: SEMANTIC_TOKENS_REGISTRATION_ID.to_owned(), - method: SEMANTIC_TOKENS_METHOD_ID.to_owned(), - register_options: Some( - serde_json::to_value(options) - .expect("semantic tokens options should be representable as JSON value"), - ), - } -} - -pub fn get_semantic_tokens_unregistration() -> Unregistration { - Unregistration { - id: SEMANTIC_TOKENS_REGISTRATION_ID.to_owned(), - method: SEMANTIC_TOKENS_METHOD_ID.to_owned(), - } -} - -pub fn get_semantic_tokens_options() -> SemanticTokensOptions { - SemanticTokensOptions { - legend: get_legend(), - full: Some(SemanticTokensFullOptions::Delta { delta: Some(true) }), - ..Default::default() - } -} diff --git a/crates/tinymist-query/src/on_enter.rs b/crates/tinymist-query/src/on_enter.rs index ceaad8455..5432a0044 100644 --- a/crates/tinymist-query/src/on_enter.rs +++ b/crates/tinymist-query/src/on_enter.rs @@ -20,8 +20,8 @@ use crate::{prelude::*, syntax::node_ancestors, SyntaxRequest}; pub struct OnEnterRequest { /// The path of the document to get folding ranges for. pub path: PathBuf, - /// The source code position to request for. - pub position: LspPosition, + /// The source code range to request for. + pub range: LspRange, } impl SyntaxRequest for OnEnterRequest { @@ -33,7 +33,8 @@ impl SyntaxRequest for OnEnterRequest { position_encoding: PositionEncoding, ) -> Option { let root = LinkedNode::new(source.root()); - let cursor = lsp_to_typst::position(self.position, position_encoding, source)?; + let rng = lsp_to_typst::range(self.range, position_encoding, source)?; + let cursor = rng.end; let leaf = root.leaf_at_compat(cursor)?; let worker = OnEnterWorker { @@ -42,13 +43,13 @@ impl SyntaxRequest for OnEnterRequest { }; if matches!(leaf.kind(), SyntaxKind::LineComment) { - return worker.enter_line_doc_comment(&leaf, cursor); + return worker.enter_line_doc_comment(&leaf, rng); } let math_node = node_ancestors(&leaf).find(|node| matches!(node.kind(), SyntaxKind::Equation)); if let Some(mn) = math_node { - return worker.enter_block_math(mn, cursor); + return worker.enter_block_math(mn, rng); } None @@ -68,7 +69,11 @@ impl OnEnterWorker<'_> { " ".repeat(indent_size) } - fn enter_line_doc_comment(&self, leaf: &LinkedNode, cursor: usize) -> Option> { + fn enter_line_doc_comment( + &self, + leaf: &LinkedNode, + rng: Range, + ) -> Option> { let skipper = |n: &LinkedNode| { matches!( n.kind(), @@ -100,8 +105,6 @@ impl OnEnterWorker<'_> { let indent = self.indent_of(leaf.offset()); // todo: remove_trailing_whitespace - let rng = cursor..cursor; - let edit = TextEdit { range: typst_to_lsp::range(rng, self.source, self.position_encoding), new_text: format!("\n{indent}{comment_prefix} $0"), @@ -110,9 +113,13 @@ impl OnEnterWorker<'_> { Some(vec![edit]) } - fn enter_block_math(&self, math_node: &LinkedNode<'_>, cursor: usize) -> Option> { + fn enter_block_math( + &self, + math_node: &LinkedNode<'_>, + rng: Range, + ) -> Option> { let o = math_node.range(); - if !o.contains(&cursor) { + if !o.contains(&rng.end) { return None; } @@ -124,7 +131,6 @@ impl OnEnterWorker<'_> { } let indent = self.indent_of(o.start); - let rng = cursor..cursor; let edit = TextEdit { range: typst_to_lsp::range(rng, self.source, self.position_encoding), // todo: read indent configuration diff --git a/crates/tinymist-query/src/package.rs b/crates/tinymist-query/src/package.rs index 0540c734d..5faaee471 100644 --- a/crates/tinymist-query/src/package.rs +++ b/crates/tinymist-query/src/package.rs @@ -8,7 +8,7 @@ use parking_lot::Mutex; use reflexo_typst::typst::prelude::*; use reflexo_typst::{package::PackageSpec, TypstFileId}; use serde::{Deserialize, Serialize}; -use tinymist_world::https::HttpsRegistry; +use tinymist_world::package::HttpsRegistry; use typst::diag::{EcoString, StrResult}; use typst::syntax::package::PackageManifest; use typst::syntax::VirtualPath; @@ -92,7 +92,7 @@ pub fn list_package_by_namespace( ); for dir in registry.paths() { let local_path = dir.join(ns.as_str()); - if !local_path.exists() || !local_path.is_dir() { + if !local_path.exists() || !local_path.is_dir_follow_links() { continue; } // namespace/package_name/version @@ -105,15 +105,16 @@ pub fn list_package_by_namespace( let Some(package) = once_log(package, "read package name") else { continue; }; - if package.file_type().map_or(true, |ft| !ft.is_dir()) { + if package.file_name().to_string_lossy().starts_with('.') { continue; } - if package.file_name().to_string_lossy().starts_with('.') { + + let package_path = package.path(); + if !package_path.is_dir_follow_links() { continue; } // 3. version - let Some(versions) = - once_log(std::fs::read_dir(package.path()), "read package versions") + let Some(versions) = once_log(std::fs::read_dir(package_path), "read package versions") else { continue; }; @@ -121,13 +122,13 @@ pub fn list_package_by_namespace( let Some(version) = once_log(version, "read package version") else { continue; }; - if version.file_type().map_or(true, |ft| !ft.is_dir()) { + if version.file_name().to_string_lossy().starts_with('.') { continue; } - if version.file_name().to_string_lossy().starts_with('.') { + let package_version_path = version.path(); + if !package_version_path.is_dir_follow_links() { continue; } - let path = version.path(); let Some(version) = once_log( version.file_name().to_string_lossy().parse(), "parse package version", @@ -139,7 +140,7 @@ pub fn list_package_by_namespace( name: package.file_name().to_string_lossy().into(), version, }; - packages.push((path, spec)); + packages.push((package_version_path, spec)); } } } @@ -147,6 +148,20 @@ pub fn list_package_by_namespace( packages } +trait IsDirFollowLinks { + fn is_dir_follow_links(&self) -> bool; +} + +impl IsDirFollowLinks for PathBuf { + fn is_dir_follow_links(&self) -> bool { + // Although `canonicalize` is heavy, we must use it because `symlink_metadata` + // is not reliable. + self.canonicalize() + .map(|meta| meta.is_dir()) + .unwrap_or(false) + } +} + fn once_log(result: Result, site: &'static str) -> Option { let err = match result { Ok(value) => return Some(value), diff --git a/crates/tinymist-query/src/references.rs b/crates/tinymist-query/src/references.rs index 6d190618e..251be1c78 100644 --- a/crates/tinymist-query/src/references.rs +++ b/crates/tinymist-query/src/references.rs @@ -1,10 +1,12 @@ +use std::sync::OnceLock; + use log::debug; use typst::syntax::Span; use crate::{ analysis::{Definition, SearchCtx}, prelude::*, - syntax::{DerefTarget, RefExpr}, + syntax::{get_index_info, DerefTarget, RefExpr}, ty::Interned, }; @@ -59,6 +61,7 @@ pub(crate) fn find_references( ctx: ctx.fork_for_search(), references: vec![], def, + module_path: OnceLock::new(), }; if finding_label { @@ -73,6 +76,7 @@ struct ReferencesWorker<'a> { ctx: SearchCtx<'a>, references: Vec, def: Definition, + module_path: OnceLock>, } impl<'a> ReferencesWorker<'a> { @@ -103,7 +107,25 @@ impl<'a> ReferencesWorker<'a> { fn file(&mut self, ref_fid: TypstFileId) -> Option<()> { log::debug!("references: file: {ref_fid:?}"); - let ei = self.ctx.ctx.expr_stage_by_id(ref_fid)?; + let src = self.ctx.ctx.source_by_id(ref_fid).ok()?; + let index = get_index_info(&src); + match self.def.decl.kind() { + DefKind::Constant | DefKind::Function | DefKind::Struct | DefKind::Variable => { + if !index.identifiers.contains(self.def.decl.name()) { + return Some(()); + } + } + DefKind::Module => { + let ref_by_ident = index.identifiers.contains(self.def.decl.name()); + let ref_by_path = index.paths.contains(self.module_path()); + if !(ref_by_ident || ref_by_path) { + return Some(()); + } + } + DefKind::Reference => {} + } + + let ei = self.ctx.ctx.expr_stage(&src); let uri = self.ctx.ctx.uri_for_id(ref_fid).ok()?; let t = ei.get_refs(self.def.decl.clone()); @@ -135,6 +157,23 @@ impl<'a> ReferencesWorker<'a> { }) })); } + + // todo: references of package + fn module_path(&self) -> &Interned { + self.module_path.get_or_init(|| { + self.def + .decl + .file_id() + .and_then(|fid| { + fid.vpath() + .as_rooted_path() + .file_name()? + .to_str() + .map(From::from) + }) + .unwrap_or_default() + }) + } } #[cfg(test)] diff --git a/crates/tinymist-query/src/rename.rs b/crates/tinymist-query/src/rename.rs index 50fb4f3e1..e2bc57cb2 100644 --- a/crates/tinymist-query/src/rename.rs +++ b/crates/tinymist-query/src/rename.rs @@ -3,16 +3,19 @@ use lsp_types::{ RenameFile, TextDocumentEdit, }; use reflexo::path::{unix_slash, PathClean}; +use rustc_hash::FxHashSet; use typst::{ foundations::{Repr, Str}, syntax::Span, }; use crate::{ + analysis::{get_link_exprs, LinkObject, LinkTarget}, find_references, prelude::*, prepare_renaming, - syntax::{deref_expr, node_ancestors, Decl, DerefTarget}, + syntax::{deref_expr, get_index_info, node_ancestors, Decl, DerefTarget, RefExpr}, + ty::Interned, }; /// The [`textDocument/rename`] request is sent from the client to the server to @@ -71,7 +74,7 @@ impl StatefulRequest for RenameRequest { let new_uri = path_to_url(&new_path).ok()?; let mut edits: HashMap> = HashMap::new(); - do_rename_file(ctx, def_fid, diff, &mut edits)?; + do_rename_file(ctx, def_fid, diff, &mut edits); let mut document_changes = edits_to_document_changes(edits); @@ -122,13 +125,57 @@ pub(crate) fn do_rename_file( diff: PathBuf, edits: &mut HashMap>, ) -> Option<()> { - let dep = ctx.module_dependencies().get(&def_fid)?.clone(); + let def_path = def_fid + .vpath() + .as_rooted_path() + .file_name() + .unwrap_or_default() + .to_str() + .unwrap_or_default() + .into(); + let mut ctx = RenameFileWorker { + ctx, + def_fid, + def_path, + diff, + inserted: FxHashSet::default(), + }; + ctx.work(edits) +} + +struct RenameFileWorker<'a> { + ctx: &'a mut LocalContext, + def_fid: TypstFileId, + def_path: Interned, + diff: PathBuf, + inserted: FxHashSet, +} + +impl<'a> RenameFileWorker<'a> { + pub(crate) fn work(&mut self, edits: &mut HashMap>) -> Option<()> { + let dep = self.ctx.module_dependencies().get(&self.def_fid).cloned(); + if let Some(dep) = dep { + for ref_fid in dep.dependents.iter() { + self.refs_in_file(*ref_fid, edits); + } + } - for ref_fid in dep.dependents.iter() { - let ref_src = ctx.source_by_id(*ref_fid).ok()?; - let uri = ctx.uri_for_id(*ref_fid).ok()?; + for ref_fid in self.ctx.source_files().clone() { + self.links_in_file(ref_fid, edits); + } - let import_info = ctx.expr_stage(&ref_src); + Some(()) + } + + fn refs_in_file( + &mut self, + ref_fid: TypstFileId, + edits: &mut HashMap>, + ) -> Option<()> { + let ref_src = self.ctx.source_by_id(ref_fid).ok()?; + let uri = self.ctx.uri_for_id(ref_fid).ok()?; + + let import_info = self.ctx.expr_stage(&ref_src); let edits = edits.entry(uri).or_default(); for (span, r) in &import_info.resolves { @@ -138,17 +185,114 @@ pub(crate) fn do_rename_file( ) { continue; } - let importing = r.root.as_ref()?.file_id(); - if importing.map_or(true, |i| i != def_fid) { + if let Some(edit) = self.rename_module_path(*span, r, &ref_src) { + edits.push(edit); + } + } + + Some(()) + } + + fn links_in_file( + &mut self, + ref_fid: TypstFileId, + edits: &mut HashMap>, + ) -> Option<()> { + let ref_src = self.ctx.source_by_id(ref_fid).ok()?; + + let index = get_index_info(&ref_src); + if !index.paths.contains(&self.def_path) { + return Some(()); + } + + let uri = self.ctx.uri_for_id(ref_fid).ok()?; + + let link_info = get_link_exprs(&ref_src); + let root = LinkedNode::new(ref_src.root()); + let edits = edits.entry(uri).or_default(); + for obj in &link_info.objects { + if !matches!(obj.target, LinkTarget::Path(..)) { continue; } - log::debug!("import: {span:?} -> {importing:?} v.s. {def_fid:?}"); - rename_importer(ctx, &ref_src, *span, &diff, edits); + if let Some(edit) = self.rename_resource_path(obj, &root, &ref_src) { + edits.push(edit); + } + } + + Some(()) + } + + fn rename_resource_path( + &mut self, + obj: &LinkObject, + root: &LinkedNode, + src: &Source, + ) -> Option { + let r = root.find(obj.span)?; + self.rename_path_expr(r.clone(), r.cast()?, src, false) + } + + fn rename_module_path(&mut self, span: Span, r: &RefExpr, src: &Source) -> Option { + let importing = r.root.as_ref()?.file_id(); + + if importing.map_or(true, |i| i != self.def_fid) { + return None; } + log::debug!("import: {span:?} -> {importing:?} v.s. {:?}", self.def_fid); + // rename_importer(self.ctx, &ref_src, *span, &self.diff, edits); + + let root = LinkedNode::new(src.root()); + let import_node = root.find(span).and_then(deref_expr)?; + let (import_path, has_path_var) = node_ancestors(&import_node).find_map(|import_node| { + match import_node.cast::()? { + ast::Expr::Import(i) => { + Some((i.source(), i.new_name().is_none() && i.imports().is_none())) + } + ast::Expr::Include(i) => Some((i.source(), false)), + _ => None, + } + })?; + + self.rename_path_expr(import_node.clone(), import_path, src, has_path_var) } - Some(()) + fn rename_path_expr( + &mut self, + node: LinkedNode, + path: ast::Expr, + src: &Source, + has_path_var: bool, + ) -> Option { + let new_text = match path { + ast::Expr::Str(s) => { + if !self.inserted.insert(s.span()) { + return None; + } + + let old_str = s.get(); + let old_path = Path::new(old_str.as_str()); + let new_path = old_path.join(&self.diff).clean(); + let new_str = unix_slash(&new_path); + + let path_part = Str::from(new_str).repr(); + let need_alias = new_path.file_name() != old_path.file_name(); + + if has_path_var && need_alias { + let alias = old_path.file_stem()?.to_str()?; + format!("{path_part} as {alias}") + } else { + path_part.to_string() + } + } + _ => return None, + }; + + let import_path_range = node.find(path.span())?.range(); + let range = self.ctx.to_lsp_range(import_path_range, src); + + Some(TextEdit { range, new_text }) + } } pub(crate) fn edits_to_document_changes( @@ -166,53 +310,6 @@ pub(crate) fn edits_to_document_changes( document_changes } -fn rename_importer( - ctx: &LocalContext, - src: &Source, - span: Span, - diff: &Path, - edits: &mut Vec, -) -> Option<()> { - let root = LinkedNode::new(src.root()); - let import_node = root.find(span).and_then(deref_expr)?; - let (import_path, has_path_var) = node_ancestors(&import_node).find_map(|import_node| { - match import_node.cast::()? { - ast::Expr::Import(i) => { - Some((i.source(), i.new_name().is_none() && i.imports().is_none())) - } - ast::Expr::Include(i) => Some((i.source(), false)), - _ => None, - } - })?; - - let new_text = match import_path { - ast::Expr::Str(s) => { - let old_str = s.get(); - let old_path = Path::new(old_str.as_str()); - let new_path = old_path.join(diff).clean(); - let new_str = unix_slash(&new_path); - - let path_part = Str::from(new_str).repr(); - let need_alias = new_path.file_name() != old_path.file_name(); - - if has_path_var && need_alias { - let alias = old_path.file_stem()?.to_str()?; - format!("{path_part} as {alias}") - } else { - path_part.to_string() - } - } - _ => return None, - }; - - let import_path_range = import_node.find(import_path.span())?.range(); - let range = ctx.to_lsp_range(import_path_range, src); - - edits.push(TextEdit { range, new_text }); - - Some(()) -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/tinymist-query/src/semantic_tokens/delta.rs b/crates/tinymist-query/src/semantic_tokens/delta.rs deleted file mode 100644 index af24450b4..000000000 --- a/crates/tinymist-query/src/semantic_tokens/delta.rs +++ /dev/null @@ -1,75 +0,0 @@ -use lsp_types::{SemanticToken, SemanticTokensEdit}; - -#[derive(Debug)] -struct CachedTokens { - tokens: Vec, - id: u64, -} - -#[derive(Default, Debug)] -pub struct CacheInner { - last_sent: Option, - next_id: u64, -} - -impl CacheInner { - pub fn try_take_result(&mut self, id: &str) -> Option> { - let id = id.parse::().ok()?; - match self.last_sent.take() { - Some(cached) if cached.id == id => Some(cached.tokens), - Some(cached) => { - // replace after taking - self.last_sent = Some(cached); - None - } - None => None, - } - } - - pub fn cache_result(&mut self, tokens: Vec) -> String { - let id = self.get_next_id(); - let cached = CachedTokens { tokens, id }; - self.last_sent = Some(cached); - id.to_string() - } - - fn get_next_id(&mut self) -> u64 { - let id = self.next_id; - self.next_id += 1; - id - } -} - -pub fn token_delta(from: &[SemanticToken], to: &[SemanticToken]) -> Vec { - // Taken from `rust-analyzer`'s algorithm - // https://github.com/rust-lang/rust-analyzer/blob/master/crates/rust-analyzer/src/semantic_tokens.rs#L219 - - let start = from - .iter() - .zip(to.iter()) - .take_while(|(x, y)| x == y) - .count(); - - let (_, from) = from.split_at(start); - let (_, to) = to.split_at(start); - - let dist_from_end = from - .iter() - .rev() - .zip(to.iter().rev()) - .take_while(|(x, y)| x == y) - .count(); - - let (from, _) = from.split_at(from.len() - dist_from_end); - let (to, _) = to.split_at(to.len() - dist_from_end); - - if from.is_empty() && to.is_empty() { - vec![] - } else { - vec![SemanticTokensEdit { - start: 5 * start as u32, - delete_count: 5 * from.len() as u32, - data: Some(to.into()), - }] - } -} diff --git a/crates/tinymist-query/src/semantic_tokens/modifier_set.rs b/crates/tinymist-query/src/semantic_tokens/modifier_set.rs deleted file mode 100644 index f214da11b..000000000 --- a/crates/tinymist-query/src/semantic_tokens/modifier_set.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::ops; - -use super::typst_tokens::Modifier; - -#[derive(Default, Clone, Copy)] -pub struct ModifierSet(u32); - -impl ModifierSet { - pub fn empty() -> Self { - Self::default() - } - - pub fn new(modifiers: &[Modifier]) -> Self { - let bits = modifiers - .iter() - .copied() - .map(Modifier::bitmask) - .fold(0, |bits, mask| bits | mask); - Self(bits) - } - - pub fn bitset(self) -> u32 { - self.0 - } -} - -impl ops::BitOr for ModifierSet { - type Output = Self; - - fn bitor(self, rhs: Self) -> Self::Output { - Self(self.0 | rhs.0) - } -} diff --git a/crates/tinymist-query/src/semantic_tokens/typst_tokens.rs b/crates/tinymist-query/src/semantic_tokens/typst_tokens.rs deleted file mode 100644 index 20b80f65c..000000000 --- a/crates/tinymist-query/src/semantic_tokens/typst_tokens.rs +++ /dev/null @@ -1,150 +0,0 @@ -//! Types for tokens used for Typst syntax - -// todo: remove this -#![allow(missing_docs)] - -use lsp_types::{SemanticTokenModifier, SemanticTokenType}; -use strum::EnumIter; - -const BOOL: SemanticTokenType = SemanticTokenType::new("bool"); -const PUNCTUATION: SemanticTokenType = SemanticTokenType::new("punct"); -const ESCAPE: SemanticTokenType = SemanticTokenType::new("escape"); -const LINK: SemanticTokenType = SemanticTokenType::new("link"); -const RAW: SemanticTokenType = SemanticTokenType::new("raw"); -const LABEL: SemanticTokenType = SemanticTokenType::new("label"); -const REF: SemanticTokenType = SemanticTokenType::new("ref"); -const HEADING: SemanticTokenType = SemanticTokenType::new("heading"); -const LIST_MARKER: SemanticTokenType = SemanticTokenType::new("marker"); -const LIST_TERM: SemanticTokenType = SemanticTokenType::new("term"); -const DELIMITER: SemanticTokenType = SemanticTokenType::new("delim"); -const INTERPOLATED: SemanticTokenType = SemanticTokenType::new("pol"); -const ERROR: SemanticTokenType = SemanticTokenType::new("error"); -const TEXT: SemanticTokenType = SemanticTokenType::new("text"); - -/// Very similar to `typst_ide::Tag`, but with convenience traits, and -/// extensible because we want to further customize highlighting -#[derive(Clone, Copy, Eq, PartialEq, EnumIter, Default)] -#[repr(u32)] -pub enum TokenType { - // Standard LSP types - Comment, - String, - Keyword, - Operator, - Number, - Function, - Decorator, - Type, - Namespace, - // Custom types - Bool, - Punctuation, - Escape, - Link, - Raw, - Label, - Ref, - Heading, - ListMarker, - ListTerm, - Delimiter, - Interpolated, - Error, - /// Any text in markup without a more specific token type, possible styled. - /// - /// We perform styling (like bold and italics) via modifiers. That means - /// everything that should receive styling needs to be a token so we can - /// apply a modifier to it. This token type is mostly for that, since - /// text should usually not be specially styled. - Text, - /// A token that is not recognized by the lexer - #[default] - None, -} - -impl From for SemanticTokenType { - fn from(token_type: TokenType) -> Self { - use TokenType::*; - - match token_type { - Comment => Self::COMMENT, - String => Self::STRING, - Keyword => Self::KEYWORD, - Operator => Self::OPERATOR, - Number => Self::NUMBER, - Function => Self::FUNCTION, - Decorator => Self::DECORATOR, - Type => Self::TYPE, - Namespace => Self::NAMESPACE, - Bool => BOOL, - Punctuation => PUNCTUATION, - Escape => ESCAPE, - Link => LINK, - Raw => RAW, - Label => LABEL, - Ref => REF, - Heading => HEADING, - ListMarker => LIST_MARKER, - ListTerm => LIST_TERM, - Delimiter => DELIMITER, - Interpolated => INTERPOLATED, - Error => ERROR, - Text => TEXT, - None => unreachable!(), - } - } -} - -const STRONG: SemanticTokenModifier = SemanticTokenModifier::new("strong"); -const EMPH: SemanticTokenModifier = SemanticTokenModifier::new("emph"); -const MATH: SemanticTokenModifier = SemanticTokenModifier::new("math"); - -#[derive(Clone, Copy, EnumIter)] -#[repr(u8)] -pub enum Modifier { - Strong, - Emph, - Math, - ReadOnly, - Static, - DefaultLibrary, -} - -impl Modifier { - pub const fn index(self) -> u8 { - self as u8 - } - - pub const fn bitmask(self) -> u32 { - 0b1 << self.index() - } -} - -impl From for SemanticTokenModifier { - fn from(modifier: Modifier) -> Self { - use Modifier::*; - - match modifier { - Strong => STRONG, - Emph => EMPH, - Math => MATH, - ReadOnly => Self::READONLY, - Static => Self::STATIC, - DefaultLibrary => Self::DEFAULT_LIBRARY, - } - } -} - -#[cfg(test)] -mod test { - use strum::IntoEnumIterator; - - use super::*; - - #[test] - fn ensure_not_too_many_modifiers() { - // Because modifiers are encoded in a 32 bit bitmask, we can't have more than 32 - // modifiers - assert!(Modifier::iter().len() <= 32); - } -} diff --git a/crates/tinymist-query/src/semantic_tokens_delta.rs b/crates/tinymist-query/src/semantic_tokens_delta.rs index f2de7c471..4b29fb540 100644 --- a/crates/tinymist-query/src/semantic_tokens_delta.rs +++ b/crates/tinymist-query/src/semantic_tokens_delta.rs @@ -1,3 +1,5 @@ +use lsp_types::{SemanticToken, SemanticTokensEdit}; + use crate::prelude::*; /// The [`textDocument/semanticTokens/full/delta`] request is sent from the @@ -27,27 +29,58 @@ impl SemanticRequest for SemanticTokensDeltaRequest { /// document. fn request(self, ctx: &mut LocalContext) -> Option { let source = ctx.source_by_path(&self.path).ok()?; - let ei = ctx.expr_stage(&source); - - let token_ctx = &ctx.analysis.tokens_ctx; - let (tokens, result_id) = - token_ctx.semantic_tokens_delta(&source, ei, &self.previous_result_id); - - match tokens { - Ok(edits) => Some( - SemanticTokensDelta { - result_id: Some(result_id), - edits, - } - .into(), - ), - Err(tokens) => Some( - SemanticTokens { - result_id: Some(result_id), - data: tokens, - } - .into(), - ), - } + let (tokens, result_id) = ctx.cached_tokens(&source); + + Some(match ctx.tokens.as_ref().and_then(|t| t.prev.as_ref()) { + Some(cached) => SemanticTokensFullDeltaResult::TokensDelta(SemanticTokensDelta { + result_id, + edits: token_delta(cached, &tokens), + }), + None => { + log::warn!( + "No previous tokens found for delta computation in {}, prev_id: {:?}", + self.path.display(), + self.previous_result_id + ); + SemanticTokensFullDeltaResult::Tokens(SemanticTokens { + result_id, + data: tokens.as_ref().clone(), + }) + } + }) + } +} + +fn token_delta(from: &[SemanticToken], to: &[SemanticToken]) -> Vec { + // Taken from `rust-analyzer`'s algorithm + // https://github.com/rust-lang/rust-analyzer/blob/master/crates/rust-analyzer/src/semantic_tokens.rs#L219 + + let start = from + .iter() + .zip(to.iter()) + .take_while(|(x, y)| x == y) + .count(); + + let (_, from) = from.split_at(start); + let (_, to) = to.split_at(start); + + let dist_from_end = from + .iter() + .rev() + .zip(to.iter().rev()) + .take_while(|(x, y)| x == y) + .count(); + + let (from, _) = from.split_at(from.len() - dist_from_end); + let (to, _) = to.split_at(to.len() - dist_from_end); + + if from.is_empty() && to.is_empty() { + vec![] + } else { + vec![SemanticTokensEdit { + start: 5 * start as u32, + delete_count: 5 * from.len() as u32, + data: Some(to.into()), + }] } } diff --git a/crates/tinymist-query/src/semantic_tokens_full.rs b/crates/tinymist-query/src/semantic_tokens_full.rs index 0dceaa23c..068d63f9c 100644 --- a/crates/tinymist-query/src/semantic_tokens_full.rs +++ b/crates/tinymist-query/src/semantic_tokens_full.rs @@ -28,17 +28,12 @@ impl SemanticRequest for SemanticTokensFullRequest { /// Handles the request to compute the semantic tokens for a given document. fn request(self, ctx: &mut LocalContext) -> Option { let source = ctx.source_by_path(&self.path).ok()?; - let ei = ctx.expr_stage(&source); - let token_ctx = &ctx.analysis.tokens_ctx; - let (tokens, result_id) = token_ctx.semantic_tokens_full(&source, ei); - - Some( - SemanticTokens { - result_id: Some(result_id), - data: tokens, - } - .into(), - ) + let (tokens, result_id) = ctx.cached_tokens(&source); + + Some(SemanticTokensResult::Tokens(SemanticTokens { + result_id, + data: tokens.as_ref().clone(), + })) } } diff --git a/crates/tinymist-query/src/signature_help.rs b/crates/tinymist-query/src/signature_help.rs index be470892f..ddf748d19 100644 --- a/crates/tinymist-query/src/signature_help.rs +++ b/crates/tinymist-query/src/signature_help.rs @@ -43,7 +43,7 @@ impl SemanticRequest for SignatureHelpRequest { let sig = ctx.sig_of_def(def.clone())?; log::debug!("got signature {sig:?}"); - let param_shift = sig.param_shift(ctx); + let param_shift = sig.param_shift(); let mut active_parameter = None; let mut label = def.name().as_ref().to_owned(); diff --git a/crates/tinymist-query/src/syntax/def.rs b/crates/tinymist-query/src/syntax/def.rs index 77de62d9c..a54a23c41 100644 --- a/crates/tinymist-query/src/syntax/def.rs +++ b/crates/tinymist-query/src/syntax/def.rs @@ -16,6 +16,8 @@ use crate::{ ty::{InsTy, Interned, SelectTy, Ty, TypeVar}, }; +use super::{ExprDescriber, ExprPrinter}; + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Expr { /// A sequence of expressions @@ -69,10 +71,11 @@ pub enum Expr { /// A star import Star, } + impl Expr { pub(crate) fn repr(&self) -> EcoString { let mut s = EcoString::new(); - let _ = ExprFormatter::new(&mut s, true).write_expr(self); + let _ = ExprDescriber::new(&mut s).write_expr(self); s } @@ -95,7 +98,7 @@ impl Expr { impl fmt::Display for Expr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - ExprFormatter::new(f, false).write_expr(self) + ExprPrinter::new(f).write_expr(self) } } @@ -630,14 +633,14 @@ pub enum Pattern { impl fmt::Display for Pattern { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ExprFormatter::new(f, false).write_pattern(self) + ExprPrinter::new(f).write_pattern(self) } } impl Pattern { pub(crate) fn repr(&self) -> EcoString { let mut s = EcoString::new(); - let _ = ExprFormatter::new(&mut s, true).write_pattern(self); + let _ = ExprDescriber::new(&mut s).write_pattern(self); s } } @@ -734,7 +737,7 @@ pub struct SetExpr { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ImportExpr { - pub decl: DeclExpr, + pub decl: Interned, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -902,350 +905,3 @@ impl_internable!( BinInst, ApplyExpr, ); - -struct ExprFormatter<'a, T: fmt::Write> { - f: &'a mut T, - repr: bool, - indent: usize, -} - -impl<'a, T: fmt::Write> ExprFormatter<'a, T> { - fn new(f: &'a mut T, repr: bool) -> Self { - Self { f, repr, indent: 0 } - } - - fn write_decl(&mut self, d: &Decl) -> fmt::Result { - write!(self.f, "{d:?}") - } - - fn write_expr(&mut self, expr: &Expr) -> fmt::Result { - match expr { - Expr::Block(s) => self.write_seq(s), - Expr::Array(a) => self.write_array(a), - Expr::Dict(d) => self.write_dict(d), - Expr::Args(a) => self.write_args(a), - Expr::Pattern(p) => self.write_pattern(p), - Expr::Element(e) => self.write_element(e), - Expr::Unary(u) => self.write_unary(u), - Expr::Binary(b) => self.write_binary(b), - Expr::Apply(a) => self.write_apply(a), - Expr::Func(func) => self.write_func(func), - Expr::Let(l) => self.write_let(l), - Expr::Show(s) => self.write_show(s), - Expr::Set(s) => self.write_set(s), - Expr::Ref(r) => self.write_ref(r), - Expr::ContentRef(r) => self.write_content_ref(r), - Expr::Select(s) => self.write_select(s), - Expr::Import(i) => self.write_import(i), - Expr::Include(i) => self.write_include(i), - Expr::Contextual(c) => self.write_contextual(c), - Expr::Conditional(c) => self.write_conditional(c), - Expr::WhileLoop(w) => self.write_while_loop(w), - Expr::ForLoop(f) => self.write_for_loop(f), - Expr::Type(t) => self.write_type(t), - Expr::Decl(d) => self.write_decl(d), - Expr::Star => self.write_star(), - } - } - - fn write_indent(&mut self) -> fmt::Result { - write!(self.f, "{:indent$}", "", indent = self.indent) - } - - fn write_seq(&mut self, s: &Interned>) -> fmt::Result { - writeln!(self.f, "[")?; - self.indent += 1; - for expr in s.iter() { - self.write_indent()?; - self.write_expr(expr)?; - self.f.write_str(",\n")?; - } - self.indent -= 1; - self.write_indent()?; - write!(self.f, "]") - } - - fn write_array(&mut self, a: &Interned>) -> fmt::Result { - writeln!(self.f, "(")?; - self.indent += 1; - for arg in a.iter() { - self.write_indent()?; - self.write_arg(arg)?; - self.f.write_str(",\n")?; - } - self.indent -= 1; - self.write_indent()?; - write!(self.f, ")") - } - - fn write_dict(&mut self, d: &Interned>) -> fmt::Result { - writeln!(self.f, "(:")?; - self.indent += 1; - for arg in d.iter() { - self.write_indent()?; - self.write_arg(arg)?; - self.f.write_str(",\n")?; - } - self.indent -= 1; - self.write_indent()?; - write!(self.f, ")") - } - - fn write_args(&mut self, a: &Interned>) -> fmt::Result { - writeln!(self.f, "(")?; - for arg in a.iter() { - self.write_indent()?; - self.write_arg(arg)?; - self.f.write_str(",\n")?; - } - self.write_indent()?; - write!(self.f, ")") - } - - fn write_arg(&mut self, a: &ArgExpr) -> fmt::Result { - match a { - ArgExpr::Pos(e) => self.write_expr(e), - ArgExpr::Named(n) => { - let n = n.as_ref(); - write!(self.f, "{n:?}: ")?; - self.write_expr(&n.1) - } - ArgExpr::NamedRt(n) => { - let n = n.as_ref(); - self.write_expr(&n.0)?; - write!(self.f, ": ")?; - self.write_expr(&n.1) - } - ArgExpr::Spread(e) => { - write!(self.f, "..")?; - self.write_expr(e) - } - } - } - - fn write_pattern(&mut self, p: &Pattern) -> fmt::Result { - match p { - Pattern::Expr(e) => self.write_expr(e), - Pattern::Simple(s) => self.write_decl(s), - Pattern::Sig(p) => self.write_pattern_sig(p), - } - } - - fn write_pattern_sig(&mut self, p: &PatternSig) -> fmt::Result { - self.f.write_str("pat(\n")?; - self.indent += 1; - for pos in &p.pos { - self.write_indent()?; - self.write_pattern(pos)?; - self.f.write_str(",\n")?; - } - for (name, pat) in &p.named { - self.write_indent()?; - write!(self.f, "{name:?} = ")?; - self.write_pattern(pat)?; - self.f.write_str(",\n")?; - } - if let Some((k, rest)) = &p.spread_left { - self.write_indent()?; - write!(self.f, "..{k:?}: ")?; - self.write_pattern(rest)?; - self.f.write_str(",\n")?; - } - if let Some((k, rest)) = &p.spread_right { - self.write_indent()?; - write!(self.f, "..{k:?}: ")?; - self.write_pattern(rest)?; - self.f.write_str(",\n")?; - } - self.indent -= 1; - self.write_indent()?; - self.f.write_str(")") - } - - fn write_element(&mut self, e: &Interned) -> fmt::Result { - self.f.write_str("elem(\n")?; - self.indent += 1; - for v in &e.content { - self.write_indent()?; - self.write_expr(v)?; - self.f.write_str(",\n")?; - } - self.indent -= 1; - self.write_indent()?; - self.f.write_str(")") - } - - fn write_unary(&mut self, u: &Interned) -> fmt::Result { - write!(self.f, "un({:?})(", u.op)?; - self.write_expr(&u.lhs)?; - self.f.write_str(")") - } - - fn write_binary(&mut self, b: &Interned) -> fmt::Result { - let [lhs, rhs] = b.operands(); - write!(self.f, "bin({:?})(", b.op)?; - self.write_expr(lhs)?; - self.f.write_str(", ")?; - self.write_expr(rhs)?; - self.f.write_str(")") - } - - fn write_apply(&mut self, a: &Interned) -> fmt::Result { - write!(self.f, "apply(")?; - self.write_expr(&a.callee)?; - self.f.write_str(", ")?; - self.write_expr(&a.args)?; - write!(self.f, ")") - } - - fn write_func(&mut self, func: &Interned) -> fmt::Result { - if self.repr { - return self.write_decl(&func.decl); - } - - write!(self.f, "func[{:?}](", func.decl)?; - self.write_pattern_sig(&func.params)?; - write!(self.f, " = ")?; - self.write_expr(&func.body)?; - write!(self.f, ")") - } - - fn write_let(&mut self, l: &Interned) -> fmt::Result { - write!(self.f, "let(")?; - self.write_pattern(&l.pattern)?; - if let Some(body) = &l.body { - write!(self.f, " = ")?; - self.write_expr(body)?; - } - write!(self.f, ")") - } - - fn write_show(&mut self, s: &Interned) -> fmt::Result { - write!(self.f, "show(")?; - if let Some(selector) = &s.selector { - self.write_expr(selector)?; - self.f.write_str(", ")?; - } - self.write_expr(&s.edit)?; - write!(self.f, ")") - } - - fn write_set(&mut self, s: &Interned) -> fmt::Result { - write!(self.f, "set(")?; - self.write_expr(&s.target)?; - self.f.write_str(", ")?; - self.write_expr(&s.args)?; - if let Some(cond) = &s.cond { - self.f.write_str(", ")?; - self.write_expr(cond)?; - } - write!(self.f, ")") - } - - fn write_ref(&mut self, r: &Interned) -> fmt::Result { - write!(self.f, "ref({:?}", r.decl)?; - if let Some(step) = &r.step { - self.f.write_str(", step = ")?; - self.write_expr(step)?; - } - if let Some(of) = &r.root { - self.f.write_str(", root = ")?; - self.write_expr(of)?; - } - if let Some(val) = &r.val { - write!(self.f, ", val = {val:?}")?; - } - self.f.write_str(")") - } - - fn write_content_ref(&mut self, r: &Interned) -> fmt::Result { - write!(self.f, "content_ref({:?}", r.ident)?; - if let Some(of) = &r.of { - self.f.write_str(", ")?; - self.write_decl(of)?; - } - if let Some(val) = &r.body { - self.write_expr(val)?; - } - self.f.write_str(")") - } - - fn write_select(&mut self, s: &Interned) -> fmt::Result { - write!(self.f, "(")?; - self.write_expr(&s.lhs)?; - self.f.write_str(").")?; - self.write_decl(&s.key) - } - - fn write_import(&mut self, i: &Interned) -> fmt::Result { - self.f.write_str("import(")?; - self.write_decl(&i.decl)?; - self.f.write_str(")") - } - - fn write_include(&mut self, i: &Interned) -> fmt::Result { - self.f.write_str("include(")?; - self.write_expr(&i.source)?; - self.f.write_str(")") - } - - fn write_contextual(&mut self, c: &Interned) -> fmt::Result { - if self.repr { - return self.f.write_str("content"); - } - - self.f.write_str("contextual(")?; - self.write_expr(c)?; - self.f.write_str(")") - } - - fn write_conditional(&mut self, c: &Interned) -> fmt::Result { - if self.repr { - return self.f.write_str("Expr(..)"); - } - - self.f.write_str("if(")?; - self.write_expr(&c.cond)?; - self.f.write_str(", then = ")?; - self.write_expr(&c.then)?; - self.f.write_str(", else = ")?; - self.write_expr(&c.else_)?; - self.f.write_str(")") - } - - fn write_while_loop(&mut self, w: &Interned) -> fmt::Result { - if self.repr { - return self.f.write_str("Expr(..)"); - } - - self.f.write_str("while(")?; - self.write_expr(&w.cond)?; - self.f.write_str(", ")?; - self.write_expr(&w.body)?; - self.f.write_str(")") - } - - fn write_for_loop(&mut self, f: &Interned) -> fmt::Result { - if self.repr { - return self.f.write_str("Expr(..)"); - } - - self.f.write_str("for(")?; - self.write_pattern(&f.pattern)?; - self.f.write_str(", ")?; - self.write_expr(&f.iter)?; - self.f.write_str(", ")?; - self.write_expr(&f.body)?; - self.f.write_str(")") - } - - fn write_type(&mut self, t: &Ty) -> fmt::Result { - let formatted = t.describe(); - let formatted = formatted.as_deref().unwrap_or("any"); - self.f.write_str(formatted) - } - - fn write_star(&mut self) -> fmt::Result { - self.f.write_str("*") - } -} diff --git a/crates/tinymist-query/src/syntax/docs.rs b/crates/tinymist-query/src/syntax/docs.rs index 94a810f6c..ea8d560f7 100644 --- a/crates/tinymist-query/src/syntax/docs.rs +++ b/crates/tinymist-query/src/syntax/docs.rs @@ -1,20 +1,22 @@ use std::{ collections::BTreeMap, + ops::Deref, sync::{LazyLock, OnceLock}, }; +use ecow::eco_format; use typst::foundations::{IntoValue, Module, Str, Type}; use crate::{ adt::snapshot_map::SnapshotMap, analysis::SharedContext, - docs::{ - convert_docs, identify_func_docs, identify_tidy_module_docs, identify_var_docs, - UntypedDefDocs, VarDocsT, - }, + docs::{convert_docs, identify_pat_docs, identify_tidy_module_docs, UntypedDefDocs, VarDocsT}, prelude::*, syntax::{Decl, DefKind}, - ty::{BuiltinTy, Interned, PackageId, SigTy, StrRef, Ty, TypeBounds, TypeVar, TypeVarBounds}, + ty::{ + BuiltinTy, InsTy, Interned, PackageId, SigTy, StrRef, Ty, TypeBounds, TypeVar, + TypeVarBounds, + }, }; use super::DeclExpr; @@ -85,13 +87,11 @@ pub(crate) fn compute_docstring( locals: SnapshotMap::default(), next_id: 0, }; + use DefKind::*; match kind { - DefKind::Function => checker.check_func_docs(docs), - DefKind::Variable => checker.check_var_docs(docs), - DefKind::Module => checker.check_module_docs(docs), - DefKind::Constant => None, - DefKind::Struct => None, - DefKind::Reference => None, + Function | Variable => checker.check_pat_docs(docs), + Module => checker.check_module_docs(docs), + Constant | Struct | Reference => None, } } @@ -105,62 +105,88 @@ struct DocsChecker<'a> { next_id: u32, } +static EMPTY_MODULE: LazyLock = + LazyLock::new(|| Module::new("stub", typst::foundations::Scope::new())); + impl<'a> DocsChecker<'a> { - pub fn check_func_docs(mut self, docs: String) -> Option { - let converted = convert_docs(self.ctx, &docs).ok()?; - let converted = identify_func_docs(&converted).ok()?; - let module = self.ctx.module_by_str(docs)?; + pub fn check_pat_docs(mut self, docs: String) -> Option { + let converted = + convert_docs(self.ctx, &docs).and_then(|converted| identify_pat_docs(&converted)); + + let converted = match Self::fallback_docs(converted, &docs) { + Ok(c) => c, + Err(e) => return Some(e), + }; + + let module = self.ctx.module_by_str(docs); + let module = module.as_ref().unwrap_or(EMPTY_MODULE.deref()); let mut params = BTreeMap::new(); for param in converted.params.into_iter() { params.insert( param.name.into(), VarDoc { - docs: param.docs, - ty: self.check_type_strings(&module, ¶m.types), + docs: self.ctx.remove_html(param.docs), + ty: self.check_type_strings(module, ¶m.types), }, ); } let res_ty = converted .return_ty - .and_then(|ty| self.check_type_strings(&module, &ty)); + .and_then(|ty| self.check_type_strings(module, &ty)); Some(DocString { - docs: Some(converted.docs), + docs: Some(self.ctx.remove_html(converted.docs)), var_bounds: self.vars, vars: params, res_ty, }) } - pub fn check_var_docs(mut self, docs: String) -> Option { - let converted = convert_docs(self.ctx, &docs).ok()?; - let converted = identify_var_docs(converted).ok()?; - let module = self.ctx.module_by_str(docs)?; + pub fn check_module_docs(self, docs: String) -> Option { + let converted = convert_docs(self.ctx, &docs).and_then(identify_tidy_module_docs); - let res_ty = converted - .return_ty - .and_then(|ty| self.check_type_strings(&module, &ty.0)); + let converted = match Self::fallback_docs(converted, &docs) { + Ok(c) => c, + Err(e) => return Some(e), + }; Some(DocString { - docs: Some(converted.docs), + docs: Some(self.ctx.remove_html(converted.docs)), var_bounds: self.vars, vars: BTreeMap::new(), - res_ty, + res_ty: None, }) } - pub fn check_module_docs(self, docs: String) -> Option { - let converted = convert_docs(self.ctx, &docs).ok()?; - let converted = identify_tidy_module_docs(converted).ok()?; - - Some(DocString { - docs: Some(converted.docs), - var_bounds: self.vars, - vars: BTreeMap::new(), - res_ty: None, - }) + fn fallback_docs(converted: Result, docs: &str) -> Result { + match converted { + Ok(c) => Ok(c), + Err(e) => { + let e = e.replace("`", "\\`"); + let max_consecutive_backticks = docs + .chars() + .fold((0, 0), |(max, count), c| { + if c == '`' { + (max.max(count + 1), count + 1) + } else { + (max, 0) + } + }) + .0; + let backticks = "`".repeat((max_consecutive_backticks + 1).max(3)); + let fallback_docs = eco_format!( + "```\nfailed to parse docs: {e}\n```\n\n{backticks}typ\n{docs}\n{backticks}\n" + ); + Err(DocString { + docs: Some(fallback_docs), + var_bounds: HashMap::new(), + vars: BTreeMap::new(), + res_ty: None, + }) + } + } } fn generate_var(&mut self, name: StrRef) -> Ty { @@ -275,6 +301,30 @@ impl<'a> DocsChecker<'a> { log::debug!("check doc type expr: {s:?}"); match s { ast::Expr::Ident(i) => self.check_type_ident(m, i.get().as_str()), + ast::Expr::None(_) + | ast::Expr::Auto(_) + | ast::Expr::Bool(..) + | ast::Expr::Int(..) + | ast::Expr::Float(..) + | ast::Expr::Numeric(..) + | ast::Expr::Str(..) => SharedContext::const_eval(s).map(|v| Ty::Value(InsTy::new(v))), + ast::Expr::Binary(b) => { + let mut components = Vec::with_capacity(2); + components.push(self.check_type_expr(m, b.lhs())?); + + let mut expr = b.rhs(); + while let ast::Expr::Binary(b) = expr { + if b.op() != ast::BinOp::Or { + break; + } + + components.push(self.check_type_expr(m, b.lhs())?); + expr = b.rhs(); + } + + components.push(self.check_type_expr(m, expr)?); + Some(Ty::from_types(components.into_iter())) + } ast::Expr::FuncCall(c) => match c.callee() { ast::Expr::Ident(i) => { let name = i.get().as_str(); diff --git a/crates/tinymist-query/src/syntax/expr.rs b/crates/tinymist-query/src/syntax/expr.rs index 429bded1f..5260f9a12 100644 --- a/crates/tinymist-query/src/syntax/expr.rs +++ b/crates/tinymist-query/src/syntax/expr.rs @@ -161,6 +161,14 @@ impl std::hash::Hash for ExprInfo { } impl ExprInfo { + pub fn get_def(&self, decl: &Interned) -> Option { + if decl.is_def() { + return Some(Expr::Decl(decl.clone())); + } + let resolved = self.resolves.get(&decl.span())?; + Some(Expr::Ref(resolved.clone())) + } + pub fn get_refs( &self, decl: Interned, @@ -612,7 +620,7 @@ impl<'a> ExprWorker<'a> { .insert_mut(decl.name().clone(), Expr::Ref(mod_ref.clone())); } - self.resolve_as(mod_ref); + self.resolve_as(mod_ref.clone()); let fid = mod_expr.as_ref().and_then(|mod_expr| match mod_expr { Expr::Type(Ty::Value(v)) => match &v.val { @@ -678,7 +686,7 @@ impl<'a> ExprWorker<'a> { } }; - Expr::Import(ImportExpr { decl }.into()) + Expr::Import(ImportExpr { decl: mod_ref }.into()) } fn check_import(&mut self, source: ast::Expr, is_import: bool) -> Option { @@ -1180,3 +1188,12 @@ fn extract_ref(step: Option) -> (Option, Option) { fn none_expr() -> Expr { Expr::Type(Ty::Builtin(BuiltinTy::None)) } + +#[cfg(test)] +mod tests { + #[test] + fn test_expr_size() { + use super::*; + assert!(size_of::() <= size_of::() * 2); + } +} diff --git a/crates/tinymist-query/src/syntax/index.rs b/crates/tinymist-query/src/syntax/index.rs new file mode 100644 index 000000000..6fb19b12c --- /dev/null +++ b/crates/tinymist-query/src/syntax/index.rs @@ -0,0 +1,66 @@ +use std::str::FromStr; + +use reflexo_typst::package::PackageSpec; +use rustc_hash::FxHashSet; + +use crate::{adt::interner::Interned, prelude::*}; + +#[derive(Default)] +pub struct IndexInfo { + pub(crate) paths: FxHashSet>, + pub(crate) packages: FxHashSet, + pub(crate) identifiers: FxHashSet>, +} + +#[comemo::memoize] +pub fn get_index_info(src: &Source) -> Arc { + let root = src.root(); + let mut worker = IndexWorker { + info: IndexInfo::default(), + }; + worker.visit(root); + Arc::new(worker.info) +} + +struct IndexWorker { + info: IndexInfo, +} + +impl IndexWorker { + fn visit(&mut self, node: &SyntaxNode) { + match node.cast::() { + Some(ast::Expr::Str(s)) => { + if s.to_untyped().text().len() > 65536 { + // skip long strings + return; + } + let s = s.get(); + + if s.starts_with('@') { + let pkg_spec = PackageSpec::from_str(&s).ok(); + if let Some(pkg_spec) = pkg_spec { + self.info.identifiers.insert(pkg_spec.name.clone().into()); + self.info.packages.insert(pkg_spec); + } + return; + } + let p = Path::new(s.as_str()); + let name = p.file_name().unwrap_or_default().to_str(); + if let Some(name) = name { + self.info.paths.insert(name.into()); + } + } + Some(ast::Expr::MathIdent(i)) => { + self.info.identifiers.insert(i.get().into()); + } + Some(ast::Expr::Ident(i)) => { + self.info.identifiers.insert(i.get().into()); + } + _ => {} + } + + for child in node.children() { + self.visit(child); + } + } +} diff --git a/crates/tinymist-query/src/syntax/lexical_hierarchy.rs b/crates/tinymist-query/src/syntax/lexical_hierarchy.rs index 86a1fe35f..d88488c7d 100644 --- a/crates/tinymist-query/src/syntax/lexical_hierarchy.rs +++ b/crates/tinymist-query/src/syntax/lexical_hierarchy.rs @@ -2,7 +2,6 @@ use std::ops::{Deref, Range}; use anyhow::anyhow; use ecow::{eco_vec, EcoString, EcoVec}; -use log::info; use lsp_types::SymbolKind; use serde::{Deserialize, Serialize}; use typst::syntax::{ @@ -42,8 +41,7 @@ pub(crate) fn get_lexical_hierarchy( worker.symbreak(); } - let e = std::time::Instant::now(); - info!("lexical hierarchy analysis took {:?}", e - b); + log::debug!("lexical hierarchy analysis took {:?}", b.elapsed()); res.map(|_| worker.stack.pop().unwrap().1) } diff --git a/crates/tinymist-query/src/syntax/matcher.rs b/crates/tinymist-query/src/syntax/matcher.rs index 635233ad9..0b622b459 100644 --- a/crates/tinymist-query/src/syntax/matcher.rs +++ b/crates/tinymist-query/src/syntax/matcher.rs @@ -1,4 +1,4 @@ -use serde::Serialize; +use serde::{Deserialize, Serialize}; use typst::foundations::{Func, ParamInfo}; use crate::prelude::*; @@ -37,10 +37,156 @@ pub(crate) fn find_expr_in_import(mut node: LinkedNode) -> Option { None } -pub fn node_ancestors<'a>(node: &'a LinkedNode<'a>) -> impl Iterator> { +pub fn node_ancestors<'a, 'b>( + node: &'b LinkedNode<'a>, +) -> impl Iterator> { std::iter::successors(Some(node), |node| node.parent()) } +pub enum DecenderItem<'a> { + Sibling(&'a LinkedNode<'a>), + Parent(&'a LinkedNode<'a>, &'a LinkedNode<'a>), +} + +impl<'a> DecenderItem<'a> { + pub fn node(&self) -> &'a LinkedNode<'a> { + match self { + DecenderItem::Sibling(node) => node, + DecenderItem::Parent(node, _) => node, + } + } +} + +/// Find the decender nodes starting from the given position. +pub fn node_decenders( + node: LinkedNode, + mut recv: impl FnMut(DecenderItem) -> Option, +) -> Option { + let mut ancestor = Some(node); + while let Some(node) = &ancestor { + let mut sibling = Some(node.clone()); + while let Some(node) = &sibling { + if let Some(v) = recv(DecenderItem::Sibling(node)) { + return Some(v); + } + + sibling = node.prev_sibling(); + } + + if let Some(parent) = node.parent() { + if let Some(v) = recv(DecenderItem::Parent(parent, node)) { + return Some(v); + } + + ancestor = Some(parent.clone()); + continue; + } + + break; + } + + None +} + +pub enum DescentDecl<'a> { + Ident(ast::Ident<'a>), + ImportSource(ast::Expr<'a>), + ImportAll(ast::ModuleImport<'a>), +} + +/// Find the descending decls starting from the given position. +pub fn descending_decls( + node: LinkedNode, + mut recv: impl FnMut(DescentDecl) -> Option, +) -> Option { + node_decenders(node, |node| { + match (&node, node.node().cast::()?) { + (DecenderItem::Sibling(..), ast::Expr::Let(lb)) => { + for ident in lb.kind().bindings() { + if let Some(t) = recv(DescentDecl::Ident(ident)) { + return Some(t); + } + } + } + (DecenderItem::Sibling(..), ast::Expr::Import(mi)) => { + // import items + match mi.imports() { + Some(ast::Imports::Wildcard) => { + if let Some(t) = recv(DescentDecl::ImportAll(mi)) { + return Some(t); + } + } + Some(ast::Imports::Items(e)) => { + for item in e.iter() { + if let Some(t) = recv(DescentDecl::Ident(item.bound_name())) { + return Some(t); + } + } + } + _ => {} + } + + // import it self + if let Some(new_name) = mi.new_name() { + if let Some(t) = recv(DescentDecl::Ident(new_name)) { + return Some(t); + } + } else if mi.imports().is_none() { + if let Some(t) = recv(DescentDecl::ImportSource(mi.source())) { + return Some(t); + } + } + } + (DecenderItem::Parent(node, child), ast::Expr::For(f)) => { + let body = node.find(f.body().span()); + let in_body = body.is_some_and(|n| n.find(child.span()).is_some()); + if !in_body { + return None; + } + + for ident in f.pattern().bindings() { + if let Some(t) = recv(DescentDecl::Ident(ident)) { + return Some(t); + } + } + } + (DecenderItem::Parent(node, child), ast::Expr::Closure(c)) => { + let body = node.find(c.body().span()); + let in_body = body.is_some_and(|n| n.find(child.span()).is_some()); + if !in_body { + return None; + } + + for param in c.params().children() { + match param { + ast::Param::Pos(pattern) => { + for ident in pattern.bindings() { + if let Some(t) = recv(DescentDecl::Ident(ident)) { + return Some(t); + } + } + } + ast::Param::Named(n) => { + if let Some(t) = recv(DescentDecl::Ident(n.name())) { + return Some(t); + } + } + ast::Param::Spread(s) => { + if let Some(sink_ident) = s.sink_ident() { + if let Some(t) = recv(DescentDecl::Ident(sink_ident)) { + return Some(t); + } + } + } + } + } + } + _ => {} + }; + None + }) +} + fn is_mark(sk: SyntaxKind) -> bool { use SyntaxKind::*; matches!( @@ -93,7 +239,7 @@ fn can_be_ident(node: &SyntaxNode) -> bool { } /// A mode in which a text document is interpreted. -#[derive(Debug, Clone, Copy, Serialize)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub enum InterpretMode { /// The position is in a comment. @@ -110,7 +256,7 @@ pub enum InterpretMode { Math, } -pub(crate) fn interpret_mode_at(k: SyntaxKind) -> Option { +pub(crate) fn interpret_mode_at_kind(k: SyntaxKind) -> Option { use SyntaxKind::*; Some(match k { LineComment | BlockComment => InterpretMode::Comment, @@ -119,18 +265,16 @@ pub(crate) fn interpret_mode_at(k: SyntaxKind) -> Option { CodeBlock | Code => InterpretMode::Code, ContentBlock | Markup => InterpretMode::Markup, Equation | Math => InterpretMode::Math, - Ident | FieldAccess | Bool | Int | Float | Numeric | Space | Linebreak | Parbreak - | Escape | Shorthand | SmartQuote | RawLang | RawDelim | RawTrimmed | Hash | LeftBrace - | RightBrace | LeftBracket | RightBracket | LeftParen | RightParen | Comma | Semicolon - | Colon | Star | Underscore | Dollar | Plus | Minus | Slash | Hat | Prime | Dot | Eq - | EqEq | ExclEq | Lt | LtEq | Gt | GtEq | PlusEq | HyphEq | StarEq | SlashEq | Dots - | Arrow | Root | Not | And | Or | None | Auto | As | Named | Keyed | Error | End => { + Label | Text | Ident | FieldAccess | Bool | Int | Float | Numeric | Space | Linebreak + | Parbreak | Escape | Shorthand | SmartQuote | RawLang | RawDelim | RawTrimmed | Hash + | LeftBrace | RightBrace | LeftBracket | RightBracket | LeftParen | RightParen | Comma + | Semicolon | Colon | Star | Underscore | Dollar | Plus | Minus | Slash | Hat | Prime + | Dot | Eq | EqEq | ExclEq | Lt | LtEq | Gt | GtEq | PlusEq | HyphEq | StarEq | SlashEq + | Dots | Arrow | Root | Not | And | Or | None | Auto | As | Named | Keyed | Error | End => { return Option::None } - Text | Strong | Emph | Link | Label | Ref | RefMarker | Heading | HeadingMarker - | ListItem | ListMarker | EnumItem | EnumMarker | TermItem | TermMarker => { - InterpretMode::Markup - } + Strong | Emph | Link | Ref | RefMarker | Heading | HeadingMarker | ListItem + | ListMarker | EnumItem | EnumMarker | TermItem | TermMarker => InterpretMode::Markup, MathIdent | MathAlignPoint | MathDelimited | MathAttach | MathPrimes | MathFrac | MathRoot | MathShorthand => InterpretMode::Math, Let | Set | Show | Context | If | Else | For | In | While | Break | Continue | Return @@ -142,6 +286,21 @@ pub(crate) fn interpret_mode_at(k: SyntaxKind) -> Option { }) } +pub(crate) fn interpret_mode_at(mut leaf: Option<&LinkedNode>) -> InterpretMode { + loop { + log::debug!("leaf for context: {leaf:?}"); + if let Some(t) = leaf { + if let Some(mode) = interpret_mode_at_kind(t.kind()) { + break mode; + } + + leaf = t.parent(); + } else { + break InterpretMode::Markup; + } + } +} + #[derive(Debug, Clone)] pub enum DerefTarget<'a> { Label(LinkedNode<'a>), @@ -437,7 +596,7 @@ pub fn get_check_target_by_context<'a>( fn possible_in_code_trivia(sk: SyntaxKind) -> bool { !matches!( - interpret_mode_at(sk), + interpret_mode_at_kind(sk), Some(InterpretMode::Markup | InterpretMode::Math | InterpretMode::Comment) ) } @@ -458,22 +617,7 @@ pub fn get_check_target(node: LinkedNode) -> Option> { let deref_node = match deref_target { DerefTarget::Callee(callee) => { - let parent = callee.parent()?; - let args = match parent.cast::() { - Some(ast::Expr::FuncCall(call)) => call.args(), - Some(ast::Expr::Set(set)) => set.args(), - _ => return None, - }; - let args = parent.find(args.span())?; - - let is_set = parent.kind() == SyntaxKind::SetRule; - let target = get_param_target(args.clone(), node, ParamKind::Call)?; - return Some(CheckTarget::Param { - callee, - args, - target, - is_set, - }); + return get_callee_target(callee, node); } DerefTarget::ImportPath(node) | DerefTarget::IncludePath(node) => { return Some(CheckTarget::Normal(node)); @@ -481,7 +625,7 @@ pub fn get_check_target(node: LinkedNode) -> Option> { deref_target => deref_target.node().clone(), }; - let Some(mut node_parent) = node.parent() else { + let Some(mut node_parent) = node.parent().cloned() else { return Some(CheckTarget::Normal(node)); }; @@ -489,10 +633,37 @@ pub fn get_check_target(node: LinkedNode) -> Option> { let Some(p) = node_parent.parent() else { return Some(CheckTarget::Normal(node)); }; - node_parent = p; + node_parent = p.clone(); } match node_parent.kind() { + SyntaxKind::Args => { + let callee = node_ancestors(&node_parent).find_map(|p| { + let s = match p.cast::()? { + ast::Expr::FuncCall(call) => call.callee().span(), + ast::Expr::Set(set) => set.target().span(), + _ => return None, + }; + p.find(s) + })?; + + let node = match node.kind() { + SyntaxKind::Ident + if matches!( + node.parent_kind().zip(node.next_sibling_kind()), + Some((SyntaxKind::Named, SyntaxKind::Colon)) + ) => + { + node + } + _ if matches!(node.parent_kind(), Some(SyntaxKind::Named)) => { + node.parent().cloned()? + } + _ => node, + }; + + get_callee_target(callee, node) + } SyntaxKind::Array | SyntaxKind::Dict => { let target = get_param_target( node_parent.clone(), @@ -519,6 +690,25 @@ pub fn get_check_target(node: LinkedNode) -> Option> { } } +fn get_callee_target<'a>(callee: LinkedNode<'a>, node: LinkedNode<'a>) -> Option> { + let parent = callee.parent()?; + let args = match parent.cast::() { + Some(ast::Expr::FuncCall(call)) => call.args(), + Some(ast::Expr::Set(set)) => set.args(), + _ => return None, + }; + let args = parent.find(args.span())?; + + let is_set = parent.kind() == SyntaxKind::SetRule; + let target = get_param_target(args.clone(), node, ParamKind::Call)?; + Some(CheckTarget::Param { + callee, + args, + target, + is_set, + }) +} + fn get_param_target<'a>( args_node: LinkedNode<'a>, mut node: LinkedNode<'a>, @@ -716,7 +906,7 @@ mod tests { assert_snapshot!(map_deref(r#"#let x = 1 Text = Heading #let y = 2; -== Heading"#).trim(), @r###" +== Heading"#).trim(), @r" #let x = 1 nnnnvvnnn Text @@ -724,11 +914,11 @@ Text = Heading #let y = 2; nnnnvvnnn == Heading - "###); - assert_snapshot!(map_deref(r#"#let f(x);"#).trim(), @r###" + "); + assert_snapshot!(map_deref(r#"#let f(x);"#).trim(), @r" #let f(x); nnnnv v - "###); + "); } #[test] @@ -736,7 +926,7 @@ Text assert_snapshot!(map_check(r#"#let x = 1 Text = Heading #let y = 2; -== Heading"#).trim(), @r###" +== Heading"#).trim(), @r" #let x = 1 nnnnnnnnn Text @@ -744,36 +934,36 @@ Text = Heading #let y = 2; nnnnnnnnn == Heading - "###); - assert_snapshot!(map_check(r#"#let f(x);"#).trim(), @r###" + "); + assert_snapshot!(map_check(r#"#let f(x);"#).trim(), @r" #let f(x); nnnnn n - "###); - assert_snapshot!(map_check(r#"#f(1, 2) Test"#).trim(), @r###" + "); + assert_snapshot!(map_check(r#"#f(1, 2) Test"#).trim(), @r" #f(1, 2) Test - npnppnp - "###); - assert_snapshot!(map_check(r#"#() Test"#).trim(), @r###" + npppppp + "); + assert_snapshot!(map_check(r#"#() Test"#).trim(), @r" #() Test ee - "###); - assert_snapshot!(map_check(r#"#(1) Test"#).trim(), @r###" + "); + assert_snapshot!(map_check(r#"#(1) Test"#).trim(), @r" #(1) Test PPP - "###); - assert_snapshot!(map_check(r#"#(a: 1) Test"#).trim(), @r###" + "); + assert_snapshot!(map_check(r#"#(a: 1) Test"#).trim(), @r" #(a: 1) Test eeeeee - "###); - assert_snapshot!(map_check(r#"#(1, 2) Test"#).trim(), @r###" + "); + assert_snapshot!(map_check(r#"#(1, 2) Test"#).trim(), @r" #(1, 2) Test eeeeee - "###); + "); assert_snapshot!(map_check(r#"#(1, 2) - Test"#).trim(), @r###" + Test"#).trim(), @r" #(1, 2) eeeeee Test - "###); + "); } } diff --git a/crates/tinymist-query/src/syntax/mod.rs b/crates/tinymist-query/src/syntax/mod.rs index 9a96e1d8a..a033d3aae 100644 --- a/crates/tinymist-query/src/syntax/mod.rs +++ b/crates/tinymist-query/src/syntax/mod.rs @@ -20,3 +20,7 @@ pub(crate) mod docs; pub use docs::*; pub(crate) mod def; pub use def::*; +pub(crate) mod repr; +use repr::*; +pub(crate) mod index; +pub use index::*; diff --git a/crates/tinymist-query/src/syntax/repr.rs b/crates/tinymist-query/src/syntax/repr.rs new file mode 100644 index 000000000..c13655b8e --- /dev/null +++ b/crates/tinymist-query/src/syntax/repr.rs @@ -0,0 +1,607 @@ +use core::fmt; + +use super::def::*; +use crate::ty::{Interned, Ty}; + +pub(in crate::syntax) struct ExprPrinter<'a, T: fmt::Write> { + f: &'a mut T, + indent: usize, +} + +impl<'a, T: fmt::Write> ExprPrinter<'a, T> { + pub fn new(f: &'a mut T) -> Self { + Self { f, indent: 0 } + } + + pub fn write_decl(&mut self, d: &Decl) -> fmt::Result { + write!(self.f, "{d:?}") + } + + pub fn write_expr(&mut self, expr: &Expr) -> fmt::Result { + match expr { + Expr::Block(s) => self.write_seq(s), + Expr::Array(a) => self.write_array(a), + Expr::Dict(d) => self.write_dict(d), + Expr::Args(a) => self.write_args(a), + Expr::Pattern(p) => self.write_pattern(p), + Expr::Element(e) => self.write_element(e), + Expr::Unary(u) => self.write_unary(u), + Expr::Binary(b) => self.write_binary(b), + Expr::Apply(a) => self.write_apply(a), + Expr::Func(func) => self.write_func(func), + Expr::Let(l) => self.write_let(l), + Expr::Show(s) => self.write_show(s), + Expr::Set(s) => self.write_set(s), + Expr::Ref(r) => self.write_ref(r), + Expr::ContentRef(r) => self.write_content_ref(r), + Expr::Select(s) => self.write_select(s), + Expr::Import(i) => self.write_import(i), + Expr::Include(i) => self.write_include(i), + Expr::Contextual(c) => self.write_contextual(c), + Expr::Conditional(c) => self.write_conditional(c), + Expr::WhileLoop(w) => self.write_while_loop(w), + Expr::ForLoop(f) => self.write_for_loop(f), + Expr::Type(t) => self.write_type(t), + Expr::Decl(d) => self.write_decl(d), + Expr::Star => self.write_star(), + } + } + + fn write_indent(&mut self) -> fmt::Result { + write!(self.f, "{:indent$}", "", indent = self.indent) + } + + fn write_seq(&mut self, s: &Interned>) -> fmt::Result { + writeln!(self.f, "[")?; + self.indent += 1; + for expr in s.iter() { + self.write_indent()?; + self.write_expr(expr)?; + self.f.write_str(",\n")?; + } + self.indent -= 1; + self.write_indent()?; + write!(self.f, "]") + } + + fn write_array(&mut self, a: &Interned>) -> fmt::Result { + writeln!(self.f, "(")?; + self.indent += 1; + for arg in a.iter() { + self.write_indent()?; + self.write_arg(arg)?; + self.f.write_str(",\n")?; + } + self.indent -= 1; + self.write_indent()?; + write!(self.f, ")") + } + + fn write_dict(&mut self, d: &Interned>) -> fmt::Result { + writeln!(self.f, "(:")?; + self.indent += 1; + for arg in d.iter() { + self.write_indent()?; + self.write_arg(arg)?; + self.f.write_str(",\n")?; + } + self.indent -= 1; + self.write_indent()?; + write!(self.f, ")") + } + + fn write_args(&mut self, a: &Interned>) -> fmt::Result { + writeln!(self.f, "(")?; + for arg in a.iter() { + self.write_indent()?; + self.write_arg(arg)?; + self.f.write_str(",\n")?; + } + self.write_indent()?; + write!(self.f, ")") + } + + fn write_arg(&mut self, a: &ArgExpr) -> fmt::Result { + match a { + ArgExpr::Pos(e) => self.write_expr(e), + ArgExpr::Named(n) => { + let (k, v) = n.as_ref(); + write!(self.f, "{k:?}: ")?; + self.write_expr(v) + } + ArgExpr::NamedRt(n) => { + let n = n.as_ref(); + self.write_expr(&n.0)?; + write!(self.f, ": ")?; + self.write_expr(&n.1) + } + ArgExpr::Spread(e) => { + write!(self.f, "..")?; + self.write_expr(e) + } + } + } + + pub fn write_pattern(&mut self, p: &Pattern) -> fmt::Result { + match p { + Pattern::Expr(e) => self.write_expr(e), + Pattern::Simple(s) => self.write_decl(s), + Pattern::Sig(p) => self.write_pattern_sig(p), + } + } + + fn write_pattern_sig(&mut self, p: &PatternSig) -> fmt::Result { + self.f.write_str("pat(\n")?; + self.indent += 1; + for pos in &p.pos { + self.write_indent()?; + self.write_pattern(pos)?; + self.f.write_str(",\n")?; + } + for (name, pat) in &p.named { + self.write_indent()?; + write!(self.f, "{name:?} = ")?; + self.write_pattern(pat)?; + self.f.write_str(",\n")?; + } + if let Some((k, rest)) = &p.spread_left { + self.write_indent()?; + write!(self.f, "..{k:?}: ")?; + self.write_pattern(rest)?; + self.f.write_str(",\n")?; + } + if let Some((k, rest)) = &p.spread_right { + self.write_indent()?; + write!(self.f, "..{k:?}: ")?; + self.write_pattern(rest)?; + self.f.write_str(",\n")?; + } + self.indent -= 1; + self.write_indent()?; + self.f.write_str(")") + } + + fn write_element(&mut self, e: &Interned) -> fmt::Result { + self.f.write_str("elem(\n")?; + self.indent += 1; + for v in &e.content { + self.write_indent()?; + self.write_expr(v)?; + self.f.write_str(",\n")?; + } + self.indent -= 1; + self.write_indent()?; + self.f.write_str(")") + } + + fn write_unary(&mut self, u: &Interned) -> fmt::Result { + write!(self.f, "un({:?})(", u.op)?; + self.write_expr(&u.lhs)?; + self.f.write_str(")") + } + + fn write_binary(&mut self, b: &Interned) -> fmt::Result { + let [lhs, rhs] = b.operands(); + write!(self.f, "bin({:?})(", b.op)?; + self.write_expr(lhs)?; + self.f.write_str(", ")?; + self.write_expr(rhs)?; + self.f.write_str(")") + } + + fn write_apply(&mut self, a: &Interned) -> fmt::Result { + write!(self.f, "apply(")?; + self.write_expr(&a.callee)?; + self.f.write_str(", ")?; + self.write_expr(&a.args)?; + write!(self.f, ")") + } + + fn write_func(&mut self, func: &Interned) -> fmt::Result { + write!(self.f, "func[{:?}](", func.decl)?; + self.write_pattern_sig(&func.params)?; + write!(self.f, " = ")?; + self.write_expr(&func.body)?; + write!(self.f, ")") + } + + fn write_let(&mut self, l: &Interned) -> fmt::Result { + write!(self.f, "let(")?; + self.write_pattern(&l.pattern)?; + if let Some(body) = &l.body { + write!(self.f, " = ")?; + self.write_expr(body)?; + } + write!(self.f, ")") + } + + fn write_show(&mut self, s: &Interned) -> fmt::Result { + write!(self.f, "show(")?; + if let Some(selector) = &s.selector { + self.write_expr(selector)?; + self.f.write_str(", ")?; + } + self.write_expr(&s.edit)?; + write!(self.f, ")") + } + + fn write_set(&mut self, s: &Interned) -> fmt::Result { + write!(self.f, "set(")?; + self.write_expr(&s.target)?; + self.f.write_str(", ")?; + self.write_expr(&s.args)?; + if let Some(cond) = &s.cond { + self.f.write_str(", ")?; + self.write_expr(cond)?; + } + write!(self.f, ")") + } + + fn write_ref(&mut self, r: &Interned) -> fmt::Result { + write!(self.f, "ref({:?}", r.decl)?; + if let Some(step) = &r.step { + self.f.write_str(", step = ")?; + self.write_expr(step)?; + } + if let Some(of) = &r.root { + self.f.write_str(", root = ")?; + self.write_expr(of)?; + } + if let Some(val) = &r.val { + write!(self.f, ", val = {val:?}")?; + } + self.f.write_str(")") + } + + fn write_content_ref(&mut self, r: &Interned) -> fmt::Result { + write!(self.f, "content_ref({:?}", r.ident)?; + if let Some(of) = &r.of { + self.f.write_str(", ")?; + self.write_decl(of)?; + } + if let Some(val) = &r.body { + self.write_expr(val)?; + } + self.f.write_str(")") + } + + fn write_select(&mut self, s: &Interned) -> fmt::Result { + write!(self.f, "(")?; + self.write_expr(&s.lhs)?; + self.f.write_str(").")?; + self.write_decl(&s.key) + } + + fn write_import(&mut self, i: &Interned) -> fmt::Result { + self.f.write_str("import(")?; + self.write_decl(&i.decl.decl)?; + self.f.write_str(")") + } + + fn write_include(&mut self, i: &Interned) -> fmt::Result { + self.f.write_str("include(")?; + self.write_expr(&i.source)?; + self.f.write_str(")") + } + + fn write_contextual(&mut self, c: &Interned) -> fmt::Result { + self.f.write_str("contextual(")?; + self.write_expr(c)?; + self.f.write_str(")") + } + + fn write_conditional(&mut self, c: &Interned) -> fmt::Result { + self.f.write_str("if(")?; + self.write_expr(&c.cond)?; + self.f.write_str(", then = ")?; + self.write_expr(&c.then)?; + self.f.write_str(", else = ")?; + self.write_expr(&c.else_)?; + self.f.write_str(")") + } + + fn write_while_loop(&mut self, w: &Interned) -> fmt::Result { + self.f.write_str("while(")?; + self.write_expr(&w.cond)?; + self.f.write_str(", ")?; + self.write_expr(&w.body)?; + self.f.write_str(")") + } + + fn write_for_loop(&mut self, f: &Interned) -> fmt::Result { + self.f.write_str("for(")?; + self.write_pattern(&f.pattern)?; + self.f.write_str(", ")?; + self.write_expr(&f.iter)?; + self.f.write_str(", ")?; + self.write_expr(&f.body)?; + self.f.write_str(")") + } + + fn write_type(&mut self, t: &Ty) -> fmt::Result { + let formatted = t.describe(); + let formatted = formatted.as_deref().unwrap_or("any"); + self.f.write_str(formatted) + } + + fn write_star(&mut self) -> fmt::Result { + self.f.write_str("*") + } +} + +pub(in crate::syntax) struct ExprDescriber<'a, T: fmt::Write> { + f: &'a mut T, + indent: usize, +} + +impl<'a, T: fmt::Write> ExprDescriber<'a, T> { + pub fn new(f: &'a mut T) -> Self { + Self { f, indent: 0 } + } + + pub fn write_decl(&mut self, d: &Decl) -> fmt::Result { + use DefKind::*; + let shorter = matches!(d.kind(), Function | Variable | Module); + if shorter && !d.name().is_empty() { + return write!(self.f, "{}", d.name()); + } + + write!(self.f, "{d:?}") + } + + pub fn write_expr(&mut self, expr: &Expr) -> fmt::Result { + match expr { + Expr::Block(..) => self.f.write_str("Expr(..)"), + Expr::Array(a) => self.write_array(a), + Expr::Dict(d) => self.write_dict(d), + Expr::Args(a) => self.write_args(a), + Expr::Pattern(p) => self.write_pattern(p), + Expr::Element(e) => self.write_element(e), + Expr::Unary(u) => self.write_unary(u), + Expr::Binary(b) => self.write_binary(b), + Expr::Apply(a) => self.write_apply(a), + Expr::Func(func) => self.write_func(func), + Expr::Ref(r) => self.write_ref(r), + Expr::ContentRef(r) => self.write_content_ref(r), + Expr::Select(s) => self.write_select(s), + Expr::Import(i) => self.write_import(i), + Expr::Include(i) => self.write_include(i), + Expr::Contextual(..) => self.f.write_str("content"), + Expr::Let(..) | Expr::Show(..) | Expr::Set(..) => self.f.write_str("Expr(..)"), + Expr::Conditional(..) | Expr::WhileLoop(..) | Expr::ForLoop(..) => { + self.f.write_str("Expr(..)") + } + Expr::Type(t) => self.write_type(t), + Expr::Decl(d) => self.write_decl(d), + Expr::Star => self.f.write_str("*"), + } + } + + fn write_indent(&mut self) -> fmt::Result { + write!(self.f, "{:indent$}", "", indent = self.indent) + } + + fn write_array(&mut self, a: &Interned>) -> fmt::Result { + if a.len() <= 1 { + self.f.write_char('(')?; + if let Some(arg) = a.first() { + self.write_arg(arg)?; + self.f.write_str(",")? + } + return self.f.write_str(")"); + } + + writeln!(self.f, "(")?; + self.indent += 1; + for arg in a.iter() { + self.write_indent()?; + self.write_arg(arg)?; + self.f.write_str(",\n")?; + } + self.indent -= 1; + self.write_indent()?; + write!(self.f, ")") + } + + fn write_dict(&mut self, d: &Interned>) -> fmt::Result { + if d.len() <= 1 { + self.f.write_char('(')?; + if let Some(arg) = d.first() { + self.write_arg(arg)?; + } else { + self.f.write_str(":")? + } + return self.f.write_str(")"); + } + + writeln!(self.f, "(:")?; + self.indent += 1; + for arg in d.iter() { + self.write_indent()?; + self.write_arg(arg)?; + self.f.write_str(",\n")?; + } + self.indent -= 1; + self.write_indent()?; + write!(self.f, ")") + } + + fn write_args(&mut self, a: &Interned>) -> fmt::Result { + writeln!(self.f, "(")?; + for arg in a.iter() { + self.write_indent()?; + self.write_arg(arg)?; + self.f.write_str(",\n")?; + } + self.write_indent()?; + write!(self.f, ")") + } + + fn write_arg(&mut self, a: &ArgExpr) -> fmt::Result { + match a { + ArgExpr::Pos(e) => self.write_expr(e), + ArgExpr::Named(n) => { + let (k, v) = n.as_ref(); + self.write_decl(k)?; + write!(self.f, ": ")?; + self.write_expr(v) + } + ArgExpr::NamedRt(n) => { + let n = n.as_ref(); + self.write_expr(&n.0)?; + write!(self.f, ": ")?; + self.write_expr(&n.1) + } + ArgExpr::Spread(e) => { + write!(self.f, "..")?; + self.write_expr(e) + } + } + } + + pub fn write_pattern(&mut self, p: &Pattern) -> fmt::Result { + match p { + Pattern::Expr(e) => self.write_expr(e), + Pattern::Simple(s) => self.write_decl(s), + Pattern::Sig(p) => self.write_pattern_sig(p), + } + } + + fn write_pattern_sig(&mut self, p: &PatternSig) -> fmt::Result { + self.f.write_str("pat(\n")?; + self.indent += 1; + for pos in &p.pos { + self.write_indent()?; + self.write_pattern(pos)?; + self.f.write_str(",\n")?; + } + for (name, pat) in &p.named { + self.write_indent()?; + write!(self.f, "{name:?} = ")?; + self.write_pattern(pat)?; + self.f.write_str(",\n")?; + } + if let Some((k, rest)) = &p.spread_left { + self.write_indent()?; + write!(self.f, "..{k:?}: ")?; + self.write_pattern(rest)?; + self.f.write_str(",\n")?; + } + if let Some((k, rest)) = &p.spread_right { + self.write_indent()?; + write!(self.f, "..{k:?}: ")?; + self.write_pattern(rest)?; + self.f.write_str(",\n")?; + } + self.indent -= 1; + self.write_indent()?; + self.f.write_str(")") + } + + fn write_element(&mut self, e: &Interned) -> fmt::Result { + write!(self.f, "{:?}", e.elem.name()) + } + + fn write_unary(&mut self, u: &Interned) -> fmt::Result { + use UnaryOp::*; + match u.op { + Pos => { + self.f.write_str("+")?; + self.write_expr(&u.lhs) + } + Neg => { + self.f.write_str("-")?; + self.write_expr(&u.lhs) + } + Not => { + self.f.write_str("not ")?; + self.write_expr(&u.lhs) + } + Return => { + self.f.write_str("return ")?; + self.write_expr(&u.lhs) + } + Context => { + self.f.write_str("context ")?; + self.write_expr(&u.lhs) + } + Spread => { + self.f.write_str("..")?; + self.write_expr(&u.lhs) + } + NotElementOf => { + self.f.write_str("not elementOf(")?; + self.write_expr(&u.lhs)?; + self.f.write_str(")") + } + ElementOf => { + self.f.write_str("elementOf(")?; + self.write_expr(&u.lhs)?; + self.f.write_str(")") + } + TypeOf => { + self.f.write_str("typeOf(")?; + self.write_expr(&u.lhs)?; + self.f.write_str(")") + } + } + } + + fn write_binary(&mut self, b: &Interned) -> fmt::Result { + let [lhs, rhs] = b.operands(); + self.write_expr(lhs)?; + write!(self.f, " {} ", b.op.as_str())?; + self.write_expr(rhs) + } + + fn write_apply(&mut self, a: &Interned) -> fmt::Result { + self.write_expr(&a.callee)?; + write!(self.f, "(")?; + self.write_expr(&a.args)?; + write!(self.f, ")") + } + + fn write_func(&mut self, func: &Interned) -> fmt::Result { + self.write_decl(&func.decl) + } + + fn write_ref(&mut self, r: &Interned) -> fmt::Result { + if let Some(r) = &r.root { + return self.write_expr(r); + } + if let Some(r) = &r.val { + return self.write_type(r); + } + + write!(self.f, "undefined({:?})", r.decl) + } + + fn write_content_ref(&mut self, r: &Interned) -> fmt::Result { + write!(self.f, "@{:?}", r.ident) + } + + fn write_select(&mut self, s: &Interned) -> fmt::Result { + write!(self.f, "")?; + self.write_expr(&s.lhs)?; + self.f.write_str(".")?; + self.write_decl(&s.key) + } + + fn write_import(&mut self, i: &Interned) -> fmt::Result { + self.f.write_str("import(")?; + self.write_decl(&i.decl.decl)?; + self.f.write_str(")") + } + + fn write_include(&mut self, i: &Interned) -> fmt::Result { + self.f.write_str("include(")?; + self.write_expr(&i.source)?; + self.f.write_str(")") + } + + fn write_type(&mut self, t: &Ty) -> fmt::Result { + let formatted = t.describe(); + let formatted = formatted.as_deref().unwrap_or("any"); + self.f.write_str(formatted) + } +} diff --git a/crates/tinymist-query/src/tests.rs b/crates/tinymist-query/src/tests.rs index 5e3a88d93..84a26dd0d 100644 --- a/crates/tinymist-query/src/tests.rs +++ b/crates/tinymist-query/src/tests.rs @@ -1,5 +1,5 @@ use core::fmt; -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; use std::{ collections::{HashMap, HashSet}, ops::Range, @@ -21,14 +21,18 @@ pub use serde_json::json; pub use tinymist_world::{LspUniverse, LspUniverseBuilder}; use typst_shim::syntax::LinkedNodeExt; +use crate::syntax::find_module_level_docs; use crate::{ analysis::Analysis, prelude::LocalContext, typst_to_lsp, LspPosition, PositionEncoding, VersionedDocument, }; +use crate::{CompletionFeat, LspWorldExt}; type CompileDriver = CompileDriverImpl; pub fn snapshot_testing(name: &str, f: &impl Fn(&mut LocalContext, PathBuf)) { + let name = if name.is_empty() { "playground" } else { name }; + let mut settings = insta::Settings::new(); settings.set_prepend_module_to_snapshot(false); settings.set_snapshot_path(format!("fixtures/{name}/snaps")); @@ -58,7 +62,29 @@ pub fn run_with_ctx( .map(|p| TypstFileId::new(None, VirtualPath::new(p.strip_prefix(&root).unwrap()))) .collect::>(); - let mut ctx = Arc::new(Analysis::default()).snapshot(w.snapshot()); + let w = w.snapshot(); + + let source = w.source_by_path(&p).ok().unwrap(); + let docs = find_module_level_docs(&source).unwrap_or_default(); + let properties = get_test_properties(&docs); + let supports_html = properties + .get("html") + .map(|v| v.trim() == "true") + .unwrap_or(true); + + let mut ctx = Arc::new(Analysis { + remove_html: !supports_html, + completion_feat: CompletionFeat { + trigger_on_snippet_placeholders: true, + trigger_suggest: true, + trigger_parameter_hints: true, + trigger_suggest_and_parameter_hints: true, + ..Default::default() + }, + ..Analysis::default() + }) + .snapshot(w); + ctx.test_completion_files(Vec::new); ctx.test_files(|| paths); f(&mut ctx, p) @@ -69,8 +95,10 @@ pub fn get_test_properties(s: &str) -> HashMap<&'_ str, &'_ str> { for line in s.lines() { let mut line = line.splitn(2, ':'); let key = line.next().unwrap().trim(); - let value = line.next().unwrap().trim(); - props.insert(key, value); + let Some(value) = line.next() else { + continue; + }; + props.insert(key, value.trim()); } props } @@ -103,6 +131,7 @@ pub fn run_with_sources(source: &str, f: impl FnOnce(&mut LspUniverse, PathBu }; let mut world = LspUniverseBuilder::build( EntryState::new_rooted(root.as_path().into(), None), + Default::default(), Arc::new( LspUniverseBuilder::resolve_fonts(CompileFontArgs { ignore_system_fonts: true, @@ -110,8 +139,7 @@ pub fn run_with_sources(source: &str, f: impl FnOnce(&mut LspUniverse, PathBu }) .unwrap(), ), - Default::default(), - None, + LspUniverseBuilder::resolve_package(None, None), ) .unwrap(); let sources = source.split("-----"); @@ -291,6 +319,7 @@ pub fn find_test_position_(s: &Source, offset: usize) -> LspPosition { pub static REDACT_LOC: Lazy = Lazy::new(|| { RedactFields::from_iter([ "location", + "contents", "uri", "oldUri", "newUri", @@ -383,6 +412,18 @@ impl Redact for RedactFields { format!("{}:{}", pos(&t["start"]), pos(&t["end"])).into(), ); } + "contents" => { + let res = t.as_str().unwrap(); + static REG: OnceLock = OnceLock::new(); + let reg = REG.get_or_init(|| { + regex::Regex::new(r#"data:image/svg\+xml;base64,([^"]+)"#).unwrap() + }); + let res = reg.replace_all(res, |_captures: ®ex::Captures| { + "data:image-hash/svg+xml;base64,redacted" + }); + + m.insert(k.to_owned(), res.into()); + } _ => {} } } diff --git a/crates/tinymist-query/src/ty/bound.rs b/crates/tinymist-query/src/ty/bound.rs index 238bd9ed6..ad6971be2 100644 --- a/crates/tinymist-query/src/ty/bound.rs +++ b/crates/tinymist-query/src/ty/bound.rs @@ -1,3 +1,5 @@ +use std::ops::Deref; + use typst::foundations::{self, Func}; use crate::ty::prelude::*; @@ -19,6 +21,25 @@ pub trait BoundChecker: Sized + TyCtx { } } +#[derive(BindTyCtx)] +#[bind(0)] +pub struct BoundPred<'a, T: TyCtx, F>(pub &'a T, pub F); + +impl<'a, T: TyCtx, F> BoundPred<'a, T, F> { + pub fn new(t: &'a T, f: F) -> Self { + Self(t, f) + } +} + +impl<'a, T: TyCtx, F> BoundChecker for BoundPred<'a, T, F> +where + F: FnMut(&Ty, bool), +{ + fn collect(&mut self, ty: &Ty, pol: bool) { + self.1(ty, pol); + } +} + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum DocSource { Var(Interned), @@ -78,8 +99,9 @@ impl Ty { Any | Boolean(_) | If(..) | Builtin(..) | Value(..) => {} Dict(..) | Array(..) | Tuple(..) | Func(..) | Args(..) | Pattern(..) => {} Unary(..) | Binary(..) => {} - Field(ty) => { - collect(&ty.field, results); + Param(ty) => { + // todo: doc source can be param ty + collect(&ty.ty, results); } Union(ty) => { for ty in ty.iter() { @@ -98,7 +120,12 @@ impl Ty { results.push(DocSource::Var(ty.clone())); } With(ty) => collect(&ty.sig, results), - Select(_ty) => { + Select(ty) => { + // todo: do this correctly + if matches!(ty.select.deref(), "with" | "where") { + collect(&ty.ty, results); + } + // collect(&ty.ty, results) } } diff --git a/crates/tinymist-query/src/ty/builtin.rs b/crates/tinymist-query/src/ty/builtin.rs index 0ada21717..f842561d6 100644 --- a/crates/tinymist-query/src/ty/builtin.rs +++ b/crates/tinymist-query/src/ty/builtin.rs @@ -1,5 +1,6 @@ use core::fmt; +use ecow::{eco_format, EcoString}; use once_cell::sync::Lazy; use regex::RegexSet; use strum::{EnumIter, IntoEnumIterator}; @@ -9,6 +10,7 @@ use typst::{ layout::Length, }; +use crate::syntax::Decl; use crate::ty::*; #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, EnumIter)] @@ -227,7 +229,9 @@ pub enum BuiltinTy { Tag(Box<(StrRef, Option>)>), Type(typst::foundations::Type), + TypeType(typst::foundations::Type), Element(typst::foundations::Element), + Module(Interned), Path(PathPreference), } @@ -262,6 +266,7 @@ impl fmt::Debug for BuiltinTy { BuiltinTy::Inset => write!(f, "Inset"), BuiltinTy::Outset => write!(f, "Outset"), BuiltinTy::Radius => write!(f, "Radius"), + BuiltinTy::TypeType(ty) => write!(f, "TypeType({})", ty.short_name()), BuiltinTy::Type(ty) => write!(f, "Type({})", ty.short_name()), BuiltinTy::Element(e) => e.fmt(f), BuiltinTy::Tag(tag) => { @@ -272,6 +277,7 @@ impl fmt::Debug for BuiltinTy { write!(f, "Tag({name:?})") } } + BuiltinTy::Module(m) => write!(f, "{m:?}"), BuiltinTy::Path(p) => write!(f, "Path({p:?})"), } } @@ -312,7 +318,7 @@ impl BuiltinTy { BuiltinTy::Type(builtin).literally() } - pub(crate) fn describe(&self) -> String { + pub(crate) fn describe(&self) -> EcoString { let res = match self { BuiltinTy::Clause => "any", BuiltinTy::Undef => "any", @@ -342,16 +348,18 @@ impl BuiltinTy { BuiltinTy::Inset => "inset", BuiltinTy::Outset => "outset", BuiltinTy::Radius => "radius", + BuiltinTy::TypeType(..) => "type", BuiltinTy::Type(ty) => ty.short_name(), BuiltinTy::Element(ty) => ty.name(), BuiltinTy::Tag(tag) => { let (name, id) = tag.as_ref(); return if let Some(id) = id { - format!("tag {name} of {id:?}") + eco_format!("tag {name} of {id:?}") } else { - format!("tag {name}") + eco_format!("tag {name}") }; } + BuiltinTy::Module(m) => return eco_format!("module({})", m.name()), BuiltinTy::Path(s) => match s { PathPreference::None => "[any]", PathPreference::Special => "[any]", @@ -369,7 +377,7 @@ impl BuiltinTy { }, }; - res.to_string() + res.into() } } diff --git a/crates/tinymist-query/src/ty/def.rs b/crates/tinymist-query/src/ty/def.rs index 84a06851c..9503cae35 100644 --- a/crates/tinymist-query/src/ty/def.rs +++ b/crates/tinymist-query/src/ty/def.rs @@ -8,17 +8,18 @@ use std::{ sync::Arc, }; -use ecow::EcoVec; +use ecow::{EcoString, EcoVec}; use once_cell::sync::OnceCell; use parking_lot::{Mutex, RwLock}; use reflexo_typst::TypstFileId; use rustc_hash::{FxHashMap, FxHashSet}; +use serde::{Deserialize, Serialize}; use typst::{ - foundations::Value, + foundations::{Content, Element, ParamInfo, Type, Value}, syntax::{ast, Span, SyntaxKind, SyntaxNode}, }; -use super::PackageId; +use super::{BoundPred, PackageId}; use crate::{ adt::{interner::impl_internable, snapshot_map}, analysis::BuiltinTy, @@ -49,8 +50,8 @@ pub enum Ty { Builtin(BuiltinTy), /// A possible typst instance of some type. Value(Interned), - /// A field type - Field(Interned), + /// A parameter type + Param(Interned), // Combination Types /// A union type, whose negation is intersection type. @@ -120,7 +121,7 @@ impl fmt::Debug for Ty { f.write_str(")") } Ty::Let(v) => write!(f, "({v:?})"), - Ty::Field(ff) => write!(f, "{:?}: {:?}", ff.name, ff.field), + Ty::Param(ff) => write!(f, "{:?}: {:?}", ff.name, ff.ty), Ty::Var(v) => v.fmt(f), Ty::Unary(u) => write!(f, "{u:?}"), Ty::Binary(b) => write!(f, "{b:?}"), @@ -143,6 +144,15 @@ impl Ty { matches!(self, Ty::Dict(..)) } + pub(crate) fn or(ty: Option, pos: Option) -> Option { + Some(match (ty, pos) { + (Some(ty), Some(pos)) => Ty::from_types([ty, pos].into_iter()), + (Some(ty), None) => ty, + (None, Some(pos)) => pos, + (None, None) => return None, + }) + } + /// Create a union type from an iterator of types pub fn from_types(e: impl ExactSizeIterator) -> Self { if e.len() == 0 { @@ -168,6 +178,40 @@ impl Ty { Ty::Builtin(BuiltinTy::Undef) } + /// Get name of the type + pub fn name(&self) -> Interned { + match self { + Ty::Var(v) => v.name.clone(), + Ty::Builtin(BuiltinTy::Module(m)) => m.name().clone(), + ty => ty + .value() + .and_then(|v| Some(Interned::new_str(v.name()?))) + .unwrap_or_default(), + } + } + + /// Get span of the type + pub fn span(&self) -> Span { + fn seq(u: &[Ty]) -> Option { + u.iter().find_map(|ty| { + let sub = ty.span(); + if sub.is_detached() { + return None; + } + Some(sub) + }) + } + + match self { + Ty::Var(v) => v.def.span(), + Ty::Let(u) => seq(&u.ubs) + .or_else(|| seq(&u.lbs)) + .unwrap_or_else(Span::detached), + Ty::Union(u) => seq(u).unwrap_or_else(Span::detached), + _ => Span::detached(), + } + } + /// Get value repr of the type pub fn value(&self) -> Option { match self { @@ -177,6 +221,37 @@ impl Ty { _ => None, } } + + /// Get the type of the type + pub fn element(&self) -> Option { + match self { + Ty::Value(v) => match &v.val { + Value::Func(f) => f.element(), + _ => None, + }, + Ty::Builtin(BuiltinTy::Element(v)) => Some(*v), + _ => None, + } + } + + pub(crate) fn satisfy(&self, ctx: &T, f: impl FnMut(&Ty, bool)) { + self.bounds(true, &mut BoundPred::new(ctx, f)); + } + + pub(crate) fn is_content(&self, ctx: &T) -> bool { + let mut res = false; + self.satisfy(ctx, |ty: &Ty, _pol| { + res = res || { + match ty { + Ty::Value(v) => matches!(v.val, Value::Content(..)), + Ty::Builtin(BuiltinTy::Content | BuiltinTy::Element(..)) => true, + Ty::Builtin(BuiltinTy::Type(v)) => *v == Type::of::(), + _ => false, + } + } + }); + res + } } /// A function parameter type @@ -418,23 +493,107 @@ impl InsTy { })), }) } + + /// Get the span of the instance + pub fn span(&self) -> Span { + self.syntax + .as_ref() + .map(|s| s.name_node.span()) + .or_else(|| { + Some(match &self.val { + Value::Func(f) => f.span(), + Value::Args(a) => a.span, + Value::Content(c) => c.span(), + // todo: module might have file id + _ => return None, + }) + }) + .unwrap_or_else(Span::detached) + } +} + +/// Describes a function parameter. +#[derive( + Debug, Clone, Copy, Hash, Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd, Ord, +)] +pub struct ParamAttrs { + /// Is the parameter positional? + pub positional: bool, + /// Is the parameter named? + /// + /// Can be true even if `positional` is true if the parameter can be given + /// in both variants. + pub named: bool, + /// Can the parameter be given any number of times? + pub variadic: bool, + /// Is the parameter settable with a set rule? + pub settable: bool, +} + +impl ParamAttrs { + pub(crate) fn positional() -> ParamAttrs { + ParamAttrs { + positional: true, + named: false, + variadic: false, + settable: false, + } + } + + pub(crate) fn named() -> ParamAttrs { + ParamAttrs { + positional: false, + named: true, + variadic: false, + settable: false, + } + } + + pub(crate) fn variadic() -> ParamAttrs { + ParamAttrs { + positional: true, + named: false, + variadic: true, + settable: false, + } + } } -/// A field type -#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct FieldTy { - /// The name of the field +impl From<&ParamInfo> for ParamAttrs { + fn from(param: &ParamInfo) -> Self { + ParamAttrs { + positional: param.positional, + named: param.named, + variadic: param.variadic, + settable: param.settable, + } + } +} + +/// Describes a parameter type. +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct ParamTy { + /// The name of the parameter. pub name: StrRef, - /// The type of the field - pub field: Ty, + /// The docstring of the parameter. + pub docs: Option, + /// The default value of the variable + pub default: Option, + /// The type of the parameter. + pub ty: Ty, + /// The attributes of the parameter. + pub attrs: ParamAttrs, } -impl FieldTy { +impl ParamTy { /// Create an untyped field type - pub fn new_untyped(name: StrRef) -> Interned { + pub fn new_untyped(name: StrRef, attrs: ParamAttrs) -> Interned { Interned::new(Self { name, - field: Ty::Any, + ty: Ty::Any, + docs: None, + default: None, + attrs, }) } } @@ -719,6 +878,21 @@ impl SigTy { .and_then(|_| self.inputs.get(idx)) } + /// Get the parameter or the rest parameter at the given index + pub fn pos_or_rest(&self, idx: usize) -> Option { + let nth = self.pos(idx).cloned(); + nth.or_else(|| { + let rest_idx = || idx.saturating_sub(self.positional_params().len()); + + let rest_ty = self.rest_param()?; + match rest_ty { + Ty::Array(ty) => Some(ty.as_ref().clone()), + Ty::Tuple(tys) => tys.get(rest_idx()).cloned(), + _ => None, + } + }) + } + /// Get the named parameters of the function pub fn named_params(&self) -> impl ExactSizeIterator { let named_names = self.names.names.iter(); @@ -958,8 +1132,14 @@ impl IfTy { /// A type scheme on a group of syntax structures (typing) #[derive(Default)] pub struct TypeScheme { + /// Whether the typing is valid + pub valid: bool, + /// The belonging file id + pub fid: Option, /// The revision used pub revision: usize, + /// The exported types + pub exports: FxHashMap, /// The typing on definitions pub vars: FxHashMap, /// The checked documentation of definitions @@ -1146,7 +1326,7 @@ pub(super) struct TypeCanoStore { impl_internable!(Ty,); impl_internable!(InsTy,); -impl_internable!(FieldTy,); +impl_internable!(ParamTy,); impl_internable!(TypeSource,); impl_internable!(TypeVar,); impl_internable!(SigWithTy,); @@ -1198,7 +1378,7 @@ mod tests { #[test] fn test_ty_size() { use super::*; - assert!(size_of::() == 16); + assert!(size_of::() <= size_of::() * 2); } #[test] diff --git a/crates/tinymist-query/src/ty/describe.rs b/crates/tinymist-query/src/ty/describe.rs index 36e2551c6..e1ecc0a75 100644 --- a/crates/tinymist-query/src/ty/describe.rs +++ b/crates/tinymist-query/src/ty/describe.rs @@ -1,28 +1,35 @@ +use ecow::{eco_format, EcoString}; use reflexo::hash::hash128; use typst::foundations::Repr; -use crate::ty::prelude::*; - -impl TypeScheme { - /// Describe the given type with the given type scheme. - pub fn describe(&self, ty: &Ty) -> Option { - let mut worker: TypeDescriber = TypeDescriber::default(); - worker.describe_root(ty) - } -} +use crate::{ + analysis::{is_plain_value, term_value}, + ty::prelude::*, + upstream::truncated_repr_, +}; impl Ty { /// Describe the given type. - pub fn repr(&self) -> Option { + pub fn repr(&self) -> Option { + let mut worker = TypeDescriber { + repr: true, + ..Default::default() + }; + worker.describe_root(self) + } + + /// Describe available value instances of the given type. + pub fn value_repr(&self) -> Option { let mut worker = TypeDescriber { repr: true, + value: true, ..Default::default() }; worker.describe_root(self) } /// Describe the given type. - pub fn describe(&self) -> Option { + pub fn describe(&self) -> Option { let mut worker = TypeDescriber::default(); worker.describe_root(self) } @@ -46,13 +53,14 @@ impl Ty { #[derive(Default)] struct TypeDescriber { repr: bool, - described: HashMap, - results: HashSet, + value: bool, + described: HashMap, + results: HashSet, functions: Vec>, } impl TypeDescriber { - fn describe_root(&mut self, ty: &Ty) -> Option { + fn describe_root(&mut self, ty: &Ty) -> Option { let _ = TypeDescriber::describe_iter; // recursive structure if let Some(t) = self.described.get(&hash128(ty)) { @@ -63,7 +71,7 @@ impl TypeDescriber { if !res.is_empty() { return Some(res); } - self.described.insert(hash128(ty), "$self".to_string()); + self.described.insert(hash128(ty), "$self".into()); let mut results = std::mem::take(&mut self.results) .into_iter() @@ -74,7 +82,7 @@ impl TypeDescriber { // only first function is described let f = functions[0].clone(); - let mut res = String::new(); + let mut res = EcoString::new(); res.push('('); let mut not_first = false; for ty in f.positional_params() { @@ -100,8 +108,7 @@ impl TypeDescriber { res.push_str(", "); } res.push_str("..: "); - res.push_str(self.describe_root(r).as_deref().unwrap_or("")); - res.push_str("[]"); + res.push_str(self.describe_root(r).as_deref().unwrap_or("any")); } res.push_str(") => "); res.push_str( @@ -116,13 +123,13 @@ impl TypeDescriber { } if results.is_empty() { - self.described.insert(hash128(ty), "any".to_string()); + self.described.insert(hash128(ty), "any".into()); return None; } results.sort(); results.dedup(); - let res = results.join(" | "); + let res: EcoString = results.join(" | ").into(); self.described.insert(hash128(ty), res.clone()); Some(res) } @@ -136,7 +143,7 @@ impl TypeDescriber { } } - fn describe(&mut self, ty: &Ty) -> String { + fn describe(&mut self, ty: &Ty) -> EcoString { match ty { Ty::Var(..) => {} Ty::Union(tys) => { @@ -150,57 +157,63 @@ impl TypeDescriber { self.functions.push(f.clone()); } Ty::Dict(..) => { - return "dict".to_string(); + return "dictionary".into(); } Ty::Tuple(..) => { - return "array".to_string(); + return "array".into(); } Ty::Array(..) => { - return "array".to_string(); + return "array".into(); } // todo: sig with Ty::With(w) => { return self.describe(&w.sig); } Ty::Builtin(BuiltinTy::Content | BuiltinTy::Space) => { - return "content".to_string(); + return "content".into(); } // Doesn't provide any information, hence we doesn't describe it intermediately here. Ty::Any | Ty::Builtin(BuiltinTy::Clause | BuiltinTy::Undef | BuiltinTy::Infer) => {} Ty::Builtin(BuiltinTy::FlowNone | BuiltinTy::None) => { - return "none".to_string(); + return "none".into(); } Ty::Builtin(BuiltinTy::Auto) => { - return "auto".to_string(); + return "auto".into(); } Ty::Boolean(..) if self.repr => { - return "bool".to_string(); + return "bool".into(); } Ty::Boolean(None) => { - return "bool".to_string(); + return "bool".into(); } Ty::Boolean(Some(b)) => { - return b.to_string(); + return eco_format!("{b}"); } Ty::Builtin(b) => { return b.describe(); } - Ty::Value(v) if self.repr => return v.val.ty().short_name().to_string(), - Ty::Value(v) => return v.val.repr().to_string(), - Ty::Field(..) => { - return "field".to_string(); + Ty::Value(v) if matches!(v.val, Value::Module(..)) => { + let Value::Module(m) = &v.val else { + return "module".into(); + }; + return eco_format!("module({})", m.name()); + } + Ty::Value(v) if !is_plain_value(&v.val) => return self.describe(&term_value(&v.val)), + Ty::Value(v) if self.value => return truncated_repr_::<181>(&v.val), + Ty::Value(v) if self.repr => return v.val.ty().short_name().into(), + Ty::Value(v) => return v.val.repr(), + Ty::Param(..) => { + return "param".into(); } Ty::Args(..) => { - return "arguments".to_string(); + return "arguments".into(); } Ty::Pattern(..) => { - return "pattern".to_string(); - } - Ty::Select(..) | Ty::Unary(..) | Ty::Binary(..) | Ty::If(..) => { - return "any".to_string() + return "pattern".into(); } + Ty::Select(..) | Ty::Unary(..) | Ty::Binary(..) | Ty::If(..) => return "any".into(), } - String::new() + EcoString::new() } } diff --git a/crates/tinymist-query/src/ty/iface.rs b/crates/tinymist-query/src/ty/iface.rs index cac3ceed5..8ac3c26e8 100644 --- a/crates/tinymist-query/src/ty/iface.rs +++ b/crates/tinymist-query/src/ty/iface.rs @@ -27,8 +27,6 @@ pub enum Iface<'a> { val: &'a Module, at: &'a Ty, }, - ArrayCons(&'a TyRef), - Partialize(&'a Iface<'a>), } impl<'a> Iface<'a> { @@ -38,11 +36,9 @@ impl<'a> Iface<'a> { match self { // Iface::ArrayCons(a) => SigTy::array_cons(a.as_ref().clone(), false), - Iface::ArrayCons(..) => None, Iface::Dict(d) => d.field_by_name(key).cloned(), // Iface::Type { val, .. } => ctx?.type_of_func(&val.constructor().ok()?)?, // Iface::Value { val, .. } => ctx?.type_of_func(val)?, // todo - Iface::Partialize(..) => None, Iface::Element { .. } => None, Iface::Type { .. } => None, Iface::Value { val, at: _ } => ctx.type_of_dict(val).field_by_name(key).cloned(), @@ -53,7 +49,7 @@ impl<'a> Iface<'a> { } pub trait IfaceChecker: TyCtx { - fn check(&mut self, sig: Iface, args: &mut IfaceCheckContext, pol: bool) -> Option<()>; + fn check(&mut self, iface: Iface, ctx: &mut IfaceCheckContext, pol: bool) -> Option<()>; } impl Ty { @@ -64,10 +60,7 @@ impl Ty { // iface_kind: IfaceSurfaceKind, checker: &mut impl IfaceChecker, ) { - let context = IfaceCheckContext { - args: Vec::new(), - at: TyRef::new(Ty::Any), - }; + let context = IfaceCheckContext { args: Vec::new() }; let mut worker = IfaceCheckDriver { ctx: context, checker, @@ -79,7 +72,6 @@ impl Ty { pub struct IfaceCheckContext { pub args: Vec>, - pub at: TyRef, } #[derive(BindTyCtx)] @@ -165,6 +157,12 @@ impl<'a> IfaceCheckDriver<'a> { self.checker .check(Iface::Element { val: e, at: ty }, &mut self.ctx, pol); } + Ty::Builtin(BuiltinTy::Module(e)) => { + if let Decl::Module(m) = e.as_ref() { + self.checker + .check(Iface::Module { val: m.fid, at: ty }, &mut self.ctx, pol); + } + } // Ty::Func(sig) if self.value_as_iface() => { // self.checker.check(Iface::Type(sig), &mut self.ctx, pol); // } @@ -178,13 +176,7 @@ impl<'a> IfaceCheckDriver<'a> { // self.check_dict_signature(sig, pol, self.checker); self.checker.check(Iface::Dict(sig), &mut self.ctx, pol); } - Ty::Var(v) => match v.def.as_ref() { - Decl::Module(m) => { - self.checker - .check(Iface::Module { val: m.fid, at: ty }, &mut self.ctx, pol); - } - _ => ty.bounds(pol, self), - }, + Ty::Var(..) => ty.bounds(pol, self), _ if ty.has_bounds() => ty.bounds(pol, self), _ => {} } diff --git a/crates/tinymist-query/src/ty/mod.rs b/crates/tinymist-query/src/ty/mod.rs index f730986d1..1df7d8093 100644 --- a/crates/tinymist-query/src/ty/mod.rs +++ b/crates/tinymist-query/src/ty/mod.rs @@ -32,6 +32,16 @@ pub trait TyCtx { fn global_bounds(&self, _var: &Interned, _pol: bool) -> Option; } +impl TyCtx for () { + fn local_bind_of(&self, _var: &Interned) -> Option { + None + } + + fn global_bounds(&self, _var: &Interned, _pol: bool) -> Option { + None + } +} + /// A mutable type context. pub trait TyCtxMut: TyCtx { /// The type of a snapshot of the scope. diff --git a/crates/tinymist-query/src/ty/mutate.rs b/crates/tinymist-query/src/ty/mutate.rs index 86d308095..5be640199 100644 --- a/crates/tinymist-query/src/ty/mutate.rs +++ b/crates/tinymist-query/src/ty/mutate.rs @@ -16,7 +16,7 @@ pub trait TyMutator { Func(f) => Some(Func(self.mutate_func(f, pol)?.into())), Args(args) => Some(Args(self.mutate_func(args, pol)?.into())), Pattern(args) => Some(Pattern(self.mutate_func(args, pol)?.into())), - Field(f) => Some(Field(self.mutate_field(f, pol)?.into())), + Param(f) => Some(Param(self.mutate_param(f, pol)?.into())), Select(s) => Some(Select(self.mutate_select(s, pol)?.into())), With(w) => Some(With(self.mutate_with_sig(w, pol)?.into())), Unary(u) => Some(Unary(self.mutate_unary(u, pol)?.into())), @@ -71,10 +71,10 @@ pub trait TyMutator { }) } - fn mutate_field(&mut self, f: &Interned, pol: bool) -> Option { - let field = self.mutate(&f.field, pol)?; + fn mutate_param(&mut self, f: &Interned, pol: bool) -> Option { + let ty = self.mutate(&f.ty, pol)?; let mut f = f.as_ref().clone(); - f.field = field; + f.ty = ty; Some(f) } diff --git a/crates/tinymist-query/src/ty/sig.rs b/crates/tinymist-query/src/ty/sig.rs index d0225b316..89941a894 100644 --- a/crates/tinymist-query/src/ty/sig.rs +++ b/crates/tinymist-query/src/ty/sig.rs @@ -47,9 +47,14 @@ impl<'a> Sig<'a> { } pub fn shape(self, ctx: &mut impl TyCtxMut) -> Option> { - let (cano_sig, withs) = match self { + let (sig, _is_partialize) = match self { + Sig::Partialize(sig) => (*sig, true), + sig => (sig, false), + }; + + let (cano_sig, withs) = match sig { Sig::With { sig, withs, .. } => (*sig, Some(withs)), - _ => (self, None), + sig => (sig, None), }; let sig_ins = match cano_sig { @@ -237,6 +242,10 @@ impl<'a> SigCheckDriver<'a> { Ty::Unary(_) => {} Ty::Binary(_) => {} Ty::If(_) => {} + Ty::Param(p) => { + // todo: keep type information + self.ty(&p.ty, pol); + } _ if ty.has_bounds() => ty.bounds(pol, self), _ => {} } diff --git a/crates/tinymist-query/src/ty/simplify.rs b/crates/tinymist-query/src/ty/simplify.rs index 2e7feb23b..66ea33b28 100644 --- a/crates/tinymist-query/src/ty/simplify.rs +++ b/crates/tinymist-query/src/ty/simplify.rs @@ -152,8 +152,8 @@ impl<'a, 'b> TypeSimplifier<'a, 'b> { self.analyze(ub, pol); } } - Ty::Field(v) => { - self.analyze(&v.field, pol); + Ty::Param(v) => { + self.analyze(&v.ty, pol); } Ty::Value(_v) => {} Ty::Any => {} @@ -219,12 +219,17 @@ impl<'a, 'b> TypeSimplifier<'a, 'b> { self.transform(&i.then, pol).into(), self.transform(&i.else_, pol).into(), )), - Ty::Union(v) => Ty::Union(self.transform_seq(v, pol)), - Ty::Field(ty) => { + Ty::Union(seq) => { + let seq = seq.iter().map(|ty| self.transform(ty, pol)); + let seq_no_any = seq.filter(|ty| !matches!(ty, Ty::Any)); + let seq = seq_no_any.collect::>(); + Ty::from_types(seq.into_iter()) + } + Ty::Param(ty) => { let mut ty = ty.as_ref().clone(); - ty.field = self.transform(&ty.field, pol); + ty.ty = self.transform(&ty.ty, pol); - Ty::Field(ty.into()) + Ty::Param(ty.into()) } Ty::Select(sel) => { let mut sel = sel.as_ref().clone(); @@ -245,33 +250,43 @@ impl<'a, 'b> TypeSimplifier<'a, 'b> { seq.collect::>().into() } - // todo: reduce duplication + #[allow(clippy::mutable_key_type)] fn transform_let(&mut self, w: &TypeBounds, def_id: Option<&DeclExpr>, pol: bool) -> Ty { - let mut lbs = EcoVec::with_capacity(w.lbs.len()); - let mut ubs = EcoVec::with_capacity(w.ubs.len()); + let mut lbs = HashSet::with_capacity(w.lbs.len()); + let mut ubs = HashSet::with_capacity(w.ubs.len()); log::debug!("transform let [principal={}] with {w:?}", self.principal); if !self.principal || ((pol) && !def_id.is_some_and(|i| self.negatives.contains(i))) { for lb in w.lbs.iter() { - lbs.push(self.transform(lb, pol)); + lbs.insert(self.transform(lb, pol)); } } if !self.principal || ((!pol) && !def_id.is_some_and(|i| self.positives.contains(i))) { for ub in w.ubs.iter() { - ubs.push(self.transform(ub, !pol)); + ubs.insert(self.transform(ub, !pol)); } } if ubs.is_empty() { if lbs.len() == 1 { - return lbs.pop().unwrap(); + return lbs.into_iter().next().unwrap(); } if lbs.is_empty() { return Ty::Any; } + } else if lbs.is_empty() && ubs.len() == 1 { + return ubs.into_iter().next().unwrap(); } + // todo: bad performance + let mut lbs: Vec<_> = lbs.into_iter().collect(); + lbs.sort(); + let mut ubs: Vec<_> = ubs.into_iter().collect(); + ubs.sort(); + + let mut lbs = lbs.into_iter().collect(); + let mut ubs = ubs.into_iter().collect(); Ty::Let(TypeBounds { lbs, ubs }.into()) } diff --git a/crates/tinymist-query/src/upstream/complete.rs b/crates/tinymist-query/src/upstream/complete.rs index 535ded7d5..e0ec1c947 100644 --- a/crates/tinymist-query/src/upstream/complete.rs +++ b/crates/tinymist-query/src/upstream/complete.rs @@ -4,10 +4,10 @@ use std::ops::Range; use ecow::{eco_format, EcoString}; use if_chain::if_chain; +use lsp_types::TextEdit; use serde::{Deserialize, Serialize}; use typst::foundations::{fields_on, format_str, repr, Repr, StyleChain, Styles, Value}; use typst::model::Document; -use typst::syntax::ast::AstNode; use typst::syntax::{ast, is_id_continue, is_id_start, is_ident, LinkedNode, Source, SyntaxKind}; use typst::text::RawElem; use typst::World; @@ -16,12 +16,11 @@ use unscanny::Scanner; use super::{plain_docs_sentence, summarize_font_family}; use crate::adt::interner::Interned; -use crate::analysis::{analyze_labels, DynLabel, Ty}; -use crate::LocalContext; +use crate::analysis::{analyze_labels, DynLabel, LocalContext, Ty}; mod ext; -pub use ext::complete_path; use ext::*; +pub use ext::{complete_path, CompletionFeat, PostfixSnippet}; /// Autocomplete a cursor position in a source file. /// @@ -39,12 +38,10 @@ pub fn autocomplete( ) -> Option<(usize, bool, Vec, Vec)> { let _ = complete_comments(&mut ctx) || complete_type(&mut ctx).is_none() && { - log::info!("continue after completing type"); + log::debug!("continue after completing type"); complete_labels(&mut ctx) || complete_field_accesses(&mut ctx) || complete_imports(&mut ctx) - || complete_rules(&mut ctx) - || complete_params(&mut ctx) || complete_markup(&mut ctx) || complete_math(&mut ctx) || complete_code(&mut ctx, false) @@ -66,6 +63,8 @@ pub struct Completion { pub sort_text: Option, /// The composed text used for filtering. pub filter_text: Option, + /// The character that should be committed when selecting this completion. + pub commit_char: Option, /// The completed version of the input, possibly described with snippet /// syntax like `${lhs} + ${rhs}`. /// @@ -73,6 +72,10 @@ pub struct Completion { pub apply: Option, /// An optional short description, at most one sentence. pub detail: Option, + /// An optional array of additional text edits that are applied when + /// selecting this completion. Edits must not overlap with the main edit + /// nor with themselves. + pub additional_text_edits: Option>, /// An optional command to run when the completion is selected. pub command: Option<&'static str>, } @@ -337,7 +340,7 @@ fn complete_math(ctx: &mut CompletionContext) -> bool { /// Add completions for math snippets. #[rustfmt::skip] fn math_completions(ctx: &mut CompletionContext) { - ctx.scope_completions(true, |_| true); + ctx.scope_completions(true); ctx.snippet_completion( "subscript", @@ -382,7 +385,7 @@ fn complete_field_accesses(ctx: &mut CompletionContext) -> bool { if let Some((value, styles)) = ctx.ctx.analyze_expr(&prev).into_iter().next(); then { ctx.from = ctx.cursor; - field_access_completions(ctx, &value, &styles); + field_access_completions(ctx, &prev, &value, &styles); return true; } } @@ -397,7 +400,7 @@ fn complete_field_accesses(ctx: &mut CompletionContext) -> bool { if let Some((value, styles)) = ctx.ctx.analyze_expr(&prev_prev).into_iter().next(); then { ctx.from = ctx.leaf.offset(); - field_access_completions(ctx, &value, &styles); + field_access_completions(ctx,&prev_prev, &value, &styles); return true; } } @@ -406,7 +409,12 @@ fn complete_field_accesses(ctx: &mut CompletionContext) -> bool { } /// Add completions for all fields on a value. -fn field_access_completions(ctx: &mut CompletionContext, value: &Value, styles: &Option) { +fn field_access_completions( + ctx: &mut CompletionContext, + node: &LinkedNode, + value: &Value, + styles: &Option, +) { for (name, value, _) in value.ty().scope().iter() { ctx.value_completion(Some(name.clone()), value, true, None); } @@ -431,6 +439,8 @@ fn field_access_completions(ctx: &mut CompletionContext, value: &Value, styles: ); } + ctx.postfix_completions(node, value); + match value { Value::Symbol(symbol) => { for modifier in symbol.modifiers() { @@ -443,11 +453,15 @@ fn field_access_completions(ctx: &mut CompletionContext, value: &Value, styles: }); } } + + ctx.ufcs_completions(node, value); } Value::Content(content) => { for (name, value) in content.fields() { ctx.value_completion(Some(name.into()), &value, false, None); } + + ctx.ufcs_completions(node, value); } Value::Dict(dict) => { for (name, value) in dict.iter() { @@ -574,187 +588,20 @@ fn import_item_completions<'a>( } } -/// Complete set and show rules. -fn complete_rules(ctx: &mut CompletionContext) -> bool { - // We don't want to complete directly behind the keyword. - if !ctx.leaf.kind().is_trivia() { - return false; - } - - let Some(prev) = ctx.leaf.prev_leaf() else { - return false; - }; - - // Behind the set keyword: "set |". - if matches!(prev.kind(), SyntaxKind::Set) { - ctx.from = ctx.cursor; - set_rule_completions(ctx); - return true; - } - - // Behind the show keyword: "show |". - if matches!(prev.kind(), SyntaxKind::Show) { - ctx.from = ctx.cursor; - show_rule_selector_completions(ctx); - return true; - } - - // Behind a half-completed show rule: "show strong: |". - if_chain! { - if let Some(prev) = ctx.leaf.prev_leaf(); - if matches!(prev.kind(), SyntaxKind::Colon); - if matches!(prev.parent_kind(), Some(SyntaxKind::ShowRule)); - then { - ctx.from = ctx.cursor; - show_rule_recipe_completions(ctx); - return true; - } - } - - false -} - -/// Add completions for all functions from the global scope. -fn set_rule_completions(ctx: &mut CompletionContext) { - ctx.scope_completions(true, |value| { - matches!( - value, - Value::Func(func) if func.params() - .unwrap_or_default() - .iter() - .any(|param| param.settable), - ) - }); -} - -/// Add completions for selectors. -fn show_rule_selector_completions(ctx: &mut CompletionContext) { - ctx.scope_completions( - false, - |value| matches!(value, Value::Func(func) if func.element().is_some()), - ); - - ctx.enrich("", ": "); - - ctx.snippet_completion( - "text selector", - "\"${text}\": ${}", - "Replace occurrences of specific text.", - ); - - ctx.snippet_completion( - "regex selector", - "regex(\"${regex}\"): ${}", - "Replace matches of a regular expression.", - ); -} - -/// Add completions for recipes. -fn show_rule_recipe_completions(ctx: &mut CompletionContext) { - ctx.snippet_completion( - "replacement", - "[${content}]", - "Replace the selected element with content.", - ); - - ctx.snippet_completion( - "replacement (string)", - "\"${text}\"", - "Replace the selected element with a string of text.", - ); - - ctx.snippet_completion( - "transformation", - "element => [${content}]", - "Transform the element with a function.", - ); - - ctx.scope_completions(false, |value| matches!(value, Value::Func(_))); -} - -/// Complete call and set rule parameters. -fn complete_params(ctx: &mut CompletionContext) -> bool { - // Ensure that we are in a function call or set rule's argument list. - let (callee, set, args) = if_chain! { - if let Some(parent) = ctx.leaf.parent(); - if let Some(parent) = match parent.kind() { - SyntaxKind::Named => parent.parent(), - _ => Some(parent), - }; - if let Some(args) = parent.get().cast::(); - if let Some(grand) = parent.parent(); - if let Some(expr) = grand.get().cast::(); - let set = matches!(expr, ast::Expr::Set(_)); - if let Some(callee) = match expr { - ast::Expr::FuncCall(call) => Some(call.callee()), - ast::Expr::Set(set) => Some(set.target()), - _ => None, - }; - then { - (callee, set, args) - } else { - return false; - } - }; - - // Find the piece of syntax that decides what we're completing. - let mut deciding = ctx.leaf.clone(); - while !matches!( - deciding.kind(), - SyntaxKind::LeftParen | SyntaxKind::Comma | SyntaxKind::Colon - ) { - let Some(prev) = deciding.prev_leaf() else { - break; - }; - deciding = prev; - } - - // Parameter values: "func(param:|)", "func(param: |)". - if_chain! { - if deciding.kind() == SyntaxKind::Colon; - if let Some(prev) = deciding.prev_leaf(); - if let Some(param) = prev.get().cast::(); - then { - if let Some(next) = deciding.next_leaf() { - ctx.from = ctx.cursor.min(next.offset()); - } - let parent = deciding.parent().unwrap(); - log::debug!("named param parent: {:?}", parent); - // get type of this param - let ty = ctx.ctx.type_of(param.to_untyped()); - log::debug!("named param type: {:?}", ty); - - named_param_value_completions(ctx, callee, ¶m.into(), ty.as_ref()); - return true; - } - } - - // Parameters: "func(|)", "func(hi|)", "func(12,|)". - if_chain! { - if matches!(deciding.kind(), SyntaxKind::LeftParen | SyntaxKind::Comma); - if deciding.kind() != SyntaxKind::Comma || deciding.range().end <= ctx.cursor; - then { - if let Some(next) = deciding.next_leaf() { - ctx.from = ctx.cursor.min(next.offset()); - } - - param_completions(ctx, callee, set, args); - return true; - } - } - - false -} - /// Complete in code mode. fn complete_code(ctx: &mut CompletionContext, from_type: bool) -> bool { + let surrounding_syntax = ctx.surrounding_syntax(); + if matches!( - ctx.leaf.parent_kind(), - None | Some(SyntaxKind::Markup) - | Some(SyntaxKind::Math) - | Some(SyntaxKind::MathFrac) - | Some(SyntaxKind::MathAttach) - | Some(SyntaxKind::MathRoot) + (ctx.leaf.parent_kind(), surrounding_syntax), + ( + None | Some(SyntaxKind::Markup) + | Some(SyntaxKind::Math) + | Some(SyntaxKind::MathFrac) + | Some(SyntaxKind::MathAttach) + | Some(SyntaxKind::MathRoot), + SurroundingSyntax::Regular + ) ) { return false; } @@ -777,10 +624,11 @@ fn complete_code(ctx: &mut CompletionContext, from_type: bool) -> bool { // But not within or after an expression. if ctx.explicit && (ctx.leaf.kind().is_trivia() - || matches!( + || (matches!( ctx.leaf.kind(), SyntaxKind::LeftParen | SyntaxKind::LeftBrace - )) + ) || (matches!(ctx.leaf.kind(), SyntaxKind::Colon) + && ctx.leaf.parent_kind() == Some(SyntaxKind::ShowRule)))) { ctx.from = ctx.cursor; code_completions(ctx, false); @@ -793,9 +641,9 @@ fn complete_code(ctx: &mut CompletionContext, from_type: bool) -> bool { /// Add completions for expression snippets. #[rustfmt::skip] fn code_completions(ctx: &mut CompletionContext, hash: bool) { - ctx.scope_completions(true, |value| !hash || { - matches!(value, Value::Symbol(_) | Value::Func(_) | Value::Type(_) | Value::Module(_)) - }); + // todo: filter code completions + // matches!(value, Value::Symbol(_) | Value::Func(_) | Value::Type(_) | Value::Module(_)) + ctx.scope_completions(true); ctx.snippet_completion( "function call", @@ -962,10 +810,8 @@ pub struct CompletionContext<'a> { pub cursor: usize, pub explicit: bool, pub trigger_character: Option, - pub trigger_suggest: bool, - pub trigger_parameter_hints: bool, - pub trigger_named_completion: bool, pub from: usize, + pub from_ty: Option, pub completions: Vec, pub completions2: Vec, pub incomplete: bool, @@ -984,9 +830,6 @@ impl<'a> CompletionContext<'a> { cursor: usize, explicit: bool, trigger_character: Option, - trigger_suggest: bool, - trigger_parameter_hints: bool, - trigger_named_completion: bool, ) -> Option { let text = source.text(); let root = LinkedNode::new(source.root()); @@ -1001,11 +844,9 @@ impl<'a> CompletionContext<'a> { leaf, cursor, trigger_character, - trigger_suggest, - trigger_parameter_hints, - trigger_named_completion, explicit, from: cursor, + from_ty: None, incomplete: true, completions: vec![], completions2: vec![], @@ -1044,11 +885,7 @@ impl<'a> CompletionContext<'a> { apply: Some(snippet.into()), detail: Some(docs.into()), label_detail: None, - // VS Code doesn't do that... Auto triggering suggestion only happens on typing (word - // starts or trigger characters). However, you can use editor.action.triggerSuggest as - // command on a suggestion to "manually" retrigger suggest after inserting one - command: (self.trigger_suggest && snippet.contains("${")) - .then_some("editor.action.triggerSuggest"), + command: self.ctx.analysis.trigger_on_snippet(snippet.contains("${")), ..Completion::default() }); } @@ -1243,9 +1080,7 @@ impl<'a> CompletionContext<'a> { let mut command = None; if parens && matches!(value, Value::Func(_)) { if let Value::Func(func) = value { - command = self - .trigger_parameter_hints - .then_some("editor.action.triggerParameterHints"); + command = self.ctx.analysis.trigger_parameter_hints(true); if func .params() .is_some_and(|params| params.iter().all(|param| param.name == "self")) diff --git a/crates/tinymist-query/src/upstream/complete/ext.rs b/crates/tinymist-query/src/upstream/complete/ext.rs index 30ffb8b4c..84e7e02f1 100644 --- a/crates/tinymist-query/src/upstream/complete/ext.rs +++ b/crates/tinymist-query/src/upstream/complete/ext.rs @@ -1,339 +1,505 @@ use std::collections::BTreeMap; +use std::ops::Deref; +use std::sync::OnceLock; use ecow::{eco_format, EcoString}; +use hashbrown::HashSet; use lsp_types::{CompletionItem, CompletionTextEdit, InsertTextFormat, TextEdit}; -use once_cell::sync::OnceCell; use reflexo::path::unix_slash; +use regex::Regex; +use serde::{Deserialize, Serialize}; +use tinymist_derive::BindTyCtx; use tinymist_world::LspWorld; -use typst::foundations::{AutoValue, Func, Label, NoneValue, Repr, Type, Value}; -use typst::layout::{Dir, Length}; +use typst::foundations::{AutoValue, Content, Func, Label, NoneValue, Scope, Type, Value}; use typst::syntax::ast::AstNode; use typst::syntax::{ast, Span, SyntaxKind, SyntaxNode}; use typst::visualize::Color; use super::{Completion, CompletionContext, CompletionKind}; use crate::adt::interner::Interned; -use crate::analysis::{resolve_call_target, BuiltinTy, PathPreference, Ty}; -use crate::syntax::{is_ident_like, param_index_at_leaf, CheckTarget}; +use crate::analysis::{func_signature, BuiltinTy, PathPreference, Ty}; +use crate::syntax::{ + descending_decls, interpret_mode_at, is_ident_like, CheckTarget, DescentDecl, InterpretMode, +}; +use crate::ty::{Iface, IfaceChecker, InsTy, SigTy, TyCtx, TypeBounds, TypeScheme, TypeVar}; use crate::upstream::complete::complete_code; -use crate::upstream::plain_docs_sentence; use crate::{completion_kind, prelude::*, LspCompletion}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum PostfixSnippetScope { + /// Any "dottable" value. + Value, + /// Any value having content type. + Content, +} + +/// A parsed snippet +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ParsedSnippet { + node_before: EcoString, + node_before_before_cursor: Option, + node_after: EcoString, +} + +/// A postfix completion snippet. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PostfixSnippet { + /// The scope of the snippet. + pub mode: EcoVec, + /// The scope of the snippet. + pub scope: PostfixSnippetScope, + /// The snippet name. + pub label: EcoString, + /// The snippet name. + pub label_detail: Option, + /// The snippet detail. + pub snippet: EcoString, + /// The snippet description. + pub description: EcoString, + /// Lazily parsed snippet. + #[serde(skip)] + pub parsed_snippet: OnceLock>, +} + +/// Tinymist's completion features. +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionFeat { + /// Whether to trigger completions on arguments (placeholders) of snippets. + #[serde(default)] + pub trigger_on_snippet_placeholders: bool, + /// Whether supports trigger suggest completion, a.k.a. auto-completion. + #[serde(default)] + pub trigger_suggest: bool, + /// Whether supports trigger parameter hint, a.k.a. signature help. + #[serde(default)] + pub trigger_parameter_hints: bool, + /// Whether supports trigger the command combining suggest and parameter + /// hints. + #[serde(default)] + pub trigger_suggest_and_parameter_hints: bool, + + /// Whether to enable postfix completion. + pub postfix: Option, + /// Whether to enable ufcs completion. + pub postfix_ufcs: Option, + /// Whether to enable ufcs completion (left variant). + pub postfix_ufcs_left: Option, + /// Whether to enable ufcs completion (right variant). + pub postfix_ufcs_right: Option, + /// Postfix snippets. + pub postfix_snippets: Option>, +} + +impl CompletionFeat { + pub(crate) fn any_ufcs(&self) -> bool { + self.ufcs() || self.ufcs_left() || self.ufcs_right() + } + pub(crate) fn postfix(&self) -> bool { + self.postfix.unwrap_or(true) + } + pub(crate) fn ufcs(&self) -> bool { + self.postfix() && self.postfix_ufcs.unwrap_or(true) + } + pub(crate) fn ufcs_left(&self) -> bool { + self.postfix() && self.postfix_ufcs_left.unwrap_or(true) + } + pub(crate) fn ufcs_right(&self) -> bool { + self.postfix() && self.postfix_ufcs_right.unwrap_or(true) + } + + pub(crate) fn postfix_snippets(&self) -> &[PostfixSnippet] { + self.postfix_snippets + .as_ref() + .map_or(DEFAULT_POSTFIX_SNIPPET.deref(), |v| v.as_slice()) + } +} + impl<'a> CompletionContext<'a> { pub fn world(&self) -> &LspWorld { self.ctx.world() } - pub fn scope_completions(&mut self, parens: bool, filter: impl Fn(&Value) -> bool) { - self.scope_completions_(parens, |v| v.map_or(true, &filter)); + fn seen_field(&mut self, field: Interned) -> bool { + !self.seen_fields.insert(field) } - pub fn strict_scope_completions(&mut self, parens: bool, filter: impl Fn(&Value) -> bool) { - self.scope_completions_(parens, |v| v.map_or(false, &filter)); + pub(crate) fn surrounding_syntax(&mut self) -> SurroundingSyntax { + check_previous_syntax(&self.leaf) + .or_else(|| check_surrounding_syntax(&self.leaf)) + .unwrap_or(SurroundingSyntax::Regular) } - fn seen_field(&mut self, field: Interned) -> bool { - !self.seen_fields.insert(field) + fn defines(&mut self) -> Option<(Source, Defines)> { + let src = self.ctx.source_by_id(self.root.span().id()?).ok()?; + + let mut defines = Defines { + types: self.ctx.type_check(&src), + defines: Default::default(), + }; + + let in_math = matches!( + self.leaf.parent_kind(), + Some(SyntaxKind::Equation) + | Some(SyntaxKind::Math) + | Some(SyntaxKind::MathFrac) + | Some(SyntaxKind::MathAttach) + ); + + let lib = self.world().library(); + let scope = if in_math { &lib.math } else { &lib.global } + .scope() + .clone(); + defines.insert_scope(&scope); + + descending_decls(self.leaf.clone(), |node| -> Option<()> { + match node { + DescentDecl::Ident(ident) => { + let ty = self.ctx.type_of_span(ident.span()).unwrap_or(Ty::Any); + defines.insert_ty(ty, ident.get()); + } + DescentDecl::ImportSource(src) => { + let ty = analyze_import_source(self.ctx, &defines.types, src)?; + let name = ty.name().as_ref().into(); + defines.insert_ty(ty, &name); + } + // todo: cache completion items + DescentDecl::ImportAll(mi) => { + let ty = analyze_import_source(self.ctx, &defines.types, mi.source())?; + ty.iface_surface(true, &mut ScopeChecker(&mut defines, self.ctx)); + } + } + None + }); + + Some((src, defines)) } - /// Add completions for definitions that are available at the cursor. - /// - /// Filters the global/math scope with the given filter. - pub fn scope_completions_(&mut self, parens: bool, filter: impl Fn(Option<&Value>) -> bool) { - let mut defined = BTreeMap::new(); + pub fn postfix_completions(&mut self, node: &LinkedNode, value: &Value) -> Option<()> { + if !self.ctx.analysis.completion_feat.postfix() { + return None; + } + let src = self.ctx.source_by_id(self.root.span().id()?).ok()?; - #[derive(Debug, Clone)] - enum DefKind { - Syntax(Span), - Instance(Span, Value), + let _ = node; + + let surrounding_syntax = self.surrounding_syntax(); + if !matches!(surrounding_syntax, SurroundingSyntax::Regular) { + return None; } - let mut try_insert = |name: EcoString, kind: (CompletionKind, DefKind)| { - if name.is_empty() { - return; + let cursor_mode = interpret_mode_at(Some(node)); + let is_content = value.ty() == Type::of::() + || value.ty() == Type::of::(); + log::debug!("post snippet is_content: {is_content}"); + + let rng = node.range(); + for snippet in self.ctx.analysis.completion_feat.postfix_snippets() { + if !snippet.mode.contains(&cursor_mode) { + continue; } - if let std::collections::btree_map::Entry::Vacant(entry) = defined.entry(name) { - entry.insert(kind); + let scope = match snippet.scope { + PostfixSnippetScope::Value => true, + PostfixSnippetScope::Content => is_content, + }; + if !scope { + continue; } - }; + log::debug!("post snippet: {}", snippet.label); + + static TYPST_SNIPPET_PLACEHOLDER_RE: LazyLock = + LazyLock::new(|| Regex::new(r"\$\{(.*?)\}").unwrap()); + + let parsed_snippet = snippet.parsed_snippet.get_or_init(|| { + let split = TYPST_SNIPPET_PLACEHOLDER_RE + .find_iter(&snippet.snippet) + .map(|s| (&s.as_str()[2..s.as_str().len() - 1], s.start(), s.end())) + .collect::>(); + if split.len() > 2 { + return None; + } - let types = (|| { - let id = self.root.span().id()?; - let src = self.ctx.source_by_id(id).ok()?; - Some(self.ctx.type_check(&src)) - })(); - let types = types.as_ref(); - - let mut ancestor = Some(self.leaf.clone()); - while let Some(node) = &ancestor { - let mut sibling = Some(node.clone()); - while let Some(node) = &sibling { - if let Some(v) = node.cast::() { - let kind = match v.kind() { - ast::LetBindingKind::Closure(..) => CompletionKind::Func, - ast::LetBindingKind::Normal(..) => CompletionKind::Variable, - }; - for ident in v.kind().bindings() { - try_insert( - ident.get().clone(), - (kind.clone(), DefKind::Syntax(ident.span())), - ); - } + let split0 = split[0]; + let split1 = split.get(1); + + if split0.0.contains("node") { + Some(ParsedSnippet { + node_before: snippet.snippet[..split0.1].into(), + node_before_before_cursor: None, + node_after: snippet.snippet[split0.2..].into(), + }) + } else { + split1.map(|split1| ParsedSnippet { + node_before_before_cursor: Some(snippet.snippet[..split0.1].into()), + node_before: snippet.snippet[split0.1..split1.1].into(), + node_after: snippet.snippet[split1.2..].into(), + }) } + }); + log::debug!("post snippet: {} on {:?}", snippet.label, parsed_snippet); + let Some(ParsedSnippet { + node_before, + node_before_before_cursor, + node_after, + }) = parsed_snippet + else { + continue; + }; - // todo: cache - if let Some(v) = node.cast::() { - let imports = v.imports(); - let anaylyze = node.children().find(|child| child.is::()); - let analyzed = anaylyze - .as_ref() - .and_then(|source| self.ctx.module_by_syntax(source)); - if analyzed.is_none() { - log::debug!("failed to analyze import: {:?}", anaylyze); - } + let base = Completion { + kind: CompletionKind::Syntax, + apply: Some("".into()), + label: snippet.label.clone(), + label_detail: snippet.label_detail.clone(), + detail: Some(snippet.description.clone()), + // range: Some(range), + ..Default::default() + }; + if let Some(node_before_before_cursor) = &node_before_before_cursor { + let node_content = node.get().clone().into_text(); + let before = TextEdit { + range: self.ctx.to_lsp_range(rng.start..self.from, &src), + new_text: node_before_before_cursor.into(), + }; - // import it self - if imports.is_none() || v.new_name().is_some() { - // todo: name of import syntactically + self.completions.push(Completion { + apply: Some(eco_format!("{node_before}{node_content}{node_after}")), + additional_text_edits: Some(vec![before]), + ..base.clone() + }); + } else { + let before = TextEdit { + range: self.ctx.to_lsp_range(rng.start..rng.start, &src), + new_text: node_before.as_ref().into(), + }; + let after = TextEdit { + range: self.ctx.to_lsp_range(rng.end..self.from, &src), + new_text: "".into(), + }; + self.completions.push(Completion { + apply: Some(node_after.clone()), + additional_text_edits: Some(vec![before, after]), + ..base + }); + } + } - let name = (|| { - if let Some(new_name) = v.new_name() { - return Some(new_name.get().clone()); - } - if let Some(module_ins) = &analyzed { - return module_ins.name().map(From::from); - } + Some(()) + } - // todo: name of import syntactically - None - })(); - - let def_kind = analyzed.clone().map(|module_ins| { - DefKind::Instance( - v.new_name() - .map(|n| n.span()) - .unwrap_or_else(Span::detached), - module_ins, - ) - }); + pub fn ufcs_completions(&mut self, node: &LinkedNode, value: &Value) { + if !self.ctx.analysis.completion_feat.any_ufcs() { + return; + } - if let Some((name, def_kind)) = name.zip(def_kind) { - try_insert(name, (CompletionKind::Module, def_kind)); - } - } + let _ = value; + let surrounding_syntax = self.surrounding_syntax(); + if !matches!(surrounding_syntax, SurroundingSyntax::Regular) { + return; + } - // import items - match (imports, analyzed) { - (Some(..), None) => { - // todo: name of import syntactically - } - (Some(e), Some(module_ins)) => { - let import_filter = match e { - ast::Imports::Wildcard => None, - ast::Imports::Items(e) => { - let mut filter = HashMap::new(); - for item in e.iter() { - match item { - ast::ImportItem::Simple(n) => { - filter.insert( - n.name().get().clone(), - DefKind::Syntax(n.span()), - ); - } - ast::ImportItem::Renamed(n) => { - filter.insert( - n.new_name().get().clone(), - DefKind::Syntax(n.span()), - ); - } - } - } - Some(filter) - } - }; - - if let Some(scope) = module_ins.scope() { - for (name, v, _) in scope.iter() { - let kind = value_to_completion_kind(v); - let def_kind = match &import_filter { - Some(import_filter) => { - let w = import_filter.get(name); - match w { - Some(DefKind::Syntax(span)) => { - Some(DefKind::Instance(*span, v.clone())) - } - Some(DefKind::Instance(span, v)) => { - Some(DefKind::Instance(*span, v.clone())) - } - None => None, - } - } - None => { - Some(DefKind::Instance(Span::detached(), v.clone())) - } - }; - if let Some(def_kind) = def_kind { - try_insert(name.clone(), (kind, def_kind)); - } - } - } else if let Some(filter) = import_filter { - for (name, def_kind) in filter { - try_insert(name, (CompletionKind::Variable, def_kind)); - } - } - } - _ => {} - } - } + let Some((src, defines)) = self.defines() else { + return; + }; + + log::debug!("defines: {:?}", defines.defines.len()); + let mut kind_checker = CompletionKindChecker { + symbols: HashSet::default(), + functions: HashSet::default(), + }; - sibling = node.prev_sibling(); + let rng = node.range(); + + let is_content_block = node.kind() == SyntaxKind::ContentBlock; + + let lb = if is_content_block { "" } else { "(" }; + let rb = if is_content_block { "" } else { ")" }; + + // we don't check literal type here for faster completion + for (name, ty) in defines.defines { + // todo: filter ty + if name.is_empty() { + continue; } - if let Some(parent) = node.parent() { - if let Some(v) = parent.cast::() { - if node.prev_sibling_kind() != Some(SyntaxKind::In) { - let pattern = v.pattern(); - for ident in pattern.bindings() { - try_insert( - ident.get().clone(), - (CompletionKind::Variable, DefKind::Syntax(ident.span())), - ); + kind_checker.check(&ty); + + if kind_checker.symbols.iter().min().copied().is_some() { + continue; + } + if kind_checker.functions.is_empty() { + continue; + } + + let label_detail = ty.describe().map(From::from).or_else(|| Some("any".into())); + let base = Completion { + kind: CompletionKind::Func, + label_detail, + apply: Some("".into()), + // range: Some(range), + command: self.ctx.analysis.trigger_on_snippet_with_param_hint(true), + ..Default::default() + }; + let fn_feat = FnCompletionFeat::default().check(kind_checker.functions.iter()); + + log::debug!("fn_feat: {name} {ty:?} -> {fn_feat:?}"); + + if fn_feat.min_pos() < 1 || !fn_feat.next_arg_is_content { + continue; + } + log::debug!("checked ufcs: {ty:?}"); + if self.ctx.analysis.completion_feat.ufcs() && fn_feat.min_pos() == 1 { + let before = TextEdit { + range: self.ctx.to_lsp_range(rng.start..rng.start, &src), + new_text: format!("{name}{lb}"), + }; + let after = TextEdit { + range: self.ctx.to_lsp_range(rng.end..self.from, &src), + new_text: rb.into(), + }; + + self.completions.push(Completion { + label: name.clone(), + additional_text_edits: Some(vec![before, after]), + ..base.clone() + }); + } + let more_args = fn_feat.min_pos() > 1 || fn_feat.min_named() > 0; + if self.ctx.analysis.completion_feat.ufcs_left() && more_args { + let node_content = node.get().clone().into_text(); + let before = TextEdit { + range: self.ctx.to_lsp_range(rng.start..self.from, &src), + new_text: format!("{name}{lb}"), + }; + self.completions.push(Completion { + apply: if is_content_block { + Some(eco_format!("(${{}}){node_content}")) + } else { + Some(eco_format!("${{}}, {node_content})")) + }, + label: eco_format!("{name}("), + additional_text_edits: Some(vec![before]), + ..base.clone() + }); + } + if self.ctx.analysis.completion_feat.ufcs_right() && more_args { + let before = TextEdit { + range: self.ctx.to_lsp_range(rng.start..rng.start, &src), + new_text: format!("{name}("), + }; + let after = TextEdit { + range: self.ctx.to_lsp_range(rng.end..self.from, &src), + new_text: "".into(), + }; + self.completions.push(Completion { + apply: Some(eco_format!("${{}})")), + label: eco_format!("{name})"), + additional_text_edits: Some(vec![before, after]), + ..base + }); + } + } + } + + /// Add completions for definitions that are available at the cursor. + /// + /// Filters the global/math scope with the given filter. + pub fn scope_completions(&mut self, parens: bool) { + let Some((_, defines)) = self.defines() else { + return; + }; + + let defines = defines.defines; + + let surrounding_syntax = self.surrounding_syntax(); + let mode = interpret_mode_at(Some(&self.leaf)); + + let mut kind_checker = CompletionKindChecker { + symbols: HashSet::default(), + functions: HashSet::default(), + }; + + let filter = |c: &CompletionKindChecker| { + match surrounding_syntax { + SurroundingSyntax::Regular => true, + SurroundingSyntax::Selector => 'selector: { + for func in &c.functions { + if func.element().is_some() { + break 'selector true; } } + + false } - if let Some(v) = node.cast::() { - for param in v.params().children() { - match param { - ast::Param::Pos(pattern) => { - for ident in pattern.bindings() { - try_insert( - ident.get().clone(), - (CompletionKind::Variable, DefKind::Syntax(ident.span())), - ); - } - } - ast::Param::Named(n) => try_insert( - n.name().get().clone(), - (CompletionKind::Variable, DefKind::Syntax(n.name().span())), - ), - ast::Param::Spread(s) => { - if let Some(sink_ident) = s.sink_ident() { - try_insert( - sink_ident.get().clone(), - (CompletionKind::Variable, DefKind::Syntax(s.span())), - ) - } + SurroundingSyntax::ShowTransform => !c.functions.is_empty(), + SurroundingSyntax::SetRule => 'set_rule: { + // todo: user defined elements + for func in &c.functions { + if let Some(elem) = func.element() { + if elem.params().iter().any(|param| param.settable) { + break 'set_rule true; } } } + + false } + } + }; - ancestor = Some(parent.clone()); + // we don't check literal type here for faster completion + for (name, ty) in defines { + if name.is_empty() { continue; } - break; - } - - let in_math = matches!( - self.leaf.parent_kind(), - Some(SyntaxKind::Equation) - | Some(SyntaxKind::Math) - | Some(SyntaxKind::MathFrac) - | Some(SyntaxKind::MathAttach) - ); - - let lib = self.world().library(); - let scope = if in_math { &lib.math } else { &lib.global } - .scope() - .clone(); - for (name, value, _) in scope.iter() { - if filter(Some(value)) && !defined.contains_key(name) { - defined.insert( - name.clone(), - ( - value_to_completion_kind(value), - DefKind::Instance(Span::detached(), value.clone()), - ), - ); + kind_checker.check(&ty); + if !filter(&kind_checker) { + continue; } - } - - enum SurroundingSyntax { - Regular, - Selector, - SetRule, - } - - let surrounding_syntax = check_surrounding_syntax(&self.leaf) - .or_else(|| check_previous_syntax(&self.leaf)) - .unwrap_or(SurroundingSyntax::Regular); - for (name, (kind, def_kind)) in defined { - if !filter(None) || name.is_empty() { + if let Some(ch) = kind_checker.symbols.iter().min().copied() { + // todo: describe all chars + let kind = CompletionKind::Symbol(ch); + self.completions.push(Completion { + kind, + label: name, + label_detail: Some(symbol_label_detail(ch)), + detail: Some(symbol_detail(ch)), + ..Completion::default() + }); continue; } - let span = match def_kind { - DefKind::Syntax(span) => span, - DefKind::Instance(span, _) => span, - }; - // we don't check literal type here for faster completion - let ty_detail = if let CompletionKind::Symbol(c) = &kind { - Some(symbol_label_detail(*c)) - } else { - types - .and_then(|types| { - let ty = types.type_of_span(span)?; - let ty = types.simplify(ty, false); - types.describe(&ty).map(From::from) - }) - .or_else(|| { - if let DefKind::Instance(_, v) = &def_kind { - Some(describe_value(self.ctx, v)) - } else { - None - } - }) - .or_else(|| Some("any".into())) - }; - let detail = if let CompletionKind::Symbol(c) = &kind { - Some(symbol_detail(*c)) - } else { - ty_detail.clone() - }; - if kind == CompletionKind::Func { + let label_detail = ty.describe().map(From::from).or_else(|| Some("any".into())); + + log::debug!("scope completions!: {name} {ty:?} {label_detail:?}"); + let detail = label_detail.clone(); + + if !kind_checker.functions.is_empty() { let base = Completion { - kind: kind.clone(), - label_detail: ty_detail, - command: self - .trigger_parameter_hints - .then_some("editor.action.triggerParameterHints"), + kind: CompletionKind::Func, + label_detail, + command: self.ctx.analysis.trigger_on_snippet_with_param_hint(true), ..Default::default() }; - let zero_args = match &def_kind { - DefKind::Instance(_, Value::Func(func)) => func - .params() - .is_some_and(|params| params.iter().all(|param| param.name == "self")), - _ => false, - }; - let is_element = match &def_kind { - DefKind::Instance(_, Value::Func(func)) => func.element().is_some(), - _ => false, - }; - log::debug!("is_element: {} {:?} -> {:?}", name, def_kind, is_element); + let fn_feat = FnCompletionFeat::default().check(kind_checker.functions.iter()); - if !zero_args && matches!(surrounding_syntax, SurroundingSyntax::Regular) { + log::debug!("fn_feat: {name} {ty:?} -> {fn_feat:?}"); + + if matches!(surrounding_syntax, SurroundingSyntax::ShowTransform) + && (fn_feat.min_pos() > 0 || fn_feat.min_named() > 0) + { self.completions.push(Completion { label: eco_format!("{}.with", name), apply: Some(eco_format!("{}.with(${{}})", name)), ..base.clone() }); } - if is_element && !matches!(surrounding_syntax, SurroundingSyntax::SetRule) { + if fn_feat.is_element && matches!(surrounding_syntax, SurroundingSyntax::Selector) { self.completions.push(Completion { label: eco_format!("{}.where", name), apply: Some(eco_format!("{}.where(${{}})", name)), @@ -344,356 +510,543 @@ impl<'a> CompletionContext<'a> { let bad_instantiate = matches!( surrounding_syntax, SurroundingSyntax::Selector | SurroundingSyntax::SetRule - ) && !is_element; + ) && !fn_feat.is_element; if !bad_instantiate { - if !parens { + if !parens || matches!(surrounding_syntax, SurroundingSyntax::Selector) { self.completions.push(Completion { label: name, ..base }); - } else if zero_args { + } else if fn_feat.min_pos() < 1 && !fn_feat.has_rest { self.completions.push(Completion { apply: Some(eco_format!("{}()${{}}", name)), label: name, ..base }); } else { + let accept_content_arg = fn_feat.next_arg_is_content && !fn_feat.has_rest; + let scope_reject_content = matches!(mode, InterpretMode::Math) + || matches!( + surrounding_syntax, + SurroundingSyntax::Selector | SurroundingSyntax::SetRule + ); self.completions.push(Completion { - apply: Some(eco_format!("{}(${{}})", name)), - label: name, - ..base + apply: Some(eco_format!("{name}(${{}})")), + label: name.clone(), + ..base.clone() }); + if !scope_reject_content && accept_content_arg { + self.completions.push(Completion { + apply: Some(eco_format!("{name}[${{}}]")), + label: eco_format!("{name}.bracket"), + ..base + }); + }; } } - } else if let DefKind::Instance(_, v) = def_kind { - let bad_instantiate = matches!( - surrounding_syntax, - SurroundingSyntax::Selector | SurroundingSyntax::SetRule - ) && !matches!(&v, Value::Func(func) if func.element().is_some()); - if !bad_instantiate { - self.value_completion_( - Some(name), - &v, - parens, - ty_detail.clone(), - detail.as_deref(), - ); - } - } else { - self.completions.push(Completion { - kind, - label: name, - label_detail: ty_detail.clone(), - detail, - ..Completion::default() - }); - } - } - - fn check_surrounding_syntax(mut leaf: &LinkedNode) -> Option { - use SurroundingSyntax::*; - let mut met_args = false; - while let Some(parent) = leaf.parent() { - log::debug!( - "check_surrounding_syntax: {:?}::{:?}", - parent.kind(), - leaf.kind() - ); - match parent.kind() { - SyntaxKind::CodeBlock | SyntaxKind::ContentBlock | SyntaxKind::Equation => { - return Some(Regular); - } - SyntaxKind::Named => { - return Some(Regular); - } - SyntaxKind::Args => { - met_args = true; - } - SyntaxKind::SetRule => { - let rule = parent.get().cast::()?; - if met_args || encolsed_by(parent, rule.condition().map(|s| s.span()), leaf) - { - return Some(Regular); - } else { - return Some(SetRule); - } - } - SyntaxKind::ShowRule => { - let rule = parent.get().cast::()?; - if encolsed_by(parent, Some(rule.transform().span()), leaf) { - return Some(Regular); - } else { - return Some(Selector); // query's first argument - } - } - _ => {} - } - - leaf = parent; + continue; } - None + let kind = ty_to_completion_kind(&ty); + self.completions.push(Completion { + kind, + label: name, + label_detail: label_detail.clone(), + detail, + ..Completion::default() + }); } + } +} - fn check_previous_syntax(leaf: &LinkedNode) -> Option { - let mut leaf = leaf.clone(); - if leaf.kind().is_trivia() { - leaf = leaf.prev_sibling()?; - } - if matches!(leaf.kind(), SyntaxKind::ShowRule | SyntaxKind::SetRule) { - return check_surrounding_syntax(&leaf.rightmost_leaf()?); - } +#[derive(Debug, Clone, Copy)] +pub(crate) enum SurroundingSyntax { + Regular, + Selector, + ShowTransform, + SetRule, +} - if matches!(leaf.kind(), SyntaxKind::Show) { - return Some(SurroundingSyntax::Selector); +fn check_surrounding_syntax(mut leaf: &LinkedNode) -> Option { + use SurroundingSyntax::*; + let mut met_args = false; + while let Some(parent) = leaf.parent() { + log::debug!( + "check_surrounding_syntax: {:?}::{:?}", + parent.kind(), + leaf.kind() + ); + match parent.kind() { + SyntaxKind::CodeBlock | SyntaxKind::ContentBlock | SyntaxKind::Equation => { + return Some(Regular); } - if matches!(leaf.kind(), SyntaxKind::Set) { - return Some(SurroundingSyntax::SetRule); + SyntaxKind::Named => { + return Some(Regular); } - - None - } - } -} - -fn describe_value(ctx: &mut LocalContext, v: &Value) -> EcoString { - match v { - Value::Func(f) => { - let mut f = f; - while let typst::foundations::func::Repr::With(with_f) = f.inner() { - f = &with_f.0; + SyntaxKind::Args => { + met_args = true; } - - let sig = ctx.sig_of_func(f.clone()); - sig.primary() - .ty() - .describe() - .unwrap_or_else(|| "function".into()) - .into() - } - Value::Module(m) => { - if let Some(fid) = m.file_id() { - let package = fid.package(); - let path = unix_slash(fid.vpath().as_rootless_path()); - if let Some(package) = package { - return eco_format!("{package}:{path}"); + SyntaxKind::SetRule => { + let rule = parent.get().cast::()?; + if met_args || encolsed_by(parent, rule.condition().map(|s| s.span()), leaf) { + return Some(Regular); + } else { + return Some(SetRule); } - return path.into(); } + SyntaxKind::ShowRule => { + let rule = parent.get().cast::()?; + let colon = rule + .to_untyped() + .children() + .find(|s| s.kind() == SyntaxKind::Colon); + let Some(colon) = colon.and_then(|colon| parent.find(colon.span())) else { + // incomplete show rule + return Some(Selector); + }; - "module".into() + if leaf.offset() >= colon.offset() { + return Some(ShowTransform); + } else { + return Some(Selector); // query's first argument + } + } + _ => {} } - _ => v.ty().repr(), + + leaf = parent; } -} -fn encolsed_by(parent: &LinkedNode, s: Option, leaf: &LinkedNode) -> bool { - s.and_then(|s| parent.find(s)?.find(leaf.span())).is_some() + None } -fn sort_and_explicit_code_completion(ctx: &mut CompletionContext) { - let mut completions = std::mem::take(&mut ctx.completions); - let explict = ctx.explicit; - ctx.explicit = true; - complete_code(ctx, true); - ctx.explicit = explict; - - log::debug!( - "sort_and_explicit_code_completion: {:#?} {:#?}", - completions, - ctx.completions - ); - - completions.sort_by(|a, b| { - a.sort_text - .as_ref() - .cmp(&b.sort_text.as_ref()) - .then_with(|| a.label.cmp(&b.label)) - }); - ctx.completions.sort_by(|a, b| { - a.sort_text - .as_ref() - .cmp(&b.sort_text.as_ref()) - .then_with(|| a.label.cmp(&b.label)) - }); - - // todo: this is a bit messy, we can refactor for improving maintainability - // The messy code will finally gone, but to help us go over the mess stage, I - // drop some comment here. - // - // currently, there are only path completions in ctx.completions2 - // and type/named param/positional param completions in completions - // and all rest less relevant completions inctx.completions - for (i, compl) in ctx.completions2.iter_mut().enumerate() { - compl.sort_text = Some(format!("{i:03}")); +fn check_previous_syntax(leaf: &LinkedNode) -> Option { + let mut leaf = leaf.clone(); + if leaf.kind().is_trivia() { + leaf = leaf.prev_sibling()?; } - let sort_base = ctx.completions2.len(); - for (i, compl) in (completions.iter_mut().chain(ctx.completions.iter_mut())).enumerate() { - compl.sort_text = Some(eco_format!("{i:03}", i = i + sort_base)); + if matches!(leaf.kind(), SyntaxKind::ShowRule | SyntaxKind::SetRule) { + return check_surrounding_syntax(&leaf.rightmost_leaf()?); } - log::debug!( - "sort_and_explicit_code_completion after: {:#?} {:#?}", - completions, - ctx.completions - ); - - ctx.completions.append(&mut completions); + if matches!(leaf.kind(), SyntaxKind::Show) { + return Some(SurroundingSyntax::Selector); + } + if matches!(leaf.kind(), SyntaxKind::Set) { + return Some(SurroundingSyntax::SetRule); + } - log::debug!("sort_and_explicit_code_completion: {:?}", ctx.completions); + None } -pub fn value_to_completion_kind(value: &Value) -> CompletionKind { - match value { - Value::Func(..) => CompletionKind::Func, - Value::Module(..) => CompletionKind::Module, - Value::Type(..) => CompletionKind::Type, - Value::Symbol(s) => CompletionKind::Symbol(s.get()), - _ => CompletionKind::Constant, - } +#[derive(BindTyCtx)] +#[bind(types)] +struct Defines { + types: Arc, + defines: BTreeMap, } -/// Add completions for the parameters of a function. -pub fn param_completions<'a>( - ctx: &mut CompletionContext<'a>, - callee: ast::Expr<'a>, - set: bool, - args: ast::Args<'a>, -) { - let Some(cc) = ctx - .root - .find(callee.span()) - .and_then(|callee| resolve_call_target(ctx.ctx.shared(), &callee)) - else { - return; - }; - // todo: regards call convention - let this = cc.method_this().cloned(); - let func = cc.callee(); - - use typst::foundations::func::Repr; - let mut func = func; - while let Repr::With(f) = func.inner() { - // todo: complete with positional arguments - // with_args.push(ArgValue::Instance(f.1.clone())); - func = f.0.clone(); - } +impl Defines { + fn insert(&mut self, name: EcoString, item: Ty) { + if name.is_empty() { + return; + } - let pos_index = - param_index_at_leaf(&ctx.leaf, &func, args).map(|i| if this.is_some() { i + 1 } else { i }); + if let std::collections::btree_map::Entry::Vacant(entry) = self.defines.entry(name.clone()) + { + entry.insert(item); + } + } - let signature = ctx.ctx.sig_of_func(func.clone()); + fn insert_ty(&mut self, ty: Ty, name: &EcoString) { + self.insert(name.clone(), ty); + } - let leaf_type = ctx.ctx.literal_type_of_node(ctx.leaf.clone()); - log::debug!("pos_param_completion_by_type: {:?}", leaf_type); + fn insert_scope(&mut self, scope: &Scope) { + // filter(Some(value)) && + for (name, value, _) in scope.iter() { + if !self.defines.contains_key(name) { + self.insert(name.clone(), Ty::Value(InsTy::new(value.clone()))); + } + } + } +} - for arg in args.items() { - if let ast::Arg::Named(named) = arg { - ctx.seen_field(named.name().into()); +fn analyze_import_source(ctx: &LocalContext, types: &TypeScheme, s: ast::Expr) -> Option { + if let Some(res) = types.type_of_span(s.span()) { + if !matches!(res.value(), Some(Value::Str(..))) { + return Some(types.simplify(res, false)); } } - let primary_sig = signature.primary(); + let m = ctx.module_by_syntax(s.to_untyped())?; + Some(Ty::Value(InsTy::new_at(m, s.span()))) +} - 'pos_check: { - let mut doc = None; +#[derive(BindTyCtx)] +#[bind(0)] +struct ScopeChecker<'a>(&'a mut Defines, &'a mut LocalContext); + +impl<'a> IfaceChecker for ScopeChecker<'a> { + fn check( + &mut self, + iface: Iface, + _ctx: &mut crate::ty::IfaceCheckContext, + _pol: bool, + ) -> Option<()> { + match iface { + // dict is not importable + Iface::Dict(..) | Iface::Value { .. } => {} + Iface::Element { val, .. } => { + self.0.insert_scope(val.scope()); + } + Iface::Type { val, .. } => { + self.0.insert_scope(val.scope()); + } + Iface::Module { val, .. } => { + let ti = self.1.type_check_by_id(val); + if !ti.valid { + self.0.insert_scope(self.1.module_by_id(val).ok()?.scope()); + } else { + for (name, ty) in ti.exports.iter() { + // todo: Interned -> EcoString here + let ty = ti.simplify(ty.clone(), false); + self.0.insert(name.as_ref().into(), ty); + } + } + } + Iface::ModuleVal { val, .. } => { + self.0.insert_scope(val.scope()); + } + } + None + } +} - if let Some(pos_index) = pos_index { - let pos = primary_sig.get_pos(pos_index); - log::debug!("pos_param_completion_to: {:?}", pos); +pub(crate) struct CompletionKindChecker { + pub(crate) symbols: HashSet, + pub(crate) functions: HashSet, +} +impl CompletionKindChecker { + fn reset(&mut self) { + self.symbols.clear(); + self.functions.clear(); + } - if let Some(pos) = pos { - if set && !pos.attrs.settable { - break 'pos_check; + fn check(&mut self, ty: &Ty) { + self.reset(); + match ty { + Ty::Value(val) => match &val.val { + Value::Type(t) if t.constructor().is_ok() => { + self.functions.insert(ty.clone()); } - - if let Some(docs) = &pos.docs { - doc = Some(plain_docs_sentence(docs)); + Value::Func(..) => { + self.functions.insert(ty.clone()); } - - if pos.attrs.positional { - type_completion(ctx, &pos.ty, doc.as_deref()); + Value::Symbol(s) => { + self.symbols.insert(s.get()); } + _ => {} + }, + Ty::Func(..) | Ty::With(..) => { + self.functions.insert(ty.clone()); } - } - - if let Some(leaf_type) = leaf_type { - type_completion(ctx, &leaf_type, doc.as_deref()); + Ty::Builtin(BuiltinTy::TypeType(t)) if t.constructor().is_ok() => { + self.functions.insert(ty.clone()); + } + Ty::Builtin(BuiltinTy::Element(..)) => { + self.functions.insert(ty.clone()); + } + Ty::Let(l) => { + for ty in l.ubs.iter().chain(l.lbs.iter()) { + self.check(ty); + } + } + Ty::Any + | Ty::Builtin(..) + | Ty::Boolean(..) + | Ty::Param(..) + | Ty::Union(..) + | Ty::Var(..) + | Ty::Dict(..) + | Ty::Array(..) + | Ty::Tuple(..) + | Ty::Args(..) + | Ty::Pattern(..) + | Ty::Select(..) + | Ty::Unary(..) + | Ty::Binary(..) + | Ty::If(..) => {} } } +} - for param in primary_sig.named() { - let name = ¶m.name; - if ctx.seen_field(name.as_ref().into()) { - continue; - } - log::debug!( - "pos_named_param_completion_to({set:?}): {name:?} {:?}", - param.attrs.settable - ); +#[derive(Default, Debug)] +struct FnCompletionFeat { + min_pos: Option, + min_named: Option, + has_rest: bool, + next_arg_is_content: bool, + is_element: bool, +} - if set && !param.attrs.settable { - continue; +impl FnCompletionFeat { + fn check<'a>(mut self, fns: impl ExactSizeIterator) -> Self { + for ty in fns { + self.check_one(ty, 0); } - let _d = OnceCell::new(); - let docs = || { - _d.get_or_init(|| param.docs.as_ref().map(|d| plain_docs_sentence(d.as_str()))) - .clone() - }; + self + } - if param.attrs.named { - let compl = Completion { - kind: CompletionKind::Field, - label: param.name.as_ref().into(), - apply: Some(eco_format!("{}: ${{}}", param.name)), - detail: docs(), - label_detail: None, - command: ctx - .trigger_named_completion - .then_some("tinymist.triggerNamedCompletion"), - ..Completion::default() - }; - match param.ty { - Ty::Builtin(BuiltinTy::TextSize) => { - for size_template in &[ - "10.5pt", "12pt", "9pt", "14pt", "8pt", "16pt", "18pt", "20pt", "22pt", - "24pt", "28pt", - ] { - let compl = compl.clone(); - ctx.completions.push(Completion { - label: eco_format!("{}: {}", param.name, size_template), - apply: None, - ..compl - }); - } + fn min_pos(&self) -> usize { + self.min_pos.unwrap_or_default() + } + + fn min_named(&self) -> usize { + self.min_named.unwrap_or_default() + } + + fn check_one(&mut self, ty: &Ty, pos: usize) { + match ty { + Ty::Value(val) => match &val.val { + Value::Type(ty) => { + self.check_one(&Ty::Builtin(BuiltinTy::Type(*ty)), pos); } - Ty::Builtin(BuiltinTy::Dir) => { - for dir_template in &["ltr", "rtl", "ttb", "btt"] { - let compl = compl.clone(); - ctx.completions.push(Completion { - label: eco_format!("{}: {}", param.name, dir_template), - apply: None, - ..compl - }); + Value::Func(func) => { + if func.element().is_some() { + self.is_element = true; } + let sig = func_signature(func.clone()).type_sig(); + self.check_sig(&sig, pos); } - _ => {} + Value::None + | Value::Auto + | Value::Bool(_) + | Value::Int(_) + | Value::Float(..) + | Value::Length(..) + | Value::Angle(..) + | Value::Ratio(..) + | Value::Relative(..) + | Value::Fraction(..) + | Value::Color(..) + | Value::Gradient(..) + | Value::Pattern(..) + | Value::Symbol(..) + | Value::Version(..) + | Value::Str(..) + | Value::Bytes(..) + | Value::Label(..) + | Value::Datetime(..) + | Value::Decimal(..) + | Value::Duration(..) + | Value::Content(..) + | Value::Styles(..) + | Value::Array(..) + | Value::Dict(..) + | Value::Args(..) + | Value::Module(..) + | Value::Plugin(..) + | Value::Dyn(..) => {} + }, + Ty::Func(sig) => self.check_sig(sig, pos), + Ty::With(w) => { + self.check_one(&w.sig, pos + w.with.positional_params().len()); } - ctx.completions.push(compl); + Ty::Builtin(b) => match b { + BuiltinTy::Element(func) => { + self.is_element = true; + let func = (*func).into(); + let sig = func_signature(func).type_sig(); + self.check_sig(&sig, pos); + } + BuiltinTy::Type(ty) => { + let func = ty.constructor().ok(); + if let Some(func) = func { + let sig = func_signature(func).type_sig(); + self.check_sig(&sig, pos); + } + } + BuiltinTy::TypeType(..) => {} + BuiltinTy::Clause + | BuiltinTy::Undef + | BuiltinTy::Content + | BuiltinTy::Space + | BuiltinTy::None + | BuiltinTy::Break + | BuiltinTy::Continue + | BuiltinTy::Infer + | BuiltinTy::FlowNone + | BuiltinTy::Auto + | BuiltinTy::Args + | BuiltinTy::Color + | BuiltinTy::TextSize + | BuiltinTy::TextFont + | BuiltinTy::TextLang + | BuiltinTy::TextRegion + | BuiltinTy::Label + | BuiltinTy::CiteLabel + | BuiltinTy::RefLabel + | BuiltinTy::Dir + | BuiltinTy::Length + | BuiltinTy::Float + | BuiltinTy::Stroke + | BuiltinTy::Margin + | BuiltinTy::Inset + | BuiltinTy::Outset + | BuiltinTy::Radius + | BuiltinTy::Tag(..) + | BuiltinTy::Module(..) + | BuiltinTy::Path(..) => {} + }, + Ty::Any + | Ty::Boolean(..) + | Ty::Param(..) + | Ty::Union(..) + | Ty::Let(..) + | Ty::Var(..) + | Ty::Dict(..) + | Ty::Array(..) + | Ty::Tuple(..) + | Ty::Args(..) + | Ty::Pattern(..) + | Ty::Select(..) + | Ty::Unary(..) + | Ty::Binary(..) + | Ty::If(..) => {} } + } - if param.attrs.positional { - type_completion(ctx, ¶m.ty, docs().as_deref()); - } + // todo: sig is element + fn check_sig(&mut self, sig: &SigTy, idx: usize) { + let pos_size = sig.positional_params().len(); + self.has_rest = self.has_rest || sig.rest_param().is_some(); + self.next_arg_is_content = + self.next_arg_is_content || sig.pos(idx).map_or(false, |ty| ty.is_content(&())); + let name_size = sig.named_params().len(); + let left_pos = pos_size.saturating_sub(idx); + self.min_pos = self + .min_pos + .map_or(Some(left_pos), |v| Some(v.min(left_pos))); + self.min_named = self + .min_named + .map_or(Some(name_size), |v| Some(v.min(name_size))); } +} - sort_and_explicit_code_completion(ctx); - if ctx.before.ends_with(',') { - ctx.enrich(" ", ""); +fn encolsed_by(parent: &LinkedNode, s: Option, leaf: &LinkedNode) -> bool { + s.and_then(|s| parent.find(s)?.find(leaf.span())).is_some() +} + +pub fn ty_to_completion_kind(ty: &Ty) -> CompletionKind { + match ty { + Ty::Value(ty) => value_to_completion_kind(&ty.val), + Ty::Func(..) | Ty::With(..) => CompletionKind::Func, + Ty::Any => CompletionKind::Variable, + Ty::Builtin(b) => match b { + BuiltinTy::Module(..) => CompletionKind::Module, + BuiltinTy::Type(..) | BuiltinTy::TypeType(..) => CompletionKind::Type, + _ => CompletionKind::Variable, + }, + Ty::Let(l) => fold_ty_kind(l.ubs.iter().chain(l.lbs.iter())), + Ty::Union(u) => fold_ty_kind(u.iter()), + Ty::Boolean(..) + | Ty::Param(..) + | Ty::Var(..) + | Ty::Dict(..) + | Ty::Array(..) + | Ty::Tuple(..) + | Ty::Args(..) + | Ty::Pattern(..) + | Ty::Select(..) + | Ty::Unary(..) + | Ty::Binary(..) + | Ty::If(..) => CompletionKind::Constant, + } +} + +fn fold_ty_kind<'a>(tys: impl Iterator) -> CompletionKind { + tys.fold(None, |acc, ty| match acc { + Some(CompletionKind::Variable) => Some(CompletionKind::Variable), + Some(acc) => { + let kind = ty_to_completion_kind(ty); + if acc == kind { + Some(acc) + } else { + Some(CompletionKind::Variable) + } + } + None => Some(ty_to_completion_kind(ty)), + }) + .unwrap_or(CompletionKind::Variable) +} + +pub fn value_to_completion_kind(value: &Value) -> CompletionKind { + match value { + Value::Func(..) => CompletionKind::Func, + Value::Plugin(..) | Value::Module(..) => CompletionKind::Module, + Value::Type(..) => CompletionKind::Type, + Value::Symbol(s) => CompletionKind::Symbol(s.get()), + Value::None + | Value::Auto + | Value::Bool(..) + | Value::Int(..) + | Value::Float(..) + | Value::Length(..) + | Value::Angle(..) + | Value::Ratio(..) + | Value::Relative(..) + | Value::Fraction(..) + | Value::Color(..) + | Value::Gradient(..) + | Value::Pattern(..) + | Value::Version(..) + | Value::Str(..) + | Value::Bytes(..) + | Value::Label(..) + | Value::Datetime(..) + | Value::Decimal(..) + | Value::Duration(..) + | Value::Content(..) + | Value::Styles(..) + | Value::Array(..) + | Value::Dict(..) + | Value::Args(..) + | Value::Dyn(..) => CompletionKind::Variable, } } +// if param.attrs.named { +// match param.ty { +// Ty::Builtin(BuiltinTy::TextSize) => { +// for size_template in &[ +// "10.5pt", "12pt", "9pt", "14pt", "8pt", "16pt", "18pt", +// "20pt", "22pt", "24pt", "28pt", +// ] { +// let compl = compl.clone(); +// ctx.completions.push(Completion { +// label: eco_format!("{}: {}", param.name, size_template), +// apply: None, +// ..compl +// }); +// } +// } +// Ty::Builtin(BuiltinTy::Dir) => { +// for dir_template in &["ltr", "rtl", "ttb", "btt"] { +// let compl = compl.clone(); +// ctx.completions.push(Completion { +// label: eco_format!("{}: {}", param.name, dir_template), +// apply: None, +// ..compl +// }); +// } +// } +// _ => {} +// } +// ctx.completions.push(compl); +// } + fn type_completion( ctx: &mut CompletionContext<'_>, infer_type: &Ty, @@ -718,8 +1071,18 @@ fn type_completion( ctx.snippet_completion("false", "false", "No / Disabled."); ctx.snippet_completion("true", "true", "Yes / Enabled."); } - Ty::Field(f) => { - let f = &f.name; + Ty::Param(p) => { + // todo: variadic + + let docs = docs.or_else(|| p.docs.as_deref()); + if p.attrs.positional { + type_completion(ctx, &p.ty, docs); + } + if !p.attrs.named { + return Some(()); + } + + let f = &p.name; if ctx.seen_field(f.clone()) { return Some(()); } @@ -736,10 +1099,9 @@ fn type_completion( kind: CompletionKind::Field, label: f.into(), apply: Some(eco_format!("{}: ${{}}", f)), + label_detail: p.ty.describe(), detail: docs.map(Into::into), - command: ctx - .trigger_named_completion - .then_some("tinymist.triggerNamedCompletion"), + command: ctx.ctx.analysis.trigger_on_snippet_with_param_hint(true), ..Completion::default() }); } @@ -757,6 +1119,7 @@ fn type_completion( BuiltinTy::Infer => return None, BuiltinTy::FlowNone => return None, BuiltinTy::Tag(..) => return None, + BuiltinTy::Module(..) => return None, BuiltinTy::Path(p) => { let source = ctx.ctx.source_by_id(ctx.root.span().id()?).ok()?; @@ -811,8 +1174,6 @@ fn type_completion( "color.hsl(${h}, ${s}, ${l}, ${a})", "A custom HSLA color.", ); - let color_ty = Type::of::(); - ctx.strict_scope_completions(false, |value| value.ty() == color_ty); } BuiltinTy::TextSize => return None, BuiltinTy::TextLang => { @@ -841,10 +1202,7 @@ fn type_completion( }); } } - BuiltinTy::Dir => { - let ty = Type::of::(); - ctx.strict_scope_completions(false, |value| value.ty() == ty); - } + BuiltinTy::Dir => {} BuiltinTy::TextFont => { ctx.font_completions(); } @@ -870,8 +1228,6 @@ fn type_completion( ctx.snippet_completion("cm", "${1}cm", "Centimeter length unit."); ctx.snippet_completion("in", "${1}in", "Inch length unit."); ctx.snippet_completion("em", "${1}em", "Em length unit."); - let length_ty = Type::of::(); - ctx.strict_scope_completions(false, |value| value.ty() == length_ty); type_completion(ctx, &Ty::Builtin(BuiltinTy::Auto), docs); } BuiltinTy::Float => { @@ -886,7 +1242,7 @@ fn type_completion( BuiltinTy::RefLabel => { ctx.ref_completions(); } - BuiltinTy::Type(ty) => { + BuiltinTy::TypeType(ty) | BuiltinTy::Type(ty) => { if *ty == Type::of::() { let docs = docs.or(Some("Nothing.")); type_completion(ctx, &Ty::Builtin(BuiltinTy::None), docs); @@ -914,7 +1270,6 @@ fn type_completion( detail: Some(eco_format!("A value of type {ty}.")), ..Completion::default() }); - ctx.strict_scope_completions(false, |value| value.ty() == *ty); } } BuiltinTy::Element(e) => { @@ -961,90 +1316,9 @@ fn type_completion( Some(()) } -/// Add completions for the values of a named function parameter. -pub fn named_param_value_completions<'a>( - ctx: &mut CompletionContext<'a>, - callee: ast::Expr<'a>, - name: &Interned, - ty: Option<&Ty>, -) { - let Some(cc) = ctx - .root - .find(callee.span()) - .and_then(|callee| resolve_call_target(ctx.ctx.shared(), &callee)) - else { - // static analysis - if let Some(ty) = ty { - type_completion(ctx, ty, None); - } - - return; - }; - // todo: regards call convention - let func = cc.callee(); - - let leaf_type = ctx.ctx.literal_type_of_node(ctx.leaf.clone()); - log::debug!( - "named_param_completion_by_type: {:?} -> {:?}", - ctx.leaf.kind(), - leaf_type - ); - - use typst::foundations::func::Repr; - let mut func = func; - while let Repr::With(f) = func.inner() { - // todo: complete with positional arguments - // with_args.push(ArgValue::Instance(f.1.clone())); - func = f.0.clone(); - } - - let signature = ctx.ctx.sig_of_func(func.clone()); - - let primary_sig = signature.primary(); - - let Some(param) = primary_sig.get_named(name) else { - return; - }; - if !param.attrs.named { - return; - } - - let doc = param.docs.as_ref().map(|d| plain_docs_sentence(d.as_str())); - - // static analysis - if let Some(ty) = ty { - type_completion(ctx, ty, doc.as_deref()); - } - - let mut completed = false; - if let Some(type_sig) = leaf_type { - log::debug!("named_param_completion by type: {:?}", param); - type_completion(ctx, &type_sig, doc.as_deref()); - completed = true; - } - - if !matches!(param.ty, Ty::Any) { - type_completion(ctx, ¶m.ty, doc.as_deref()); - completed = true; - } - - if !completed { - if let Some(expr) = ¶m.default { - ctx.completions.push(Completion { - kind: CompletionKind::Constant, - label: expr.clone(), - apply: None, - detail: doc.map(Into::into), - ..Completion::default() - }); - } - } - - sort_and_explicit_code_completion(ctx); - if ctx.before.ends_with(':') { - ctx.enrich(" ", ""); - } -} +// if ctx.before.ends_with(':') { +// ctx.enrich(" ", ""); +// } /// Complete call and set rule parameters. pub(crate) fn complete_type(ctx: &mut CompletionContext) -> Option<()> { @@ -1052,6 +1326,7 @@ pub(crate) fn complete_type(ctx: &mut CompletionContext) -> Option<()> { let check_target = get_check_target(ctx.leaf.clone()); log::debug!("complete_type: pos {:?} -> {check_target:#?}", ctx.leaf); + let mut args_node = None; match check_target { Some(CheckTarget::Element { container, .. }) => { @@ -1070,32 +1345,168 @@ pub(crate) fn complete_type(ctx: &mut CompletionContext) -> Option<()> { ctx.seen_field(named.name().into()); } } + args_node = Some(args.to_untyped().clone()); + } + Some(CheckTarget::Normal(e)) + if (matches!(e.kind(), SyntaxKind::ContentBlock) + && matches!(ctx.leaf.kind(), SyntaxKind::LeftBracket)) => + { + args_node = e.parent().map(|s| s.get().clone()); } - Some(CheckTarget::Normal(e)) if matches!(e.kind(), SyntaxKind::Label | SyntaxKind::Ref) => { + // todo: complete type field + Some(CheckTarget::Normal(e)) if matches!(e.kind(), SyntaxKind::FieldAccess) => { + return None; } - Some(CheckTarget::Paren { .. }) => {} - Some(CheckTarget::Normal(..)) => return None, - None => return None, + Some(CheckTarget::Paren { .. } | CheckTarget::Normal(..)) | None => {} } + log::debug!("ctx.leaf {:?}", ctx.leaf.clone()); + let ty = ctx .ctx .literal_type_of_node(ctx.leaf.clone()) - .filter(|ty| !matches!(ty, Ty::Any))?; + .filter(|ty| !matches!(ty, Ty::Any)); + + let scope = ctx.surrounding_syntax(); + + log::debug!("complete_type: {:?} -> ({scope:?}, {ty:#?})", ctx.leaf); + if matches!((scope, &ty), (SurroundingSyntax::Regular, None)) { + return None; + } // adjust the completion position if is_ident_like(&ctx.leaf) { ctx.from = ctx.leaf.offset(); } - log::debug!("complete_type: ty {:?} -> {ty:#?}", ctx.leaf); + if let Some(ty) = ty { + type_completion(ctx, &ty, None); + } - type_completion(ctx, &ty, None); if ctx.before.ends_with(',') || ctx.before.ends_with(':') { ctx.enrich(" ", ""); } - sort_and_explicit_code_completion(ctx); + let mut completions = std::mem::take(&mut ctx.completions); + let explict = ctx.explicit; + ctx.explicit = true; + let ty = Some(Ty::from_types(ctx.seen_types.iter().cloned())); + let from_ty = std::mem::replace(&mut ctx.from_ty, ty); + complete_code(ctx, true); + ctx.from_ty = from_ty; + ctx.explicit = explict; + + match scope { + SurroundingSyntax::Regular => {} + SurroundingSyntax::Selector => { + ctx.snippet_completion( + "text selector", + "\"${text}\"", + "Replace occurrences of specific text.", + ); + + ctx.snippet_completion( + "regex selector", + "regex(\"${regex}\")", + "Replace matches of a regular expression.", + ); + } + SurroundingSyntax::ShowTransform => { + ctx.snippet_completion( + "replacement", + "[${content}]", + "Replace the selected element with content.", + ); + + ctx.snippet_completion( + "replacement (string)", + "\"${text}\"", + "Replace the selected element with a string of text.", + ); + + ctx.snippet_completion( + "transformation", + "element => [${content}]", + "Transform the element with a function.", + ); + } + SurroundingSyntax::SetRule => {} + } + + // ctx.strict_scope_completions(false, |value| value.ty() == *ty); + // let length_ty = Type::of::(); + // ctx.strict_scope_completions(false, |value| value.ty() == length_ty); + // let color_ty = Type::of::(); + // ctx.strict_scope_completions(false, |value| value.ty() == color_ty); + // let ty = Type::of::(); + // ctx.strict_scope_completions(false, |value| value.ty() == ty); + + log::debug!( + "sort_and_explicit_code_completion: {completions:#?} {:#?}", + ctx.completions + ); + + completions.sort_by(|a, b| { + a.sort_text + .as_ref() + .cmp(&b.sort_text.as_ref()) + .then_with(|| a.label.cmp(&b.label)) + }); + ctx.completions.sort_by(|a, b| { + a.sort_text + .as_ref() + .cmp(&b.sort_text.as_ref()) + .then_with(|| a.label.cmp(&b.label)) + }); + + // todo: this is a bit messy, we can refactor for improving maintainability + // The messy code will finally gone, but to help us go over the mess stage, I + // drop some comment here. + // + // currently, there are only path completions in ctx.completions2 + // and type/named param/positional param completions in completions + // and all rest less relevant completions inctx.completions + for (i, compl) in ctx.completions2.iter_mut().enumerate() { + compl.sort_text = Some(format!("{i:03}")); + } + let sort_base = ctx.completions2.len(); + for (i, compl) in (completions.iter_mut().chain(ctx.completions.iter_mut())).enumerate() { + compl.sort_text = Some(eco_format!("{i:03}", i = i + sort_base)); + } + + log::debug!( + "sort_and_explicit_code_completion after: {completions:#?} {:#?}", + ctx.completions + ); + + ctx.completions.append(&mut completions); + + if let Some(c) = args_node { + log::debug!("content block compl: args {c:?}"); + let is_unclosed = matches!(c.kind(), SyntaxKind::Args) + && c.children().fold(0i32, |acc, node| match node.kind() { + SyntaxKind::LeftParen => acc + 1, + SyntaxKind::RightParen => acc - 1, + SyntaxKind::Error if node.text() == "(" => acc + 1, + SyntaxKind::Error if node.text() == ")" => acc - 1, + _ => acc, + }) > 0; + if is_unclosed { + ctx.enrich("", ")"); + } + } + + match scope { + SurroundingSyntax::Regular => {} + SurroundingSyntax::Selector => { + ctx.enrich("", ": ${}"); + } + SurroundingSyntax::ShowTransform => {} + SurroundingSyntax::SetRule => {} + } + + log::debug!("sort_and_explicit_code_completion: {:?}", ctx.completions); + Some(()) } @@ -1174,7 +1585,11 @@ pub fn complete_path( // diff with root unix_slash(path.vpath().as_rooted_path()) } else { - let base = base.vpath().as_rooted_path(); + let base = base + .vpath() + .as_rooted_path() + .parent() + .unwrap_or(Path::new("/")); let path = path.vpath().as_rooted_path(); let w = pathdiff::diff_paths(path, base)?; unix_slash(&w) @@ -1292,6 +1707,47 @@ pub fn symbol_label_detail(ch: char) -> EcoString { } } +static DEFAULT_POSTFIX_SNIPPET: LazyLock> = LazyLock::new(|| { + vec![ + PostfixSnippet { + scope: PostfixSnippetScope::Content, + mode: eco_vec![InterpretMode::Code, InterpretMode::Markup], + label: "aleft".into(), + label_detail: Some(".align left".into()), + snippet: "align(left, ${node})".into(), + description: "wrap as with align left".into(), + parsed_snippet: OnceLock::new(), + }, + PostfixSnippet { + scope: PostfixSnippetScope::Value, + mode: eco_vec![InterpretMode::Code, InterpretMode::Markup], + label: "if".into(), + label_detail: Some(".if".into()), + snippet: "if ${node} { ${} }".into(), + description: "wrap as if expression".into(), + parsed_snippet: OnceLock::new(), + }, + PostfixSnippet { + scope: PostfixSnippetScope::Value, + mode: eco_vec![InterpretMode::Code, InterpretMode::Markup], + label: "return".into(), + label_detail: Some(".return".into()), + snippet: "return ${node}".into(), + description: "wrap as return expression".into(), + parsed_snippet: OnceLock::new(), + }, + PostfixSnippet { + scope: PostfixSnippetScope::Value, + mode: eco_vec![InterpretMode::Code, InterpretMode::Markup], + label: "let".into(), + label_detail: Some(".let".into()), + snippet: "let ${_} = ${node}".into(), + description: "wrap as let expression".into(), + parsed_snippet: OnceLock::new(), + }, + ] +}); + #[cfg(test)] mod tests { diff --git a/crates/tinymist-query/src/upstream/mod.rs b/crates/tinymist-query/src/upstream/mod.rs index 3aae1b4c5..67fc02900 100644 --- a/crates/tinymist-query/src/upstream/mod.rs +++ b/crates/tinymist-query/src/upstream/mod.rs @@ -55,7 +55,7 @@ pub fn plain_docs_sentence(docs: &str) -> EcoString { let link_content = s.from(c + 1); s.eat(); - log::info!("Intra Link: {link_content}"); + log::debug!("Intra Link: {link_content}"); let link = resolve(link_content, "https://typst.app/docs/").ok(); let link = link.unwrap_or_else(|| { log::warn!("Failed to resolve link: {link_content}"); diff --git a/crates/tinymist-query/src/workspace_label.rs b/crates/tinymist-query/src/workspace_label.rs index a9498f24d..d7309e738 100644 --- a/crates/tinymist-query/src/workspace_label.rs +++ b/crates/tinymist-query/src/workspace_label.rs @@ -22,8 +22,6 @@ impl SemanticRequest for WorkspaceLabelRequest { let mut symbols = vec![]; for id in ctx.source_files().clone() { - let now = reflexo::time::Instant::now(); - log::info!("workspace/label: {:?}", id); let Ok(source) = ctx.source_by_id(id) else { continue; }; @@ -39,7 +37,6 @@ impl SemanticRequest for WorkspaceLabelRequest { if let Some(mut res) = res { symbols.append(&mut res) } - log::info!("workspace/label: {:?} took {:?}", id, now.elapsed()); } Some(symbols) diff --git a/crates/tinymist-world/Cargo.toml b/crates/tinymist-world/Cargo.toml index d8744c175..b43f337c9 100644 --- a/crates/tinymist-world/Cargo.toml +++ b/crates/tinymist-world/Cargo.toml @@ -23,28 +23,13 @@ log.workspace = true reflexo-typst.workspace = true reflexo-typst-shim = { workspace = true, features = ["nightly"] } typst.workspace = true +typst-kit.workspace = true tinymist-assets = { workspace = true } typst-assets = { workspace = true, features = ["fonts"] } dirs.workspace = true parking_lot.workspace = true -flate2 = "1" -tar = "0.4" - -[target.'cfg(not(any(target_arch = "riscv64", target_arch = "wasm32", all(target_os = "windows", target_arch = "aarch64"))))'.dependencies] -reqwest = { version = "^0.11", default-features = false, features = [ - "rustls-tls", - "blocking", - "multipart", -] } - -[target.'cfg(any(target_arch = "riscv64", all(target_os = "windows", target_arch = "aarch64")))'.dependencies] -reqwest = { version = "^0.11", default-features = false, features = [ - "native-tls", - "blocking", - "multipart", -] } [features] no-content-hint = ["reflexo-typst/no-content-hint"] diff --git a/crates/tinymist-world/src/https.rs b/crates/tinymist-world/src/https.rs deleted file mode 100644 index dd58cdb74..000000000 --- a/crates/tinymist-world/src/https.rs +++ /dev/null @@ -1,257 +0,0 @@ -//! Https registry for tinymist. - -use std::path::Path; -use std::sync::OnceLock; -use std::{path::PathBuf, sync::Arc}; - -use log::error; -use parking_lot::Mutex; -use reflexo_typst::package::{DummyNotifier, Notifier, PackageError, PackageRegistry, PackageSpec}; -use reflexo_typst::typst::{ - diag::{eco_format, EcoString}, - syntax::package::PackageVersion, -}; -use reqwest::{blocking::Response, Certificate}; - -/// The http registry without typst.ts to implement more for tinymist. -pub struct HttpsRegistry { - notifier: Arc>, - - packages: OnceLock)>>, - - cert_path: Option, - - data_dir_cache: OnceLock>>, - cache_dir_cache: OnceLock>>, - // package_dir_cache: RwLock, PackageError>>>, -} - -impl Default for HttpsRegistry { - fn default() -> Self { - Self { - notifier: Arc::new(Mutex::::default()), - - // todo: reset cache - packages: OnceLock::new(), - - // Default to None - cert_path: None, - - data_dir_cache: OnceLock::new(), - cache_dir_cache: OnceLock::new(), - // package_dir_cache: RwLock::new(HashMap::new()), - } - } -} - -impl HttpsRegistry { - /// Create a new registry. - pub fn new(cert_path: Option) -> Self { - Self { - cert_path, - ..Default::default() - } - } - - /// Get local path option - pub fn local_path(&self) -> Option> { - if let Some(data_dir) = self.data_dir() { - if data_dir.exists() { - return Some(data_dir.join("typst/packages").into()); - } - } - - None - } - - fn data_dir(&self) -> Option<&Arc> { - self.data_dir_cache - .get_or_init(|| dirs::data_dir().map(From::from)) - .as_ref() - } - - fn cache_dir(&self) -> Option<&Arc> { - self.cache_dir_cache - .get_or_init(|| dirs::cache_dir().map(From::from)) - .as_ref() - } - - /// Get data & cache dir - pub fn paths(&self) -> Vec> { - let mut res = vec![]; - if let Some(data_dir) = self.data_dir() { - let dir: Box = data_dir.join("typst/packages").into(); - if dir.exists() { - res.push(dir); - } - } - - if let Some(cache_dir) = self.cache_dir() { - let dir: Box = cache_dir.join("typst/packages").into(); - if dir.exists() { - res.push(dir); - } - } - - res - } - - /// Make a package available in the on-disk cache. - pub fn prepare_package(&self, spec: &PackageSpec) -> Result, PackageError> { - // let cache = self.package_dir_cache.read(); - // if let Some(dir) = cache.get(spec) { - // return dir.clone(); - // } - - // drop(cache); - // let mut cache = self.package_dir_cache.write(); - // if let Some(dir) = cache.get(spec) { - // return dir.clone(); - // } - - // let dir = self.prepare_package_(spec); - // cache.insert(spec.clone(), dir.clone()); - // dir - self.prepare_package_(spec) - } - - /// Make a package available in the on-disk cache. - pub fn prepare_package_(&self, spec: &PackageSpec) -> Result, PackageError> { - let subdir = format!( - "typst/packages/{}/{}/{}", - spec.namespace, spec.name, spec.version - ); - - if let Some(data_dir) = self.data_dir() { - let dir = data_dir.join(&subdir); - if dir.exists() { - return Ok(dir.into()); - } - } - - if let Some(cache_dir) = self.cache_dir() { - let dir = cache_dir.join(&subdir); - - // Download from network if it doesn't exist yet. - if spec.namespace == "preview" && !dir.exists() { - self.download_package(spec, &dir)?; - } - - if dir.exists() { - return Ok(dir.into()); - } - } - - Err(PackageError::NotFound(spec.clone())) - } - - /// Download a package over the network. - fn download_package(&self, spec: &PackageSpec, package_dir: &Path) -> Result<(), PackageError> { - let url = format!( - "https://packages.typst.org/preview/{}-{}.tar.gz", - spec.name, spec.version - ); - - self.notifier.lock().downloading(spec); - threaded_http(&url, self.cert_path.as_deref(), |resp| { - let reader = match resp.and_then(|r| r.error_for_status()) { - Ok(response) => response, - Err(err) if matches!(err.status().map(|s| s.as_u16()), Some(404)) => { - return Err(PackageError::NotFound(spec.clone())) - } - Err(err) => return Err(PackageError::NetworkFailed(Some(eco_format!("{err}")))), - }; - - let decompressed = flate2::read::GzDecoder::new(reader); - tar::Archive::new(decompressed) - .unpack(package_dir) - .map_err(|err| { - std::fs::remove_dir_all(package_dir).ok(); - PackageError::MalformedArchive(Some(eco_format!("{err}"))) - }) - }) - .ok_or_else(|| PackageError::Other(Some(eco_format!("cannot spawn http thread"))))? - } -} - -impl PackageRegistry for HttpsRegistry { - fn resolve(&self, spec: &PackageSpec) -> Result, PackageError> { - self.prepare_package(spec) - } - - fn packages(&self) -> &[(PackageSpec, Option)] { - self.packages.get_or_init(|| { - let url = "https://packages.typst.org/preview/index.json"; - - threaded_http(url, self.cert_path.as_deref(), |resp| { - let reader = match resp.and_then(|r| r.error_for_status()) { - Ok(response) => response, - Err(err) => { - // todo: silent error - error!("Failed to fetch package index: {err} from {url}"); - return vec![]; - } - }; - - #[derive(serde::Deserialize)] - struct RemotePackageIndex { - name: EcoString, - version: PackageVersion, - description: Option, - } - - let index: Vec = match serde_json::from_reader(reader) { - Ok(index) => index, - Err(err) => { - error!("Failed to parse package index: {err} from {url}"); - return vec![]; - } - }; - - index - .into_iter() - .map(|e| { - ( - PackageSpec { - namespace: "preview".into(), - name: e.name, - version: e.version, - }, - e.description, - ) - }) - .collect::>() - }) - .unwrap_or_default() - }) - } -} - -fn threaded_http( - url: &str, - cert_path: Option<&Path>, - f: impl FnOnce(Result) -> T + Send + Sync, -) -> Option { - std::thread::scope(|s| { - s.spawn(move || { - let client_builder = reqwest::blocking::Client::builder(); - - let client = if let Some(cert_path) = cert_path { - let cert = std::fs::read(cert_path) - .ok() - .and_then(|buf| Certificate::from_pem(&buf).ok()); - if let Some(cert) = cert { - client_builder.add_root_certificate(cert).build().unwrap() - } else { - client_builder.build().unwrap() - } - } else { - client_builder.build().unwrap() - }; - - f(client.get(url).send()) - }) - .join() - .ok() - }) -} diff --git a/crates/tinymist-world/src/lib.rs b/crates/tinymist-world/src/lib.rs index 8342b4121..65b37f4f0 100644 --- a/crates/tinymist-world/src/lib.rs +++ b/crates/tinymist-world/src/lib.rs @@ -1,5 +1,6 @@ //! World implementation of typst for tinymist. +pub use reflexo_typst; pub use reflexo_typst::config::CompileFontOpts; pub use reflexo_typst::error::prelude; pub use reflexo_typst::font::FontResolverImpl; @@ -20,8 +21,8 @@ use reflexo_typst::vfs::{system::SystemAccessModel, Vfs}; use reflexo_typst::{CompilerFeat, CompilerUniverse, CompilerWorld, TypstDict}; use serde::{Deserialize, Serialize}; -pub mod https; -use https::HttpsRegistry; +pub mod package; +use package::HttpsRegistry; const ENV_PATH_SEP: char = if cfg!(windows) { ';' } else { ':' }; @@ -64,6 +65,22 @@ pub struct CompileFontArgs { pub ignore_system_fonts: bool, } +/// Arguments related to where packages are stored in the system. +#[derive(Debug, Clone, Parser, Default, PartialEq, Eq)] +pub struct CompilePackageArgs { + /// Custom path to local packages, defaults to system-dependent location + #[clap(long = "package-path", env = "TYPST_PACKAGE_PATH", value_name = "DIR")] + pub package_path: Option, + + /// Custom path to package cache, defaults to system-dependent location + #[clap( + long = "package-cache-path", + env = "TYPST_PACKAGE_CACHE_PATH", + value_name = "DIR" + )] + pub package_cache_path: Option, +} + /// Common arguments of compile, watch, and query. #[derive(Debug, Clone, Parser, Default)] pub struct CompileOnceArgs { @@ -88,6 +105,10 @@ pub struct CompileOnceArgs { #[clap(flatten)] pub font: CompileFontArgs, + /// Package related arguments. + #[clap(flatten)] + pub package: CompilePackageArgs, + /// The document's creation date formatted as a UNIX timestamp. /// /// For more information, see . @@ -103,26 +124,26 @@ pub struct CompileOnceArgs { /// Path to CA certificate file for network access, especially for /// downloading typst packages. #[clap(long = "cert", env = "TYPST_CERT", value_name = "CERT_PATH")] - pub certification: Option, + pub cert: Option, } impl CompileOnceArgs { /// Get a universe instance from the given arguments. pub fn resolve(&self) -> anyhow::Result { let entry = self.entry()?.try_into()?; - let fonts = LspUniverseBuilder::resolve_fonts(self.font.clone())?; let inputs = self .inputs .iter() .map(|(k, v)| (Str::from(k.as_str()), Value::Str(Str::from(v.as_str())))) .collect(); - let cert_path = self.certification.clone(); + let fonts = LspUniverseBuilder::resolve_fonts(self.font.clone())?; + let package = LspUniverseBuilder::resolve_package(self.cert.clone(), Some(&self.package)); LspUniverseBuilder::build( entry, - Arc::new(fonts), Arc::new(LazyHash::new(inputs)), - cert_path, + Arc::new(fonts), + package, ) .context("failed to create universe") } @@ -184,15 +205,15 @@ impl LspUniverseBuilder { /// See [`LspCompilerFeat`] for instantiation details. pub fn build( entry: EntryState, - font_resolver: Arc, inputs: ImmutDict, - cert_path: Option, + font_resolver: Arc, + package_registry: HttpsRegistry, ) -> ZResult { Ok(LspUniverse::new_raw( entry, Some(inputs), Vfs::new(SystemAccessModel {}), - HttpsRegistry::new(cert_path), + package_registry, font_resolver, )) } @@ -208,6 +229,14 @@ impl LspUniverseBuilder { })?; Ok(searcher.into()) } + + /// Resolve package registry from given options. + pub fn resolve_package( + cert_path: Option, + args: Option<&CompilePackageArgs>, + ) -> HttpsRegistry { + HttpsRegistry::new(cert_path, args) + } } /// Parses key/value pairs split by the first equal sign. diff --git a/crates/tinymist-world/src/package.rs b/crates/tinymist-world/src/package.rs new file mode 100644 index 000000000..c489ab14b --- /dev/null +++ b/crates/tinymist-world/src/package.rs @@ -0,0 +1,164 @@ +//! Https registry for tinymist. + +use std::sync::OnceLock; +use std::{path::PathBuf, sync::Arc}; + +use parking_lot::Mutex; +use reflexo_typst::package::{DummyNotifier, Notifier, PackageError, PackageRegistry, PackageSpec}; +use reflexo_typst::typst::diag::EcoString; +use reflexo_typst::ImmutPath; +use typst_kit::download::{DownloadState, Downloader}; +use typst_kit::package::PackageStorage; + +use crate::CompilePackageArgs; + +/// The https package registry for tinymist. +pub struct HttpsRegistry { + /// The path at which local packages (`@local` packages) are stored. + local_dir: OnceLock>, + /// The path at which non-local packages (`@preview` packages) should be + /// stored when downloaded. + cache_dir: OnceLock>, + /// The cached index of the preview namespace. + index: OnceLock)>>, + /// lazily initialized package storage. + storage: OnceLock, + cert_path: Option, + notifier: Arc>, + // package_dir_cache: RwLock>>, +} + +impl Default for HttpsRegistry { + fn default() -> Self { + Self { + notifier: Arc::new(Mutex::::default()), + // todo: reset cache + index: OnceLock::new(), + // Default to None + cert_path: None, + + local_dir: OnceLock::new(), + cache_dir: OnceLock::new(), + storage: OnceLock::new(), + // package_dir_cache: RwLock::new(HashMap::new()), + } + } +} + +impl std::ops::Deref for HttpsRegistry { + type Target = PackageStorage; + + fn deref(&self) -> &Self::Target { + self.storage() + } +} + +impl HttpsRegistry { + /// Create a new registry. + pub fn new(cert_path: Option, package_args: Option<&CompilePackageArgs>) -> Self { + let local_dir = OnceLock::new(); + if let Some(dir) = package_args.and_then(|args| args.package_path.as_deref()) { + let _ = local_dir.set(Some(dir.into())); + } + + let cache_dir = OnceLock::new(); + if let Some(dir) = package_args.and_then(|args| args.package_cache_path.as_deref()) { + let _ = cache_dir.set(Some(dir.into())); + } + + Self { + cert_path, + local_dir, + cache_dir, + ..Default::default() + } + } + + /// Get local path option + pub fn local_path(&self) -> Option { + self.data_dir().cloned() + } + + fn data_dir(&self) -> Option<&ImmutPath> { + self.local_dir + .get_or_init(|| Some(dirs::data_dir()?.join("typst/packages").into())) + .as_ref() + } + + fn cache_dir(&self) -> Option<&ImmutPath> { + self.cache_dir + .get_or_init(|| Some(dirs::cache_dir()?.join("typst/packages").into())) + .as_ref() + } + + /// Get data & cache dir + pub fn paths(&self) -> Vec { + let mut res = Vec::with_capacity(2); + if let Some(data_dir) = self.data_dir() { + res.push(data_dir.clone()); + } + + if let Some(cache_dir) = self.cache_dir() { + res.push(cache_dir.clone()) + } + + res + } + + /// Get `typst-kit` implementing package storage + pub fn storage(&self) -> &PackageStorage { + self.storage.get_or_init(|| { + let user_agent = concat!("typst/", env!("CARGO_PKG_VERSION")); + let downloader = match self.cert_path.clone() { + Some(cert) => Downloader::with_path(user_agent, cert), + None => Downloader::new(user_agent), + }; + PackageStorage::new( + self.cache_dir().map(|s| s.as_ref().into()), + self.data_dir().map(|s| s.as_ref().into()), + downloader, + ) + }) + } + + /// Make a package available in the on-disk cache. + pub fn prepare_package(&self, spec: &PackageSpec) -> Result { + self.storage() + .prepare_package(spec, &mut NotifierProgress(self.notifier.clone(), spec)) + } +} + +impl PackageRegistry for HttpsRegistry { + fn resolve(&self, spec: &PackageSpec) -> Result { + self.prepare_package(spec).map(From::from) + } + + fn packages(&self) -> &[(PackageSpec, Option)] { + self.index.get_or_init(|| { + let packages = self.storage().download_index().unwrap_or_default().iter(); + + packages + .map(|e| { + ( + PackageSpec { + namespace: "preview".into(), + name: e.name.clone(), + version: e.version, + }, + e.description.clone(), + ) + }) + .collect() + }) + } +} + +struct NotifierProgress<'a>(Arc>, &'a PackageSpec); + +impl typst_kit::download::Progress for NotifierProgress<'_> { + fn print_start(&mut self) { + self.0.lock().downloading(self.1); + } + fn print_progress(&mut self, _state: &DownloadState) {} + fn print_finish(&mut self, _state: &DownloadState) {} +} diff --git a/crates/tinymist/Cargo.toml b/crates/tinymist/Cargo.toml index c868f8280..2ec0dc983 100644 --- a/crates/tinymist/Cargo.toml +++ b/crates/tinymist/Cargo.toml @@ -35,6 +35,7 @@ serde_json.workspace = true serde_yaml.workspace = true parking_lot.workspace = true paste.workspace = true +strum.workspace = true clap.workspace = true clap_builder.workspace = true diff --git a/crates/tinymist/src/actor/mod.rs b/crates/tinymist/src/actor/mod.rs index 64cd0201c..2a47d0a6f 100644 --- a/crates/tinymist/src/actor/mod.rs +++ b/crates/tinymist/src/actor/mod.rs @@ -12,7 +12,7 @@ use reflexo::ImmutPath; use reflexo_typst::vfs::notify::{FileChangeSet, MemoryEvent}; use reflexo_typst::world::EntryState; use tinymist_query::analysis::{Analysis, PeriscopeProvider}; -use tinymist_query::{ExportKind, LocalContext, SemanticTokenContext, VersionedDocument}; +use tinymist_query::{ExportKind, LocalContext, VersionedDocument}; use tinymist_render::PeriscopeRenderer; use tokio::sync::mpsc; use typst::layout::Position; @@ -107,6 +107,10 @@ impl LanguageState { stats: Default::default(), analysis: Arc::new(Analysis { position_encoding: const_config.position_encoding, + allow_overlapping_token: const_config.tokens_overlapping_token_support, + allow_multiline_token: const_config.tokens_multiline_token_support, + remove_html: !self.config.support_html_in_markdown, + completion_feat: self.config.completion.clone(), color_theme: match self.compile_config().color_theme.as_deref() { Some("dark") => tinymist_query::ColorTheme::Dark, _ => tinymist_query::ColorTheme::Light, @@ -115,15 +119,11 @@ impl LanguageState { let r = TypstPeriscopeProvider(PeriscopeRenderer::new(args)); Arc::new(r) as Arc }), - tokens_ctx: Arc::new(SemanticTokenContext::new( - const_config.position_encoding, - const_config.tokens_overlapping_token_support, - const_config.tokens_multiline_token_support, - )), + tokens_caches: Arc::default(), workers: Default::default(), caches: Default::default(), - cache_grid: Default::default(), - stats: Default::default(), + analysis_rev_cache: Arc::default(), + stats: Arc::default(), }), notified_revision: parking_lot::Mutex::new(0), @@ -134,12 +134,16 @@ impl LanguageState { let compile_handle = handle.clone(); let cache = self.cache.clone(); let cert_path = self.compile_config().determine_certification_path(); + let package = self.compile_config().determine_package_opts(); self.client.handle.spawn_blocking(move || { // Create the world let font_resolver = font_resolver.wait().clone(); - let verse = LspUniverseBuilder::build(entry_.clone(), font_resolver, inputs, cert_path) - .expect("incorrect options"); + let package_registry = + LspUniverseBuilder::resolve_package(cert_path.clone(), Some(&package)); + let verse = + LspUniverseBuilder::build(entry_.clone(), inputs, font_resolver, package_registry) + .expect("incorrect options"); // Create the actor let server = CompileServerActor::new_with( diff --git a/crates/tinymist/src/actor/typ_client.rs b/crates/tinymist/src/actor/typ_client.rs index d95bad4f6..e72ba5e81 100644 --- a/crates/tinymist/src/actor/typ_client.rs +++ b/crates/tinymist/src/actor/typ_client.rs @@ -22,9 +22,9 @@ //! //! The [`CompileHandler`] will push information to other actors. -use std::{collections::HashMap, ops::Deref, path::PathBuf, sync::Arc}; +use std::{collections::HashMap, ops::Deref, sync::Arc}; -use anyhow::{anyhow, bail}; +use anyhow::bail; use log::{error, info, trace}; use reflexo_typst::{ error::prelude::*, typst::prelude::*, vfs::notify::MemoryEvent, world::EntryState, @@ -32,12 +32,12 @@ use reflexo_typst::{ }; use sync_lsp::{just_future, QueryFuture}; use tinymist_query::{ - analysis::{Analysis, LocalContextGuard}, - CompilerQueryRequest, CompilerQueryResponse, DiagnosticsMap, ExportKind, SemanticRequest, + analysis::{Analysis, AnalysisRevLock, LocalContextGuard}, + CompilerQueryRequest, CompilerQueryResponse, DiagnosticsMap, OnExportRequest, SemanticRequest, ServerInfoResponse, StatefulRequest, VersionedDocument, }; use tokio::sync::{mpsc, oneshot}; -use typst::{diag::SourceDiagnostic, World as TypstWorld}; +use typst::{diag::SourceDiagnostic, World}; use super::{ editor::{DocVersion, EditorRequest, TinymistCompileStatusEnum}, @@ -71,13 +71,26 @@ pub struct CompileHandler { impl CompileHandler { /// Snapshot the compiler thread for tasks - pub fn snapshot(&self) -> ZResult { + pub fn snapshot(&self) -> ZResult { let (tx, rx) = oneshot::channel(); self.intr_tx .send(Interrupt::SnapshotRead(tx)) .map_err(map_string_err("failed to send snapshot request"))?; - Ok(QuerySnap { rx }) + Ok(WorldSnapFut { rx }) + } + + /// Snapshot the compiler thread for language queries + pub fn query_snapshot(&self, q: Option<&CompilerQueryRequest>) -> ZResult { + let fut = self.snapshot()?; + let analysis = self.analysis.clone(); + let rev_lock = analysis.lock_revision(q); + + Ok(QuerySnapFut { + fut, + analysis, + rev_lock, + }) } /// Get latest artifact the compiler thread for tasks @@ -130,67 +143,18 @@ impl CompileHandler { let revision = world.revision().get(); trace!("notify diagnostics({revision}): {errors:#?} {warnings:#?}"); - let diagnostics = self.run_analysis(world, |ctx| { - tinymist_query::convert_diagnostics(ctx, errors.iter().chain(warnings.iter())) - }); - - match diagnostics { - Ok(diagnostics) => { - let entry = world.entry_state(); - // todo: better way to remove diagnostics - // todo: check all errors in this file - let detached = entry.is_inactive(); - let valid = !detached; - self.push_diagnostics(revision, valid.then_some(diagnostics)); - } - Err(err) => { - error!("TypstActor: failed to convert diagnostics: {:#}", err); - self.push_diagnostics(revision, None); - } - } - } - - pub fn run_stateful( - &self, - snap: CompileSnapshot, - query: T, - wrapper: fn(Option) -> CompilerQueryResponse, - ) -> anyhow::Result { - let w = &snap.world; - let doc = snap.success_doc.map(|doc| VersionedDocument { - version: w.revision().get(), - document: doc, - }); - self.run_analysis(w, |ctx| query.request(ctx, doc)) - .map(wrapper) - } - - pub fn run_semantic( - &self, - snap: CompileSnapshot, - query: T, - wrapper: fn(Option) -> CompilerQueryResponse, - ) -> anyhow::Result { - self.run_analysis(&snap.world, |ctx| query.request(ctx)) - .map(wrapper) - } - - pub fn run_analysis( - &self, - w: &LspWorld, - f: impl FnOnce(&mut LocalContextGuard) -> T, - ) -> anyhow::Result { - let Some(main) = w.main_id() else { - error!("TypstActor: main file is not set"); - bail!("main file is not set"); - }; - w.source(main).map_err(|err| { - info!("TypstActor: failed to prepare main file: {err:?}"); - anyhow!("failed to get source: {err}") - })?; + let diagnostics = tinymist_query::convert_diagnostics( + world, + errors.iter().chain(warnings.iter()), + self.analysis.position_encoding, + ); - let mut analysis = self.analysis.snapshot(w.clone()); - Ok(f(&mut analysis)) + let entry = world.entry_state(); + // todo: better way to remove diagnostics + // todo: check all errors in this file + let detached = entry.is_inactive(); + let valid = !detached; + self.push_diagnostics(revision, valid.then_some(diagnostics)); } // todo: multiple preview support @@ -319,17 +283,22 @@ impl CompileClientActor { } /// Snapshot the compiler thread for tasks - pub fn snapshot(&self) -> ZResult { + pub fn snapshot(&self) -> ZResult { self.handle.clone().snapshot() } - /// Snapshot the compiler thread for tasks - pub fn snapshot_with_stat(&self, q: &CompilerQueryRequest) -> ZResult { + /// Snapshot the compiler thread for language queries + pub fn query_snapshot(&self) -> ZResult { + self.handle.clone().query_snapshot(None) + } + + /// Snapshot the compiler thread for language queries + pub fn query_snapshot_with_stat(&self, q: &CompilerQueryRequest) -> ZResult { let name: &'static str = q.into(); let path = q.associated_path(); let stat = self.handle.stats.query_stat(path, name); - let snap = self.handle.clone().snapshot()?; - Ok(QuerySnapWithStat { snap, stat }) + let fut = self.handle.clone().query_snapshot(Some(q))?; + Ok(QuerySnapWithStat { fut, stat }) } pub fn add_memory_changes(&self, event: MemoryEvent) { @@ -348,7 +317,8 @@ impl CompileClientActor { self.handle.export.change_config(config); } - pub fn on_export(&self, kind: ExportKind, path: PathBuf) -> QueryFuture { + pub fn on_export(&self, req: OnExportRequest) -> QueryFuture { + let OnExportRequest { path, kind, open } = req; let snap = self.snapshot()?; let entry = self.config.determine_entry(Some(path.as_path().into())); @@ -356,6 +326,22 @@ impl CompileClientActor { just_future(async move { let res = export.await?; + // See https://github.com/Myriad-Dreamin/tinymist/issues/837 + // Also see https://github.com/Byron/open-rs/issues/105 + #[cfg(not(target_os = "windows"))] + let do_open = ::open::that_detached; + #[cfg(target_os = "windows")] + fn do_open(path: impl AsRef) -> std::io::Result<()> { + ::open::with_detached(path, "explorer") + } + + if let Some(Some(path)) = open.then_some(res.as_ref()) { + log::info!("open with system default apps: {path:?}"); + if let Err(e) = do_open(path) { + log::error!("failed to open with system default apps: {e}"); + }; + } + log::info!("CompileActor: on export end: {path:?} as {res:?}"); Ok(tinymist_query::CompilerQueryResponse::OnExport(res)) }) @@ -434,16 +420,16 @@ impl CompileClientActor { } pub struct QuerySnapWithStat { - pub snap: QuerySnap, + pub fut: QuerySnapFut, pub(crate) stat: QueryStatGuard, } -pub struct QuerySnap { +pub struct WorldSnapFut { rx: oneshot::Receiver>, } -impl QuerySnap { - /// Snapshot the compiler thread for tasks +impl WorldSnapFut { + /// wait for the snapshot to be ready pub async fn receive(self) -> ZResult> { self.rx .await @@ -451,6 +437,81 @@ impl QuerySnap { } } +pub struct QuerySnapFut { + fut: WorldSnapFut, + analysis: Arc, + rev_lock: AnalysisRevLock, +} + +impl QuerySnapFut { + /// wait for the snapshot to be ready + pub async fn receive(self) -> ZResult { + let snap = self.fut.receive().await?; + Ok(QuerySnap { + snap, + analysis: self.analysis, + rev_lock: self.rev_lock, + }) + } +} + +pub struct QuerySnap { + pub snap: CompileSnapshot, + analysis: Arc, + rev_lock: AnalysisRevLock, +} + +impl std::ops::Deref for QuerySnap { + type Target = CompileSnapshot; + + fn deref(&self) -> &Self::Target { + &self.snap + } +} + +impl QuerySnap { + pub fn task(mut self, inputs: TaskInputs) -> Self { + self.snap = self.snap.task(inputs); + self + } + + pub fn run_stateful( + self, + query: T, + wrapper: fn(Option) -> CompilerQueryResponse, + ) -> anyhow::Result { + let doc = self.snap.success_doc.as_ref().map(|doc| VersionedDocument { + version: self.world.revision().get(), + document: doc.clone(), + }); + self.run_analysis(|ctx| query.request(ctx, doc)) + .map(wrapper) + } + + pub fn run_semantic( + self, + query: T, + wrapper: fn(Option) -> CompilerQueryResponse, + ) -> anyhow::Result { + self.run_analysis(|ctx| query.request(ctx)).map(wrapper) + } + + pub fn run_analysis(self, f: impl FnOnce(&mut LocalContextGuard) -> T) -> anyhow::Result { + let w = self.world.as_ref(); + let Some(main) = w.main_id() else { + error!("TypstActor: main file is not set"); + bail!("main file is not set"); + }; + w.source(main).map_err(|err| { + info!("TypstActor: failed to prepare main file: {err:?}"); + anyhow::anyhow!("failed to get source: {err}") + })?; + + let mut analysis = self.analysis.snapshot_(w.clone(), self.rev_lock); + Ok(f(&mut analysis)) + } +} + pub struct ArtifactSnap { rx: oneshot::Receiver>, } diff --git a/crates/tinymist/src/cmd.rs b/crates/tinymist/src/cmd.rs index 2e7901d4d..89123cd3d 100644 --- a/crates/tinymist/src/cmd.rs +++ b/crates/tinymist/src/cmd.rs @@ -20,14 +20,19 @@ use super::server::*; use super::*; use crate::tool::package::InitTask; +/// See [`ExportKind`]. #[derive(Debug, Clone, Default, Deserialize)] struct ExportOpts { creation_timestamp: Option, fill: Option, ppi: Option, + #[serde(default)] page: PageSelection, + /// Whether to open the exported file(s) after the export is done. + open: Option, } +/// See [`ExportKind`]. #[derive(Debug, Clone, Default, Deserialize)] #[serde(rename_all = "camelCase")] struct QueryOpts { @@ -38,6 +43,8 @@ struct QueryOpts { selector: String, field: Option, one: Option, + /// Whether to open the exported file(s) after the export is done. + open: Option, } #[derive(Debug, Clone, Default, Deserialize)] @@ -61,22 +68,49 @@ impl LanguageState { self.config.compile.determine_creation_timestamp() }; - self.export(req_id, ExportKind::Pdf { creation_timestamp }, args) + self.export( + req_id, + ExportKind::Pdf { creation_timestamp }, + opts.open.unwrap_or_default(), + args, + ) } /// Export the current document as HTML file(s). - pub fn export_html(&mut self, req_id: RequestId, args: Vec) -> ScheduledResult { - self.export(req_id, ExportKind::Html {}, args) + pub fn export_html(&mut self, req_id: RequestId, mut args: Vec) -> ScheduledResult { + let opts = get_arg_or_default!(args[1] as ExportOpts); + self.export( + req_id, + ExportKind::Html {}, + opts.open.unwrap_or_default(), + args, + ) } /// Export the current document as Markdown file(s). - pub fn export_markdown(&mut self, req_id: RequestId, args: Vec) -> ScheduledResult { - self.export(req_id, ExportKind::Markdown {}, args) + pub fn export_markdown( + &mut self, + req_id: RequestId, + mut args: Vec, + ) -> ScheduledResult { + let opts = get_arg_or_default!(args[1] as ExportOpts); + self.export( + req_id, + ExportKind::Markdown {}, + opts.open.unwrap_or_default(), + args, + ) } /// Export the current document as Text file(s). - pub fn export_text(&mut self, req_id: RequestId, args: Vec) -> ScheduledResult { - self.export(req_id, ExportKind::Text {}, args) + pub fn export_text(&mut self, req_id: RequestId, mut args: Vec) -> ScheduledResult { + let opts = get_arg_or_default!(args[1] as ExportOpts); + self.export( + req_id, + ExportKind::Text {}, + opts.open.unwrap_or_default(), + args, + ) } /// Query the current document and export the result as JSON file(s). @@ -93,6 +127,7 @@ impl LanguageState { pretty: opts.pretty.unwrap_or(true), one: opts.one.unwrap_or(false), }, + opts.open.unwrap_or_default(), args, ) } @@ -100,7 +135,12 @@ impl LanguageState { /// Export the current document as Svg file(s). pub fn export_svg(&mut self, req_id: RequestId, mut args: Vec) -> ScheduledResult { let opts = get_arg_or_default!(args[1] as ExportOpts); - self.export(req_id, ExportKind::Svg { page: opts.page }, args) + self.export( + req_id, + ExportKind::Svg { page: opts.page }, + opts.open.unwrap_or_default(), + args, + ) } /// Export the current document as Png file(s). @@ -113,6 +153,7 @@ impl LanguageState { ppi: opts.ppi, page: opts.page, }, + opts.open.unwrap_or_default(), args, ) } @@ -123,11 +164,12 @@ impl LanguageState { &mut self, req_id: RequestId, kind: ExportKind, + open: bool, mut args: Vec, ) -> ScheduledResult { let path = get_arg!(args[0] as PathBuf); - run_query!(req_id, self.OnExport(path, kind)) + run_query!(req_id, self.OnExport(path, open, kind)) } /// Export a range of the current document as Ansi highlighted text. @@ -292,7 +334,7 @@ impl LanguageState { /// Initialize a new template. pub fn init_template(&mut self, mut args: Vec) -> AnySchedulableResponse { - use crate::tool::package::{self, determine_latest_version, TemplateSource}; + use crate::tool::package::{self, TemplateSource}; #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] @@ -317,7 +359,7 @@ impl LanguageState { // Try to parse without version, but prefer the error message of the // normal package spec parsing if it fails. let spec: VersionlessPackageSpec = from_source.parse().map_err(|_| err)?; - let version = determine_latest_version(&snap.world, &spec)?; + let version = snap.world.registry.determine_latest_version(&spec)?; StrResult::Ok(spec.at(version)) }) .map_err(map_string_err("failed to parse package spec")) @@ -344,7 +386,7 @@ impl LanguageState { /// Get the entry of a template. pub fn get_template_entry(&mut self, mut args: Vec) -> AnySchedulableResponse { - use crate::tool::package::{self, determine_latest_version, TemplateSource}; + use crate::tool::package::{self, TemplateSource}; let from_source = get_arg!(args[0] as String); @@ -362,7 +404,7 @@ impl LanguageState { // Try to parse without version, but prefer the error message of the // normal package spec parsing if it fails. let spec: VersionlessPackageSpec = from_source.parse().map_err(|_| err)?; - let version = determine_latest_version(&snap.world, &spec)?; + let version = snap.world.registry.determine_latest_version(&spec)?; StrResult::Ok(spec.at(version)) }) .map_err(map_string_err("failed to parse package spec")) @@ -505,6 +547,7 @@ impl LanguageState { just_future(async move { let snap = snap.receive().await.map_err(z_internal_error)?; let paths = snap.world.registry.paths(); + let paths = paths.iter().map(|p| p.as_ref()).collect::>(); serde_json::to_value(paths).map_err(|e| internal_error(e.to_string())) }) } @@ -517,12 +560,8 @@ impl LanguageState { let snap = self.primary().snapshot().map_err(z_internal_error)?; just_future(async move { let snap = snap.receive().await.map_err(z_internal_error)?; - let paths = snap - .world - .registry - .local_path() - .into_iter() - .collect::>(); + let paths = snap.world.registry.local_path(); + let paths = paths.as_deref().into_iter().collect::>(); serde_json::to_value(paths).map_err(|e| internal_error(e.to_string())) }) } @@ -552,27 +591,20 @@ impl LanguageState { &mut self, mut arguments: Vec, ) -> AnySchedulableResponse { - let handle = self.primary().handle.clone(); + let fut = self.primary().query_snapshot().map_err(internal_error)?; let info = get_arg!(arguments[1] as PackageInfo); - // todo: do this in a common place - let rev_lock = handle.analysis.lock_revision(); - - let snap = handle.snapshot().map_err(z_internal_error)?; just_future(async move { - let snap = snap.receive().await.map_err(z_internal_error)?; - let w = snap.world.as_ref(); + let snap = fut.receive().await.map_err(z_internal_error)?; - let symbols = handle - .run_analysis(w, |a| { + let symbols = snap + .run_analysis(|a| { tinymist_query::docs::package_module_docs(a, &info) .map_err(map_string_err("failed to list symbols")) }) .map_err(internal_error)? .map_err(internal_error)?; - drop(rev_lock); - serde_json::to_value(symbols).map_err(internal_error) }) } @@ -619,16 +651,10 @@ impl LanguageState { info: PackageInfo, f: impl FnOnce(&mut LocalContextGuard) -> LspResult + Send + Sync, ) -> LspResult>> { - let handle: std::sync::Arc = - self.primary().handle.clone(); - - // todo: do this in a common place - let rev_lock = handle.analysis.lock_revision(); - - let snap = handle.snapshot().map_err(z_internal_error)?; + let fut = self.primary().query_snapshot().map_err(internal_error)?; Ok(async move { - let snap = snap.receive().await.map_err(z_internal_error)?; + let snap = fut.receive().await.map_err(z_internal_error)?; let w = snap.world.as_ref(); let entry: StrResult = Ok(()).and_then(|_| { @@ -645,14 +671,12 @@ impl LanguageState { }); let entry = entry.map_err(|e| internal_error(e.to_string()))?; - let w = snap.world.task(TaskInputs { + let snap = snap.task(TaskInputs { entry: Some(entry), inputs: None, }); - let res = handle.run_analysis(&w, f).map_err(internal_error)?; - drop(rev_lock); - res + snap.run_analysis(f).map_err(internal_error)? }) } } diff --git a/crates/tinymist/src/init.rs b/crates/tinymist/src/init.rs index c82bf45d6..3e30f5036 100644 --- a/crates/tinymist/src/init.rs +++ b/crates/tinymist/src/init.rs @@ -12,8 +12,10 @@ use reflexo_typst::world::EntryState; use reflexo_typst::{ImmutPath, TypstDict}; use serde::{Deserialize, Serialize}; use serde_json::{json, Map, Value as JsonValue}; +use strum::IntoEnumIterator; use task::FormatUserConfig; -use tinymist_query::{get_semantic_tokens_options, PositionEncoding}; +use tinymist_query::analysis::{Modifier, TokenType}; +use tinymist_query::{CompletionFeat, PositionEncoding}; use tinymist_render::PeriscopeArgs; use typst::foundations::IntoValue; use typst::syntax::{FileId, VirtualPath}; @@ -145,23 +147,11 @@ impl Initializer for SuperInit { return (service, Err(err)); } - // Respond to the host (LSP client) - // Register these capabilities statically if the client does not support dynamic - // registration - let semantic_tokens_provider = match service.config.semantic_tokens { - SemanticTokensMode::Enable if !const_config.tokens_dynamic_registration => { - Some(get_semantic_tokens_options().into()) - } - _ => None, - }; - let document_formatting_provider = match service.config.formatter_mode { - FormatterMode::Typstyle | FormatterMode::Typstfmt - if !const_config.doc_fmt_dynamic_registration => - { - Some(OneOf::Left(true)) - } - _ => None, - }; + let semantic_tokens_provider = (!const_config.tokens_dynamic_registration).then(|| { + SemanticTokensServerCapabilities::SemanticTokensOptions(get_semantic_tokens_options()) + }); + let document_formatting_provider = + (!const_config.doc_fmt_dynamic_registration).then_some(OneOf::Left(true)); let file_operations = const_config.notify_will_rename_files.then(|| { WorkspaceFileOperationsServerCapabilities { @@ -185,7 +175,11 @@ impl Initializer for SuperInit { // position_encoding: Some(cc.position_encoding.into()), hover_provider: Some(HoverProviderCapability::Simple(true)), signature_help_provider: Some(SignatureHelpOptions { - trigger_characters: Some(vec!["(".to_string(), ",".to_string()]), + trigger_characters: Some(vec![ + String::from("("), + String::from(","), + String::from(":"), + ]), retrigger_characters: None, work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None, @@ -271,12 +265,14 @@ impl Initializer for SuperInit { // region Configuration Items const CONFIG_ITEMS: &[&str] = &[ + "tinymist", "outputPath", "exportPdf", "rootPath", "semanticTokens", "formatterMode", "formatterPrintWidth", + "completion", "fontPaths", "systemFonts", "typstExtraArgs", @@ -301,12 +297,10 @@ pub struct Config { pub formatter_mode: FormatterMode, /// Dynamic configuration for the experimental formatter. pub formatter_print_width: Option, - /// Whether to trigger suggest completion, a.k.a. auto-completion. - pub trigger_suggest: bool, - /// Whether to trigger named parameter completion. - pub trigger_named_completion: bool, - /// Whether to trigger parameter hint, a.k.a. signature help. - pub trigger_parameter_hints: bool, + /// Whether to remove html from markup content in responses. + pub support_html_in_markdown: bool, + /// Tinymist's completion features. + pub completion: CompletionFeat, } impl Config { @@ -344,7 +338,16 @@ impl Config { /// Errors if the update is invalid. pub fn update(&mut self, update: &JsonValue) -> anyhow::Result<()> { if let JsonValue::Object(update) = update { - self.update_by_map(update) + let namespaced = update.get("tinymist").and_then(|m| match m { + JsonValue::Object(namespaced) => Some(namespaced), + _ => None, + }); + + self.update_by_map(update)?; + if let Some(namespaced) = namespaced { + self.update_by_map(namespaced)?; + } + Ok(()) } else { bail!("got invalid configuration object {update}") } @@ -355,21 +358,34 @@ impl Config { /// # Errors /// Errors if the update is invalid. pub fn update_by_map(&mut self, update: &Map) -> anyhow::Result<()> { - macro_rules! deser_or_default { - ($key:expr, $ty:ty) => { - try_or_default(|| <$ty>::deserialize(update.get($key)?).ok()) + macro_rules! assign_config { + ($( $field_path:ident ).+ := $bind:literal?: $ty:ty) => { + let v = try_deserialize::<$ty>(update, $bind); + self.$($field_path).+ = v.unwrap_or_default(); }; + ($( $field_path:ident ).+ := $bind:literal: $ty:ty = $default_value:expr) => { + let v = try_deserialize::<$ty>(update, $bind); + self.$($field_path).+ = v.unwrap_or_else(|| $default_value); + }; + } + + fn try_deserialize( + map: &Map, + key: &str, + ) -> Option { + T::deserialize(map.get(key)?) + .inspect_err(|e| log::warn!("failed to deserialize {key:?}: {e}")) + .ok() } - try_(|| SemanticTokensMode::deserialize(update.get("semanticTokens")?).ok()) - .inspect(|v| self.semantic_tokens = *v); - try_(|| FormatterMode::deserialize(update.get("formatterMode")?).ok()) - .inspect(|v| self.formatter_mode = *v); - try_(|| u32::deserialize(update.get("formatterPrintWidth")?).ok()) - .inspect(|v| self.formatter_print_width = Some(*v)); - self.trigger_suggest = deser_or_default!("triggerSuggest", bool); - self.trigger_parameter_hints = deser_or_default!("triggerParameterHints", bool); - self.trigger_named_completion = deser_or_default!("triggerNamedCompletion", bool); + assign_config!(semantic_tokens := "semanticTokens"?: SemanticTokensMode); + assign_config!(formatter_mode := "formatterMode"?: FormatterMode); + assign_config!(formatter_print_width := "formatterPrintWidth"?: Option); + assign_config!(support_html_in_markdown := "supportHtmlInMarkdown"?: bool); + assign_config!(completion := "completion"?: CompletionFeat); + assign_config!(completion.trigger_suggest := "triggerSuggest"?: bool); + assign_config!(completion.trigger_parameter_hints := "triggerParameterHints"?: bool); + assign_config!(completion.trigger_suggest_and_parameter_hints := "triggerSuggestAndParameterHints"?: bool); self.compile.update_by_map(update)?; self.compile.validate() } @@ -560,8 +576,9 @@ impl CompileConfig { root_dir: command.root, inputs: Arc::new(LazyHash::new(inputs)), font: command.font, + package: command.package, creation_timestamp: command.creation_timestamp, - cert: command.certification, + cert: command.cert, }); } @@ -707,6 +724,14 @@ impl CompileConfig { opts } + /// Determines the package options. + pub fn determine_package_opts(&self) -> CompilePackageArgs { + if let Some(extras) = &self.typst_extra_args { + return extras.package.clone(); + } + CompilePackageArgs::default() + } + /// Determines the font resolver. pub fn determine_fonts(&self) -> Deferred> { // todo: on font resolving failure, downgrade to a fake font book @@ -839,6 +864,20 @@ pub enum SemanticTokensMode { Enable, } +pub(crate) fn get_semantic_tokens_options() -> SemanticTokensOptions { + SemanticTokensOptions { + legend: SemanticTokensLegend { + token_types: TokenType::iter() + .filter(|e| *e != TokenType::None) + .map(Into::into) + .collect(), + token_modifiers: Modifier::iter().map(Into::into).collect(), + }, + full: Some(SemanticTokensFullOptions::Delta { delta: Some(true) }), + ..Default::default() + } +} + /// Additional options for compilation. #[derive(Debug, Clone, PartialEq, Default)] pub struct CompileExtraOpts { @@ -850,6 +889,8 @@ pub struct CompileExtraOpts { pub inputs: ImmutDict, /// Additional font paths. pub font: CompileFontArgs, + /// Package related arguments. + pub package: CompilePackageArgs, /// The creation timestamp for various output. pub creation_timestamp: Option>, /// Path to certification file @@ -971,6 +1012,23 @@ mod tests { ); } + #[test] + fn test_namespaced_config() { + let mut config = Config::default(); + + // Emacs uses a shared configuration object for all language servers. + let update = json!({ + "exportPdf": "onSave", + "tinymist": { + "exportPdf": "onType", + } + }); + + config.update(&update).unwrap(); + + assert_eq!(config.compile.export_pdf, ExportMode::OnType); + } + #[test] fn test_config_creation_timestamp() { type Timestamp = Option>; diff --git a/crates/tinymist/src/main.rs b/crates/tinymist/src/main.rs index 40ee79010..1d2046aa9 100644 --- a/crates/tinymist/src/main.rs +++ b/crates/tinymist/src/main.rs @@ -64,10 +64,12 @@ fn main() -> anyhow::Result<()> { env_logger::builder() .filter_module("tinymist", Info) .filter_module("typst_preview", Debug) - .filter_module("typst_ts", Info) + .filter_module("typlite", Info) + .filter_module("reflexo", Info) .filter_module("sync_lsp", Info) - .filter_module("typst_ts_compiler::service::compile", Info) - .filter_module("typst_ts_compiler::service::watch", Info) + .filter_module("reflexo_typst::service::compile", Info) + .filter_module("reflexo_typst::service::watch", Info) + .filter_module("reflexo_typst::diag::console", Info) .try_init() }; diff --git a/crates/tinymist/src/resource/symbols.rs b/crates/tinymist/src/resource/symbols.rs index 1babed1a6..793f4069a 100644 --- a/crates/tinymist/src/resource/symbols.rs +++ b/crates/tinymist/src/resource/symbols.rs @@ -6,7 +6,7 @@ use reflexo_typst::{ }; use sync_lsp::LspResult; -use crate::{actor::typ_client::QuerySnap, z_internal_error}; +use crate::{actor::typ_client::WorldSnapFut, z_internal_error}; pub use super::prelude::*; @@ -52,7 +52,7 @@ enum SymCategory { Harpoon, Tack, // Lowercase Greek and Uppercase Greek - Greek, + Greek, Hebrew, DoubleStruck, } @@ -947,7 +947,7 @@ static CAT_MAP: Lazy> = Lazy::new(|| { impl LanguageState { /// Get the all valid symbols - pub async fn get_symbol_resources(snap: QuerySnap) -> LspResult { + pub async fn get_symbol_resources(snap: WorldSnapFut) -> LspResult { let snap = snap.receive().await.map_err(z_internal_error)?; let mut symbols = ResourceSymbolMap::new(); diff --git a/crates/tinymist/src/server.rs b/crates/tinymist/src/server.rs index 779f674af..3e30670c2 100644 --- a/crates/tinymist/src/server.rs +++ b/crates/tinymist/src/server.rs @@ -22,12 +22,9 @@ use serde::{Deserialize, Serialize}; use serde_json::{Map, Value as JsonValue}; use sync_lsp::*; use task::{CacheTask, ExportUserConfig, FormatTask, FormatUserConfig, UserActionTask}; +use tinymist_query::PageSelection; use tinymist_query::{ - get_semantic_tokens_options, get_semantic_tokens_registration, - get_semantic_tokens_unregistration, PageSelection, -}; -use tinymist_query::{ - lsp_to_typst, CompilerQueryRequest, CompilerQueryResponse, FoldRequestFeature, OnExportRequest, + lsp_to_typst, CompilerQueryRequest, CompilerQueryResponse, FoldRequestFeature, PositionEncoding, SyntaxRequest, }; use tokio::sync::mpsc; @@ -324,6 +321,27 @@ impl LanguageState { return Ok(()); } + const SEMANTIC_TOKENS_REGISTRATION_ID: &str = "semantic_tokens"; + const SEMANTIC_TOKENS_METHOD_ID: &str = "textDocument/semanticTokens"; + + pub fn get_semantic_tokens_registration(options: SemanticTokensOptions) -> Registration { + Registration { + id: SEMANTIC_TOKENS_REGISTRATION_ID.to_owned(), + method: SEMANTIC_TOKENS_METHOD_ID.to_owned(), + register_options: Some( + serde_json::to_value(options) + .expect("semantic tokens options should be representable as JSON value"), + ), + } + } + + pub fn get_semantic_tokens_unregistration() -> Unregistration { + Unregistration { + id: SEMANTIC_TOKENS_REGISTRATION_ID.to_owned(), + method: SEMANTIC_TOKENS_METHOD_ID.to_owned(), + } + } + match (enable, self.sema_tokens_registered) { (true, false) => { trace!("registering semantic tokens"); @@ -753,21 +771,10 @@ impl LanguageState { .context .and_then(|c| c.trigger_character) .and_then(|c| c.chars().next()); - let trigger_suggest = self.config.trigger_suggest; - let trigger_parameter_hints = self.config.trigger_parameter_hints; - let trigger_named_completion = self.config.trigger_named_completion; run_query!( req_id, - self.Completion( - path, - position, - explicit, - trigger_character, - trigger_suggest, - trigger_parameter_hints, - trigger_named_completion - ) + self.Completion(path, position, explicit, trigger_character) ) } @@ -800,13 +807,10 @@ impl LanguageState { run_query!(req_id, self.Symbol(pattern)) } - fn on_enter( - &mut self, - req_id: RequestId, - params: TextDocumentPositionParams, - ) -> ScheduledResult { - let (path, position) = as_path_pos(params); - run_query!(req_id, self.OnEnter(path, position)) + fn on_enter(&mut self, req_id: RequestId, params: OnEnterParams) -> ScheduledResult { + let path = as_path(params.text_document); + let range = params.range; + run_query!(req_id, self.OnEnter(path, range)) } fn will_rename_files( @@ -1025,7 +1029,7 @@ impl LanguageState { DocumentSymbol(req) => query_source!(self, DocumentSymbol, req)?, OnEnter(req) => query_source!(self, OnEnter, req)?, ColorPresentation(req) => CompilerQueryResponse::ColorPresentation(req.request()), - OnExport(OnExportRequest { kind, path }) => return primary().on_export(kind, path), + OnExport(req) => return primary().on_export(req), ServerInfo(_) => return primary().collect_server_info(), _ => return Self::query_on(primary(), is_pinning, query), }) @@ -1040,8 +1044,7 @@ impl LanguageState { type R = CompilerQueryResponse; assert!(query.fold_feature() != FoldRequestFeature::ContextFreeUnique); - let snap_stat = client.snapshot_with_stat(&query)?; - let handle = client.handle.clone(); + let fut_stat = client.query_snapshot_with_stat(&query)?; let entry = query .associated_path() .map(|path| client.config.determine_entry(Some(path.into()))) @@ -1050,10 +1053,8 @@ impl LanguageState { Some(EntryState::new_rooted(root, Some(*DETACHED_ENTRY))) }); - let rev_lock = handle.analysis.lock_revision(); - just_future(async move { - let mut snap = snap_stat.snap.receive().await?; + let mut snap = fut_stat.fut.receive().await?; // todo: whether it is safe to inherit success_doc with changed entry if !is_pinning { snap = snap.task(TaskInputs { @@ -1061,34 +1062,31 @@ impl LanguageState { ..Default::default() }); } - snap_stat.stat.snap(); - - let resp = match query { - SemanticTokensFull(req) => handle.run_semantic(snap, req, R::SemanticTokensFull), - SemanticTokensDelta(req) => handle.run_semantic(snap, req, R::SemanticTokensDelta), - Hover(req) => handle.run_stateful(snap, req, R::Hover), - GotoDefinition(req) => handle.run_stateful(snap, req, R::GotoDefinition), - GotoDeclaration(req) => handle.run_semantic(snap, req, R::GotoDeclaration), - References(req) => handle.run_stateful(snap, req, R::References), - InlayHint(req) => handle.run_semantic(snap, req, R::InlayHint), - DocumentHighlight(req) => handle.run_semantic(snap, req, R::DocumentHighlight), - DocumentColor(req) => handle.run_semantic(snap, req, R::DocumentColor), - DocumentLink(req) => handle.run_semantic(snap, req, R::DocumentLink), - CodeAction(req) => handle.run_semantic(snap, req, R::CodeAction), - CodeLens(req) => handle.run_semantic(snap, req, R::CodeLens), - Completion(req) => handle.run_stateful(snap, req, R::Completion), - SignatureHelp(req) => handle.run_semantic(snap, req, R::SignatureHelp), - Rename(req) => handle.run_stateful(snap, req, R::Rename), - WillRenameFiles(req) => handle.run_stateful(snap, req, R::WillRenameFiles), - PrepareRename(req) => handle.run_stateful(snap, req, R::PrepareRename), - Symbol(req) => handle.run_semantic(snap, req, R::Symbol), - WorkspaceLabel(req) => handle.run_semantic(snap, req, R::WorkspaceLabel), - DocumentMetrics(req) => handle.run_stateful(snap, req, R::DocumentMetrics), + fut_stat.stat.snap(); + + match query { + SemanticTokensFull(req) => snap.run_semantic(req, R::SemanticTokensFull), + SemanticTokensDelta(req) => snap.run_semantic(req, R::SemanticTokensDelta), + Hover(req) => snap.run_stateful(req, R::Hover), + GotoDefinition(req) => snap.run_stateful(req, R::GotoDefinition), + GotoDeclaration(req) => snap.run_semantic(req, R::GotoDeclaration), + References(req) => snap.run_stateful(req, R::References), + InlayHint(req) => snap.run_semantic(req, R::InlayHint), + DocumentHighlight(req) => snap.run_semantic(req, R::DocumentHighlight), + DocumentColor(req) => snap.run_semantic(req, R::DocumentColor), + DocumentLink(req) => snap.run_semantic(req, R::DocumentLink), + CodeAction(req) => snap.run_semantic(req, R::CodeAction), + CodeLens(req) => snap.run_semantic(req, R::CodeLens), + Completion(req) => snap.run_stateful(req, R::Completion), + SignatureHelp(req) => snap.run_semantic(req, R::SignatureHelp), + Rename(req) => snap.run_stateful(req, R::Rename), + WillRenameFiles(req) => snap.run_stateful(req, R::WillRenameFiles), + PrepareRename(req) => snap.run_stateful(req, R::PrepareRename), + Symbol(req) => snap.run_semantic(req, R::Symbol), + WorkspaceLabel(req) => snap.run_semantic(req, R::WorkspaceLabel), + DocumentMetrics(req) => snap.run_stateful(req, R::DocumentMetrics), _ => unreachable!(), - }; - - drop(rev_lock); - resp + } }) } } @@ -1107,9 +1105,22 @@ struct ExportOpts { page: PageSelection, } +/// A parameter for the `experimental/onEnter` command. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct OnEnterParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The visible document range for which `onEnter` edits should be computed. + pub range: Range, +} + struct OnEnter; impl lsp_types::request::Request for OnEnter { - type Params = TextDocumentPositionParams; + type Params = OnEnterParams; type Result = Option>; const METHOD: &'static str = "experimental/onEnter"; } diff --git a/crates/tinymist/src/task/export.rs b/crates/tinymist/src/task/export.rs index 72655ad82..6aca7e8cf 100644 --- a/crates/tinymist/src/task/export.rs +++ b/crates/tinymist/src/task/export.rs @@ -21,7 +21,7 @@ use crate::tool::text::FullTextDigest; use crate::{ actor::{ editor::EditorRequest, - typ_client::QuerySnap, + typ_client::WorldSnapFut, typ_server::{CompiledArtifact, ExportSignal}, }, tool::word_count, @@ -66,7 +66,7 @@ impl ExportTask { pub fn oneshot( &self, - snap: QuerySnap, + snap: WorldSnapFut, entry: Option, kind: ExportKind, ) -> impl Future>> { diff --git a/crates/tinymist/src/task/user_action.rs b/crates/tinymist/src/task/user_action.rs index eb9da4fe4..48bc7cc08 100644 --- a/crates/tinymist/src/task/user_action.rs +++ b/crates/tinymist/src/task/user_action.rs @@ -176,11 +176,9 @@ async fn trace_main( let timings = writer.into_inner().unwrap(); - let diagnostics = state.primary().handle.run_analysis(w, |ctx| { - tinymist_query::convert_diagnostics(ctx, diags.iter()) - }); - - let diagnostics = diagnostics.unwrap_or_default(); + let handle = &state.primary().handle; + let diagnostics = + tinymist_query::convert_diagnostics(w, diags.iter(), handle.analysis.position_encoding); let rpc_kind = rpc_kind.as_str(); diff --git a/crates/tinymist/src/tool/package/mod.rs b/crates/tinymist/src/tool/package/mod.rs index 58c3bc11b..6f60a66d8 100644 --- a/crates/tinymist/src/tool/package/mod.rs +++ b/crates/tinymist/src/tool/package/mod.rs @@ -1,42 +1,4 @@ //! Package management tools. -use reflexo_typst::package::PackageRegistry; -use typst::diag::{eco_format, StrResult}; -use typst::syntax::package::{PackageVersion, VersionlessPackageSpec}; - -use crate::LspWorld; - mod init; pub use init::*; - -/// Try to determine the latest version of a package. -pub fn determine_latest_version( - world: &LspWorld, - spec: &VersionlessPackageSpec, -) -> StrResult { - if spec.namespace == "preview" { - let packages = world.registry.packages(); - packages - .iter() - .filter(|(package, _)| package.namespace == "preview" && package.name == spec.name) - .map(|(package, _)| package.version) - .max() - .ok_or_else(|| eco_format!("failed to find package {spec}")) - } else { - // For other namespaces, search locally. We only search in the data - // directory and not the cache directory, because the latter is not - // intended for storage of local packages. - let subdir = format!("typst/packages/{}/{}", spec.namespace, spec.name); - world - .registry - .local_path() - .into_iter() - .flat_map(|dir| std::fs::read_dir(dir.join(&subdir)).ok()) - .flatten() - .filter_map(|entry| entry.ok()) - .map(|entry| entry.path()) - .filter_map(|path| path.file_name()?.to_string_lossy().parse().ok()) - .max() - .ok_or_else(|| eco_format!("please specify the desired version")) - } -} diff --git a/crates/tinymist/src/tool/word_count.rs b/crates/tinymist/src/tool/word_count.rs index ff7fd26c0..638a30a5a 100644 --- a/crates/tinymist/src/tool/word_count.rs +++ b/crates/tinymist/src/tool/word_count.rs @@ -133,9 +133,8 @@ impl TextExportWorker { match item { Group(g) => self.frame(&g.frame), Text(t) => { - write!(self.w, "{}", t.text.as_str()) + write!(self.w, " {}", t.text.as_str()) } - // Meta(ContentHint(c), _) => f.write_char(*c), Link(..) | Shape(..) | Image(..) => self.w.write_all(b"object"), Tag(..) => Ok(()), } diff --git a/crates/typlite/src/lib.rs b/crates/typlite/src/lib.rs index de5459527..a5addf374 100644 --- a/crates/typlite/src/lib.rs +++ b/crates/typlite/src/lib.rs @@ -13,8 +13,10 @@ pub use error::*; use base64::Engine; use scopes::Scopes; +use tinymist_world::reflexo_typst::path::unix_slash; use tinymist_world::{base::ShadowApi, EntryReader, LspWorld}; use typst::foundations::IntoValue; +use typst::WorldExt; use typst::{ foundations::{Bytes, Dict}, layout::Abs, @@ -44,18 +46,28 @@ pub enum ColorTheme { Dark, } +#[derive(Debug, Default, Clone)] +pub struct TypliteFeat { + /// The preferred color theme + pub color_theme: Option, + /// Allows GFM (GitHub Flavored Markdown) markups. + pub gfm: bool, + /// Annotate the elements for identification. + pub annotate_elem: bool, + /// Embed errors in the output instead of yielding them. + pub soft_error: bool, + /// Remove HTML tags from the output. + pub remove_html: bool, +} + /// Task builder for converting a typst document to Markdown. pub struct Typlite { /// The universe to use for the conversion. world: Arc, /// library to use for the conversion. library: Option>>, - /// Documentation style to use for annotating the document. - do_annotate: bool, - /// Whether to enable GFM (GitHub Flavored Markdown) features. - gfm: bool, - /// The preferred color theme - theme: Option, + /// Features for the conversion. + feat: TypliteFeat, } impl Typlite { @@ -67,9 +79,7 @@ impl Typlite { Self { world, library: None, - do_annotate: false, - gfm: false, - theme: None, + feat: Default::default(), } } @@ -79,15 +89,9 @@ impl Typlite { self } - /// Set the preferred color theme. - pub fn with_color_theme(mut self, theme: ColorTheme) -> Self { - self.theme = Some(theme); - self - } - - /// Annotate the elements for identification. - pub fn annotate_elements(mut self, do_annotate: bool) -> Self { - self.do_annotate = do_annotate; + /// Set conversion feature + pub fn with_feature(mut self, feat: TypliteFeat) -> Self { + self.feat = feat; self } @@ -106,9 +110,7 @@ impl Typlite { let worker = TypliteWorker { current, - gfm: self.gfm, - do_annotate: self.do_annotate, - theme: self.theme, + feat: self.feat, list_depth: 0, scopes: self .library @@ -126,12 +128,11 @@ impl Typlite { #[derive(Clone)] pub struct TypliteWorker { current: FileId, - theme: Option, - gfm: bool, - do_annotate: bool, scopes: Arc>, world: Arc, list_depth: usize, + /// Features for the conversion. + pub feat: TypliteFeat, } impl TypliteWorker { @@ -318,6 +319,34 @@ impl TypliteWorker { Ok(Value::Content(s)) } + pub fn to_raw_block(&mut self, node: &SyntaxNode, inline: bool) -> Result { + let content = node.clone().into_text(); + + let s = if inline { + let mut s = EcoString::with_capacity(content.len() + 2); + s.push_str("`"); + s.push_str(&content); + s.push_str("`"); + s + } else { + let mut s = EcoString::with_capacity(content.len() + 15); + s.push_str("```"); + let lang = match node.cast::() { + Some(ast::Expr::Text(..) | ast::Expr::Space(..)) => "typ", + Some(..) => "typc", + None => "typ", + }; + s.push_str(lang); + s.push('\n'); + s.push_str(&content); + s.push('\n'); + s.push_str("```"); + s + }; + + Ok(Value::Content(s)) + } + pub fn render(&mut self, node: &SyntaxNode, inline: bool) -> Result { let code = node.clone().into_text(); self.render_code(&code, false, "center", "", inline) @@ -331,13 +360,10 @@ impl TypliteWorker { extra_attrs: &str, inline: bool, ) -> Result { - let theme = self.theme; + let theme = self.feat.color_theme; let mut render = |theme| self.render_inner(code, is_markup, theme); let mut content = EcoString::new(); - if !inline { - let _ = write!(content, r#"

"#); - } let inline_attrs = if inline { r#" style="vertical-align: -0.35em""# @@ -346,26 +372,55 @@ impl TypliteWorker { }; match theme { Some(theme) => { - let data = render(theme)?; - let _ = write!( - content, - r#""#, - ); + let data = render(theme); + match data { + Ok(data) => { + if !inline { + let _ = write!(content, r#"

"#); + } + let _ = write!( + content, + r#""#, + ); + if !inline { + content.push_str("

"); + } + } + Err(err) if self.feat.soft_error => { + // wrap the error in a fenced code block + let err = err.to_string().replace("`", r#"\`"#); + let _ = write!(content, "```\nRender Error\n{err}\n```"); + } + Err(err) => return Err(err), + } } None => { - let _ = write!( - content, - r#""#, - dark = render(ColorTheme::Dark)?, - light = render(ColorTheme::Light)? - ); + let dark = render(ColorTheme::Dark); + let light = render(ColorTheme::Light); + + match (dark, light) { + (Ok(dark), Ok(light)) => { + if !inline { + let _ = write!(content, r#"

"#); + } + let _ = write!( + content, + r#""#, + ); + if !inline { + content.push_str("

"); + } + } + (Err(err), _) | (_, Err(err)) if self.feat.soft_error => { + // wrap the error in a fenced code block + let err = err.to_string().replace("`", r#"\`"#); + let _ = write!(content, "```\nRendering Error\n{err}\n```"); + } + (Err(err), _) | (_, Err(err)) => return Err(err), + } } } - if !inline { - content.push_str("

"); - } - Ok(Value::Content(content)) } @@ -400,9 +455,63 @@ impl TypliteWorker { world.source_db.take_state(); world.map_shadow_by_id(main_id, main).unwrap(); - let document = typst::compile(&world) - .output - .map_err(|e| format!("compiling math node: {e:?}"))?; + let document = typst::compile(&world).output; + let document = document.map_err(|e| { + let mut err = String::new(); + let _ = write!(err, "compiling node: "); + let write_span = |span: typst_syntax::Span, err: &mut String| { + let file = span.id().map(|id| match id.package() { + Some(package) => { + format!("{package}:{}", unix_slash(id.vpath().as_rooted_path())) + } + None => unix_slash(id.vpath().as_rooted_path()), + }); + let range = world.range(span); + match (file, range) { + (Some(file), Some(range)) => { + let _ = write!(err, "{file:?}:{range:?}"); + } + (Some(file), None) => { + let _ = write!(err, "{file:?}"); + } + (None, Some(range)) => { + let _ = write!(err, "{range:?}"); + } + _ => { + let _ = write!(err, "unknown location"); + } + } + }; + + for s in e.iter() { + match s.severity { + typst::diag::Severity::Error => { + let _ = write!(err, "error: "); + } + typst::diag::Severity::Warning => { + let _ = write!(err, "warning: "); + } + } + + err.push_str(&s.message); + err.push_str(" at "); + write_span(s.span, &mut err); + + for hint in s.hints.iter() { + err.push_str("\nHint: "); + err.push_str(hint); + } + + for trace in &s.trace { + write!(err, "\nTrace: {} at ", trace.v).unwrap(); + write_span(trace.span, &mut err); + } + + err.push('\n'); + } + + err + })?; let svg_payload = typst_svg::svg_merged(&document, Abs::zero()); Ok(base64::engine::general_purpose::STANDARD.encode(svg_payload)) @@ -485,7 +594,7 @@ impl TypliteWorker { fn link(&mut self, node: &SyntaxNode) -> Result { // GFM supports autolinks - if self.gfm { + if self.feat.gfm { // return Self::str(node, s); return Self::str(node); } @@ -518,12 +627,12 @@ impl TypliteWorker { let list_item = node.cast::().unwrap(); s.push_str("- "); - if self.do_annotate { + if self.feat.annotate_elem { let _ = write!(s, "", self.list_depth); self.list_depth += 1; } s.push_str(&Self::value(self.eval(list_item.body().to_untyped())?)); - if self.do_annotate { + if self.feat.annotate_elem { self.list_depth -= 1; let _ = write!(s, "", self.list_depth); } @@ -552,6 +661,10 @@ impl TypliteWorker { fn equation(&mut self, node: &SyntaxNode) -> Result { let equation: ast::Equation = node.cast().unwrap(); + if self.feat.remove_html { + return self.to_raw_block(node, !equation.block()); + } + self.render(node, !equation.block()) } @@ -584,6 +697,9 @@ impl TypliteWorker { } fn contextual(&mut self, node: &SyntaxNode) -> Result { + if self.feat.remove_html { + return self.to_raw_block(node, false); + } self.render(node, false) } diff --git a/crates/typlite/src/library.rs b/crates/typlite/src/library.rs index 120961393..1f5ac37c5 100644 --- a/crates/typlite/src/library.rs +++ b/crates/typlite/src/library.rs @@ -47,7 +47,7 @@ pub fn figure(mut args: Args) -> Result { match (body, caption) { (Value::Image { path, alt }, None) => Ok(Value::Content(eco_format!("![{alt}]({path})"))), - (Value::Image { path, alt }, Some(caption)) if args.vm.gfm => Ok(Value::Content( + (Value::Image { path, alt }, Some(caption)) if args.vm.feat.gfm => Ok(Value::Content( eco_format!("![{caption}, {alt}]({path} {caption:?})"), )), (Value::Image { path, alt }, Some(caption)) => { diff --git a/crates/typlite/src/library/docstring.rs b/crates/typlite/src/library/docstring.rs index 390818cb8..992605be7 100644 --- a/crates/typlite/src/library/docstring.rs +++ b/crates/typlite/src/library/docstring.rs @@ -47,12 +47,13 @@ pub fn example(mut args: Args) -> Result { s.push_str("```"); s.push('\n'); - // todo: render examples only if supports HTML - let is_code = lang == "typc"; - let rendered = args - .vm - .render_code(&compile, !is_code, "left", r#"width="500px""#, false)?; - s.push_str(&TypliteWorker::value(rendered)); + if !args.vm.feat.remove_html { + let is_code = lang == "typc"; + let rendered = + args.vm + .render_code(&compile, !is_code, "left", r#"width="500px""#, false)?; + s.push_str(&TypliteWorker::value(rendered)); + } Ok(Value::Content(s)) } diff --git a/crates/typlite/src/tests.rs b/crates/typlite/src/tests.rs index 29b48943d..2a6a7e16c 100644 --- a/crates/typlite/src/tests.rs +++ b/crates/typlite/src/tests.rs @@ -10,20 +10,19 @@ use typst_syntax::Source; use super::*; fn conv_(s: &str, for_docs: bool) -> EcoString { - static FONT_RESOLVER: LazyLock>> = LazyLock::new(|| { - Ok(Arc::new( + static FONT_RESOLVER: LazyLock> = LazyLock::new(|| { + Arc::new( LspUniverseBuilder::resolve_fonts(CompileFontArgs::default()) - .map_err(|e| format!("{e:?}"))?, - )) + .expect("cannot resolve default fonts"), + ) }); - let font_resolver = FONT_RESOLVER.clone(); let cwd = std::env::current_dir().unwrap(); let main = Source::detached(s); let mut universe = LspUniverseBuilder::build( EntryState::new_rooted(cwd.as_path().into(), Some(main.id())), - font_resolver.unwrap(), Default::default(), + FONT_RESOLVER.clone(), Default::default(), ) .unwrap(); @@ -32,16 +31,14 @@ fn conv_(s: &str, for_docs: bool) -> EcoString { .unwrap(); let world = universe.snapshot(); - let converter = Typlite::new(Arc::new(world)).annotate_elements(for_docs); + let converter = Typlite::new(Arc::new(world)).with_feature(TypliteFeat { + annotate_elem: for_docs, + ..Default::default() + }); let res = converter.convert().unwrap(); static REG: OnceLock = OnceLock::new(); let reg = REG.get_or_init(|| Regex::new(r#"data:image/svg\+xml;base64,([^"]+)"#).unwrap()); let res = reg.replace_all(&res, |_captures: ®ex::Captures| { - // let hash = _captures.get(1).unwrap().as_str(); - // format!( - // "data:image-hash/svg+xml;base64,siphash128:{:x}", - // typst_shim::utils::hash128(hash) - // ) "data:image-hash/svg+xml;base64,redacted" }); @@ -61,43 +58,39 @@ fn test_converted() { insta::assert_snapshot!(conv(r###" = Hello, World! This is a typst document. - "###), @r###" - # Hello, World! - This is a typst document. - "###); + "###), @r" + # Hello, World! + This is a typst document. + "); insta::assert_snapshot!(conv(r###" Some inlined raw `a`, ```c b``` "###), @"Some inlined raw `a`, `b`"); insta::assert_snapshot!(conv(r###" - Some *item* - Another _item_ - "###), @r###" - - Some **item** - - Another _item_ - "###); + "###), @r" + - Some **item** + - Another _item_ + "); insta::assert_snapshot!(conv(r###" + A + B - "###), @r###" - 1. A - 1. B - "###); + "###), @r" + 1. A + 1. B + "); insta::assert_snapshot!(conv(r###" 2. A + B - "###), @r###" - 2. A - 1. B - "###); + "###), @r" + 2. A + 1. B + "); insta::assert_snapshot!(conv(r###" $ 1/2 + 1/3 = 5/6 $ - "###), @r###" - -

typst-block

- - "###); + "###), @r#"

typst-block

"#); } #[test] @@ -121,8 +114,7 @@ See @@show-module() for outputting the results of this function. - preamble (string): Code to prepend to all code snippets shown with `#example()`. This can for instance be used to import something from the scope. -> string - "###), @r###" - + "###), @r" These again are dictionaries with the keys - `description` (optional): The description for the argument. - `types` (optional): A list of accepted argument types. @@ -141,8 +133,7 @@ See @@show-module() for outputting the results of this function. - preamble (string): Code to prepend to all code snippets shown with `#example()`. This can for instance be used to import something from the scope. -> string - - "###); + "); insta::assert_snapshot!(conv_docs(r###" These again are dictionaries with the keys - `description` (optional): The description for the argument. @@ -155,8 +146,7 @@ See @@show-module() for outputting the results of this function. - nested something - nested something 2 -> string - "###), @r###" - + "###), @r" These again are dictionaries with the keys - `description` (optional): The description for the argument. @@ -168,6 +158,5 @@ See @@show-module() for outputting the results of this function. - nested something - nested something 2 -> string - - "###); + "); } diff --git a/crates/typlite/src/tests/rendering.rs b/crates/typlite/src/tests/rendering.rs index 529534e83..bbd083d1b 100644 --- a/crates/typlite/src/tests/rendering.rs +++ b/crates/typlite/src/tests/rendering.rs @@ -4,16 +4,8 @@ use crate::tests::*; fn test_math_equation() { insta::assert_snapshot!(conv(r###" $integral x dif x$ - "###), @r###" - - typst-block - - "###); + "###), @r#"typst-block"#); insta::assert_snapshot!(conv(r###" $ integral x dif x $ - "###), @r###" - -

typst-block

- - "###); + "###), @r#"

typst-block

"#); } diff --git a/docs/tinymist/feature/language-content.typ b/docs/tinymist/feature/language-content.typ index 23dfe6688..b3aa4810a 100644 --- a/docs/tinymist/feature/language-content.typ +++ b/docs/tinymist/feature/language-content.typ @@ -29,6 +29,7 @@ Language service (LSP) features: - Or ctrl+click on a symbol. - #link("https://code.visualstudio.com/api/language-extensions/programmatic-language-features#show-hovers")[Hover tips] - Also known as "hovering tooltip". + - Render docs according to #link("https://github.com/Mc-Zen/tidy")[tidy] style. - #link("https://www.jetbrains.com/help/idea/inlay-hints.html")[Inlay hints] - Inlay hints are special markers that appear in the editor and provide you with additional information about your code, like the names of the parameters that a called method expects. - #link("https://code.visualstudio.com/api/language-extensions/programmatic-language-features#show-color-decorators")[Color Provider] @@ -41,10 +42,12 @@ Language service (LSP) features: - #link("https://code.visualstudio.com/api/language-extensions/programmatic-language-features#show-all-symbol-definitions-in-folder")[Workspace Symbols] - #link("https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-code-actions")[Code Action] - Increasing/Decreasing heading levels. + - Turn equation into "inline", "block" or "multiple-line block" styles. - #link("https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#on-enter")[experimental/onEnter] - #kbd("Enter") inside triple-slash comments automatically inserts `///` - #kbd("Enter") in the middle or after a trailing space in `//` inserts `//` - #kbd("Enter") inside `//!` doc comments automatically inserts `//!` + - #kbd("Enter") inside equation markups automatically inserts indents. Extra features: diff --git a/docs/tinymist/frontend/emacs.typ b/docs/tinymist/frontend/emacs.typ index 63eed7401..a89c360c5 100644 --- a/docs/tinymist/frontend/emacs.typ +++ b/docs/tinymist/frontend/emacs.typ @@ -42,24 +42,7 @@ For example, if you want to export PDF on save: ```el (setq-default eglot-workspace-configuration - '(:exportPdf "onSave")) -``` - -Here is an example for both configuring `pylsp` and `tinymist` - -```el - (setq-default eglot-workspace-configuration - '(:pylsp (:plugins (:ruff (:enabled t))) - :exportPdf "onSave")) -``` - -NOTE: Currently, `tinymist` doesn't support having its name as the top-level -configuration entry, so the following configuration won't work: - -```el - (setq-default eglot-workspace-configuration - '(:pylsp (:plugins (:ruff (:enabled t))) - :tinymist (:exportPdf "onSave"))) + '(:tinymist (:exportPdf "onSave"))) ``` You can also have configuration per directory. Be sure to look at the diff --git a/docs/tinymist/introduction.typ b/docs/tinymist/introduction.typ index ddf839bde..23299e93d 100644 --- a/docs/tinymist/introduction.typ +++ b/docs/tinymist/introduction.typ @@ -76,17 +76,43 @@ Nightly Channel: == Roadmap +The development in typst v0.12.0 has been finished. We'll slow down for a while to catch regressions and bugs by changes. We are also planning to implement the following features in typst v0.13.0 or spare time in weekend: + - Spell checking: There is already a branch but no suitable (default) spell checking library is found. +- Type checking: complete the type checker. +- Static Linter: linting code statically according to feedback of the type checker and succeeding code analysis. - Periscope renderer: It is disabled since vscode reject to render SVGs containing foreignObjects. - Inlay hint: It is disabled _by default_ because of performance issues. - Find references of dictionary fields and named function arguments. -- Go to definition of dictionary fields and named function arguments. +- A reliable way of configuring projects's entry files and files to export across editors. See #link("https://github.com/Myriad-Dreamin/tinymist/issues/530")[GitHub Issue 530.] - Improve symbol view's appearance. +- Improve package view. + - Navigate to symbols by clicking on the symbol name in the view. + - Automatically locate the symbol item in the view when viewing local documentation. + - Remember the recently invoked package commands, e.g. "Open Docs of \@preview/cetz:0.3.1", "Open directory of \@preview/touying:0.5.3". +- Improve label view. + - Group labels. + - Search labels. + - Keep (persist) group preferences. +- Improve Typst Preview. + - Browsing mode: if no main file is specified, the preview will be in browsing mode and use the recently focused file as the main. + - Pin drop-down: Set the file to preview in the drop-down for clients that doesn't support passing arguments to the preview command. + - Render in web worker (another thread) to reduce overhead on the electron's main thread. + +If you are interested by any above features, please feel free to send Issues to discuss or PRs to implement to #link("https://github.com/Myriad-Dreamin/tinymist")[GitHub.] == Contributing Please read the #link("CONTRIBUTING.md")[CONTRIBUTING.md] file for contribution guidelines. +== Maintainers + +Get list of maintainers from #link("https://github.com/Myriad-Dreamin/tinymist/blob/main/MAINTAINERS.typ")[MAINTAINERS.typ]. Or programmatically by `yarn maintainers` + +#note-box[ + You can add extra arguments for specific information. For example, `yarn maintainers --input="action=maintainers"`. +] + == Acknowledgements - Partially code is inherited from #link("https://github.com/nvarner/typst-lsp")[typst-lsp] diff --git a/docs/tinymist/module/lsp.typ b/docs/tinymist/module/lsp.typ index 0969abe70..d51fe053f 100644 --- a/docs/tinymist/module/lsp.typ +++ b/docs/tinymist/module/lsp.typ @@ -15,21 +15,24 @@ From the directory structure of `crates/tinymist`, the `main.rs` file parses the ```rust match args.command.unwrap_or_default() { + Commands::Query(query_cmds) => query_main(query_cmds), Commands::Lsp(args) => lsp_main(args), - Commands::Compile(args) => compiler_main(args), + Commands::TraceLsp(args) => trace_lsp_main(args), Commands::Preview(args) => tokio_runtime.block_on(preview_main(args)), Commands::Probe => Ok(()), } ``` +The `query` subcommand contains the query commands, which are used to perform language queries via cli, which is convenient for debugging and profiling single query of the language server. + There are three servers in the `server` directory: -- `lsp.rs` provides the language server, initialized by `lsp_init.rs` and owns commands in `lsp_cmd.rs`. -- `compiler.rs` provides the compiler server, initialized by `compiler_init.rs` and owns commands in `compiler_cmd.rs`. -- `preview.rs` provides a `typst-preview` compatible preview server. +- `lsp` provides the language server, initialized by `lsp_main` in `main.rs`. +- `trace` provides the trace server (profiling typst programs), initialized by `trace_lsp_main` in `main.rs`. +- `preview` provides a `typst-preview` compatible preview server, initialized by `preview_main` in `tool/preview.rs`. -The long-running servers are contributed by the modules in the `server` directory. +The long-running servers are contributed by the `LanguageState` in the `server.rs` file. -They will bootstrap actors in the `actor` directory. +They will bootstrap actors in the `actor` directory and start tasks in the `task` directory. They can construct and return resources in the `resource` directory. diff --git a/editors/emacs/README.md b/editors/emacs/README.md index 7bc0ac7fa..c3d59c9ff 100644 --- a/editors/emacs/README.md +++ b/editors/emacs/README.md @@ -61,24 +61,7 @@ For example, if you want to export PDF on save: ```el (setq-default eglot-workspace-configuration - '(:exportPdf "onSave")) -``` - -Here is an example for both configuring `pylsp` and `tinymist` - -```el - (setq-default eglot-workspace-configuration - '(:pylsp (:plugins (:ruff (:enabled t))) - :exportPdf "onSave")) -``` - -NOTE: Currently, `tinymist` doesn't support having its name as the top-level -configuration entry, so the following configuration won't work: - -```el - (setq-default eglot-workspace-configuration - '(:pylsp (:plugins (:ruff (:enabled t))) - :tinymist (:exportPdf "onSave"))) + '(:tinymist (:exportPdf "onSave"))) ``` You can also have configuration per directory. Be sure to look at the diff --git a/editors/neovim/Configuration.md b/editors/neovim/Configuration.md index 41fc8663d..7e4ef8060 100644 --- a/editors/neovim/Configuration.md +++ b/editors/neovim/Configuration.md @@ -81,3 +81,37 @@ Set the print width for the formatter, which is a **soft limit** of characters p - **Type**: `number` - **Default**: `120` + +## `completion.triggerOnSnippetPlaceholders` + +Whether to trigger completions on arguments (placeholders) of snippets. For example, `box` will be completed to `box(|)`, and server will request the editor (lsp client) to request completion after moving cursor to the placeholder in the snippet. Note: this has no effect if the editor doesn't support `editor.action.triggerSuggest` or `tinymist.triggerSuggestAndParameterHints` command. Hint: Restarting the editor is required to change this setting. + +- **Type**: `boolean` + +## `completion.postfix` + +Whether to enable postfix code completion. For example, `[A].box|` will be completed to `box[A]|`. Hint: Restarting the editor is required to change this setting. + +- **Type**: `boolean` +- **Default**: `true` + +## `completion.postfixUfcs` + +Whether to enable UFCS-style completion. For example, `[A].box|` will be completed to `box[A]|`. Hint: Restarting the editor is required to change this setting. + +- **Type**: `boolean` +- **Default**: `true` + +## `completion.postfixUfcsLeft` + +Whether to enable left-variant UFCS-style completion. For example, `[A].table|` will be completed to `table(|)[A]`. Hint: Restarting the editor is required to change this setting. + +- **Type**: `boolean` +- **Default**: `true` + +## `completion.postfixUfcsRight` + +Whether to enable right-variant UFCS-style completion. For example, `[A].table|` will be completed to `table([A], |)`. Hint: Restarting the editor is required to change this setting. + +- **Type**: `boolean` +- **Default**: `true` diff --git a/editors/vscode/CHANGELOG.md b/editors/vscode/CHANGELOG.md index 0b9643e44..e58a5edb8 100644 --- a/editors/vscode/CHANGELOG.md +++ b/editors/vscode/CHANGELOG.md @@ -4,6 +4,112 @@ All notable changes to the "tinymist" extension will be documented in this file. Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. +## v0.12.2 - [2024-11-15] + +* Bumped typstyle to v0.12.1 by @Enter-tainer in https://github.com/Myriad-Dreamin/tinymist/pull/764 +* Claiming list of maintainers in https://github.com/Myriad-Dreamin/tinymist/pull/781 + +### Announcement: New Maintainers + +We are going to add maintainers to GitHub since 2024-11-22 (in 7 days): +- @ParaN3xus want to maintain the "Nightly Releases" feature in https://github.com/Myriad-Dreamin/tinymist/pull/783 +- @max397574 want to maintain the "Editor integration" feature in https://github.com/Myriad-Dreamin/tinymist/pull/784 +- @Eric-Song-Nop want to maintain the "Language Service" feature in https://github.com/Myriad-Dreamin/tinymist/pull/796 +- @alerque want to maintain the "Neovim integration" feature in https://github.com/Myriad-Dreamin/tinymist/pull/810 + +*Please reply in PRs or DM @Myriad-Dreamin if you have any concerns about adding these maintainers to list.* + +### Docs + +* Added coc.nvim config example by @tanloong in https://github.com/Myriad-Dreamin/tinymist/pull/727 +* Maintained docs for tinymist 0.12.2 in https://github.com/Myriad-Dreamin/tinymist/pull/733 and https://github.com/Myriad-Dreamin/tinymist/pull/825 +* Updated neovim's setup section in https://github.com/Myriad-Dreamin/tinymist/pull/749 +* Added documentation about docstring in https://github.com/Myriad-Dreamin/tinymist/pull/771 + +### Editor + +* {En,De}coding base-64 strings with Text{De,En}coder in https://github.com/Myriad-Dreamin/tinymist/pull/719 and https://github.com/Myriad-Dreamin/tinymist/pull/774 +* Removed outdated typst.tmLanguage.json in https://github.com/Myriad-Dreamin/tinymist/pull/725 +* Disabling unicode bracket pair autocompletion in https://github.com/Myriad-Dreamin/tinymist/pull/726 + * This is a degradation, as discussed in https://github.com/Myriad-Dreamin/tinymist/issues/723 +* Added preview icon when clicking outside the document by @supersurviveur in https://github.com/Myriad-Dreamin/tinymist/pull/734 + +### Compiler + +* Implemented expression checker in https://github.com/Myriad-Dreamin/tinymist/pull/714, https://github.com/Myriad-Dreamin/tinymist/pull/736, https://github.com/Myriad-Dreamin/tinymist/pull/756, https://github.com/Myriad-Dreamin/tinymist/pull/759, https://github.com/Myriad-Dreamin/tinymist/pull/773, https://github.com/Myriad-Dreamin/tinymist/pull/775, https://github.com/Myriad-Dreamin/tinymist/pull/777, https://github.com/Myriad-Dreamin/tinymist/pull/798, https://github.com/Myriad-Dreamin/tinymist/pull/801, https://github.com/Myriad-Dreamin/tinymist/pull/815, and https://github.com/Myriad-Dreamin/tinymist/pull/822 + * This is a high-level IR for various analyses above AST, e.g. type checking. +* Improved ways of checking docstring in https://github.com/Myriad-Dreamin/tinymist/pull/752, https://github.com/Myriad-Dreamin/tinymist/pull/755 +* Locking and taking snapshot {analysis,token} caches on main thread in https://github.com/Myriad-Dreamin/tinymist/pull/806, https://github.com/Myriad-Dreamin/tinymist/pull/817, and https://github.com/Myriad-Dreamin/tinymist/pull/819 +* (Fix) Rendered bitmap and svg glyphs correctly in https://github.com/Myriad-Dreamin/tinymist/pull/745 + * This is broken by update typst to v0.12.0. +* (Fix) Ensuring expr and type enum are not too big correctly in https://github.com/Myriad-Dreamin/tinymist/pull/811 + +### Commands/Tools + +* Added `tinymist query checkPackage` command in https://github.com/Myriad-Dreamin/tinymist/pull/742 +* Showing performance statistics in summary page in https://github.com/Myriad-Dreamin/tinymist/pull/743 +* Completed symbol classification in handwriting recognizer by @summerBreeze03 in https://github.com/Myriad-Dreamin/tinymist/pull/705 +* (Fix) Corrected word count when empty line exists by @Eric-Song-Nop in https://github.com/Myriad-Dreamin/tinymist/pull/795 +* (Fix) Corrected usage of `/package/symbol` in package view in https://github.com/Myriad-Dreamin/tinymist/pull/820 +* (Fix) Querying file type with following symbolic links when listing packages in https://github.com/Myriad-Dreamin/tinymist/pull/821 + * Previously, some directories are not identified because they are behind symbolic links. + +### Docstring + +* Strictly matching module-level comments in https://github.com/Myriad-Dreamin/tinymist/pull/770 +* Rendering examples in docs in https://github.com/Myriad-Dreamin/tinymist/pull/772 +* Emitting errors into docs instead of causing failures in https://github.com/Myriad-Dreamin/tinymist/pull/786 +* Striping out the line containing the return type in https://github.com/Myriad-Dreamin/tinymist/pull/803 + +### Hover (Tooltip) + +* Providing docs when hovering on module refs in https://github.com/Myriad-Dreamin/tinymist/pull/751 +* Improved style of hover param docs in https://github.com/Myriad-Dreamin/tinymist/pull/813 +* Conditionally rendering code in docs in https://github.com/Myriad-Dreamin/tinymist/pull/824 + +### Completion + +* (Fix) Client-side controlling to whether issue completion callback in https://github.com/Myriad-Dreamin/tinymist/pull/744 +* (Fix) Matching all identifier-like nodes for completion in https://github.com/Myriad-Dreamin/tinymist/pull/747 +* Avoiding trivial completion when the trigger char is an ascii punctuation in https://github.com/Myriad-Dreamin/tinymist/pull/748 +* Added more completion tests in https://github.com/Myriad-Dreamin/tinymist/pull/776 +* Consistently enriching colon after show selectors in https://github.com/Myriad-Dreamin/tinymist/pull/785 + +### Syntax/Semantic Highlighting + +* Improved syntax highlighting in https://github.com/Myriad-Dreamin/tinymist/pull/724 + - [parse blocks in if/for/while more consistently](https://github.com/Myriad-Dreamin/tinymist/commit/0ac36e77408930154f1f4057aedf3da45b69f2b2) + - [improve context expression parsing](https://github.com/Myriad-Dreamin/tinymist/commit/95dbf22c1cd08c12abd46c314c40114999108c16) + - [improve parameter clause parsing](https://github.com/Myriad-Dreamin/tinymist/commit/7468ba42fa12b502dddb00d5afcd31936e07282a) +* Improved buggy bold/italic syntax highlighting in https://github.com/Myriad-Dreamin/tinymist/pull/732 + * This is benefitted from having the expression checker. +* Identifying identifier kind for semantic highlighting in https://github.com/Myriad-Dreamin/tinymist/pull/741 +* (Fix) Corrected to syntax rule to identify function identifiers by syntax in https://github.com/Myriad-Dreamin/tinymist/pull/800 + * We were not highlighting `"#{test\n[]}"` correctly. +* Refactored semantic tokens apis and crates in https://github.com/Myriad-Dreamin/tinymist/pull/802 and https://github.com/Myriad-Dreamin/tinymist/pull/809 + +### Signature Help + +* Improved style of signature docs in https://github.com/Myriad-Dreamin/tinymist/pull/750 + +### Preview + +* (Fix) Bidirectionally jumping if page.fill is set in https://github.com/Myriad-Dreamin/tinymist/pull/728 + * This is broken by update typst to v0.12.0. + +### On Enter + +* Fully supported `onEnter` edits inside comments in https://github.com/Myriad-Dreamin/tinymist/pull/823 + * Working with selection with range for all clients. + * Working with selection with multiple cursors for VS Cod{e,ium} client. + +### Misc + +* Uploading test snapshot and log for debugging in https://github.com/Myriad-Dreamin/tinymist/pull/760 and https://github.com/Myriad-Dreamin/tinymist/pull/787 +* Added time limit argument to language server's replay command in https://github.com/Myriad-Dreamin/tinymist/pull/816 + +**Full Changelog**: https://github.com/Myriad-Dreamin/tinymist/compare/v0.12.0...v0.12.2 + ## v0.12.0 - [2024-10-19] ### Document Link diff --git a/editors/vscode/Configuration.md b/editors/vscode/Configuration.md index 2fedc47b0..8289af64e 100644 --- a/editors/vscode/Configuration.md +++ b/editors/vscode/Configuration.md @@ -34,6 +34,13 @@ Enable or disable semantic tokens (LSP syntax highlighting) - `disable`: Do not use semantic tokens for syntax highlighting - **Default**: `"enable"` +## `tinymist.typingContinueCommentsOnNewline` + +Whether to prefix newlines after comments with the corresponding comment prefix. + +- **Type**: `boolean` +- **Default**: `true` + ## `tinymist.onEnterEvent` Enable or disable [experimental/onEnter](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#on-enter) (LSP onEnter feature) to allow automatic insertion of characters on enter, such as `///` for comments. Note: restarting the editor is required to change this setting. @@ -121,6 +128,50 @@ Whether to handle drag-and-drop of resources into the editing typst document. No - `disable` - **Default**: `"enable"` +## `tinymist.renderDocs` + +(Experimental) Whether to render typst elements in (hover) docs. In VS Code, when this feature is enabled, tinymist will store rendered results in the filesystem's temporary storage to show them in the hover content. Note: Please disable this feature if the editor doesn't support/handle image previewing in docs. + +- **Type**: `string` +- **Enum**: + - `enable` + - `disable` +- **Default**: `"enable"` + +## `tinymist.completion.triggerOnSnippetPlaceholders` + +Whether to trigger completions on arguments (placeholders) of snippets. For example, `box` will be completed to `box(|)`, and server will request the editor (lsp client) to request completion after moving cursor to the placeholder in the snippet. Note: this has no effect if the editor doesn't support `editor.action.triggerSuggest` or `tinymist.triggerSuggestAndParameterHints` command. Hint: Restarting the editor is required to change this setting. + +- **Type**: `boolean` + +## `tinymist.completion.postfix` + +Whether to enable postfix code completion. For example, `[A].box|` will be completed to `box[A]|`. Hint: Restarting the editor is required to change this setting. + +- **Type**: `boolean` +- **Default**: `true` + +## `tinymist.completion.postfixUfcs` + +Whether to enable UFCS-style completion. For example, `[A].box|` will be completed to `box[A]|`. Hint: Restarting the editor is required to change this setting. + +- **Type**: `boolean` +- **Default**: `true` + +## `tinymist.completion.postfixUfcsLeft` + +Whether to enable left-variant UFCS-style completion. For example, `[A].table|` will be completed to `table(|)[A]`. Hint: Restarting the editor is required to change this setting. + +- **Type**: `boolean` +- **Default**: `true` + +## `tinymist.completion.postfixUfcsRight` + +Whether to enable right-variant UFCS-style completion. For example, `[A].table|` will be completed to `table([A], |)`. Hint: Restarting the editor is required to change this setting. + +- **Type**: `boolean` +- **Default**: `true` + ## `tinymist.previewFeature` Enable or disable preview features of Typst. Note: restarting the editor is required to change this setting. diff --git a/editors/vscode/package.json b/editors/vscode/package.json index f7671deb5..156338385 100644 --- a/editors/vscode/package.json +++ b/editors/vscode/package.json @@ -1,6 +1,6 @@ { "name": "tinymist", - "version": "0.12.0", + "version": "0.12.2", "description": "An integrated language service for Typst", "keywords": [ "typst", @@ -317,6 +317,12 @@ "Do not use semantic tokens for syntax highlighting" ] }, + "tinymist.typingContinueCommentsOnNewline": { + "title": "Continue Comments on Newline", + "markdownDescription": "Whether to prefix newlines after comments with the corresponding comment prefix.", + "type": "boolean", + "default": true + }, "tinymist.onEnterEvent": { "title": "Handling on enter events", "description": "Enable or disable [experimental/onEnter](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#on-enter) (LSP onEnter feature) to allow automatic insertion of characters on enter, such as `///` for comments. Note: restarting the editor is required to change this setting.", @@ -440,6 +446,36 @@ "disable" ] }, + "tinymist.completion.triggerOnSnippetPlaceholders": { + "title": "Trigger LSP Completion on Snippet Placeholders", + "markdownDescription": "Whether to trigger completions on arguments (placeholders) of snippets. For example, `box` will be completed to `box(|)`, and server will request the editor (lsp client) to request completion after moving cursor to the placeholder in the snippet. Note: this has no effect if the editor doesn't support `editor.action.triggerSuggest` or `tinymist.triggerSuggestAndParameterHints` command. Hint: Restarting the editor is required to change this setting.", + "type": "boolean", + "default": false + }, + "tinymist.completion.postfix": { + "title": "Enable Postfix Code Completion", + "markdownDescription": "Whether to enable postfix code completion. For example, `[A].box|` will be completed to `box[A]|`. Hint: Restarting the editor is required to change this setting.", + "type": "boolean", + "default": true + }, + "tinymist.completion.postfixUfcs": { + "title": "Completion: Convert Field Access to Call", + "markdownDescription": "Whether to enable UFCS-style completion. For example, `[A].box|` will be completed to `box[A]|`. Hint: Restarting the editor is required to change this setting.", + "type": "boolean", + "default": true + }, + "tinymist.completion.postfixUfcsLeft": { + "title": "Completion: Convert Field Access to Call (Left Variant)", + "markdownDescription": "Whether to enable left-variant UFCS-style completion. For example, `[A].table|` will be completed to `table(|)[A]`. Hint: Restarting the editor is required to change this setting.", + "type": "boolean", + "default": true + }, + "tinymist.completion.postfixUfcsRight": { + "title": "Completion: Convert Field Access to Call (Right Variant)", + "description": "Whether to enable right-variant UFCS-style completion. For example, `[A].table|` will be completed to `table([A], |)`. Hint: Restarting the editor is required to change this setting.", + "type": "boolean", + "default": true + }, "tinymist.previewFeature": { "title": "Enable preview features", "description": "Enable or disable preview features of Typst. Note: restarting the editor is required to change this setting.", diff --git a/editors/vscode/scripts/config-man.cjs b/editors/vscode/scripts/config-man.cjs index 37a4e7639..870982575 100644 --- a/editors/vscode/scripts/config-man.cjs +++ b/editors/vscode/scripts/config-man.cjs @@ -59,7 +59,8 @@ const serverSideKeys = (() => { } return strings.map((x) => `tinymist.${x}`); })(); -const isServerSideConfig = (key) => serverSideKeys.includes(key); +const isServerSideConfig = (key) => serverSideKeys.includes(key) || serverSideKeys + .some((serverSideKey) => key.startsWith(`${serverSideKey}.`)); const configMd = (editor, prefix) => Object.keys(config) .map((key) => { diff --git a/editors/vscode/src/extension.ts b/editors/vscode/src/extension.ts index 0996cf89c..ecd84d23b 100644 --- a/editors/vscode/src/extension.ts +++ b/editors/vscode/src/extension.ts @@ -70,14 +70,28 @@ export async function doActivate(context: ExtensionContext): Promise { const config = loadTinymistConfig(); // Inform server that we support named completion callback at the client side config.triggerSuggest = true; - config.triggerNamedCompletion = true; + config.triggerSuggestAndParameterHints = true; config.triggerParameterHints = true; + config.supportHtmlInMarkdown = true; // Sets features extensionState.features.preview = config.previewFeature === "enable"; extensionState.features.devKit = isDevMode || config.devKit === "enable"; extensionState.features.dragAndDrop = config.dragAndDrop === "enable"; extensionState.features.onEnter = !!config.onEnterEvent; extensionState.features.renderDocs = config.renderDocs === "enable"; + + // Configures advanced language configuration + tinymist.configureLanguage(config["typingContinueCommentsOnNewline"]); + context.subscriptions.push( + vscode.workspace.onDidChangeConfiguration((e) => { + if (e.affectsConfiguration("tinymist.typingContinueCommentsOnNewline")) { + const config = loadTinymistConfig(); + // Update language configuration + tinymist.configureLanguage(config["typingContinueCommentsOnNewline"]); + } + }), + ); + // Initializes language client const client = initClient(context, config); setClient(client); @@ -108,6 +122,7 @@ export async function doActivate(context: ExtensionContext): Promise { previewSetIsTinymist(); previewActivate(context, false); } + // Starts language client return await startClient(client, context); } @@ -322,7 +337,7 @@ async function startClient(client: LanguageClient, context: ExtensionContext): P // We would like to define it at the server side, but it is not possible for now. // https://github.com/microsoft/language-server-protocol/issues/1117 - commands.registerCommand("tinymist.triggerNamedCompletion", triggerNamedCompletion), + commands.registerCommand("tinymist.triggerSuggestAndParameterHints", triggerSuggestAndParameterHints), ); // context.subscriptions.push const provider = new SymbolViewProvider(context); @@ -485,6 +500,23 @@ async function commandShow(kind: "Pdf" | "Svg" | "Png", extraOpts?: any): Promis return; } + const conf = vscode.workspace.getConfiguration("tinymist"); + const openIn: string = conf.get("showExportFileIn") || "editorTab"; + + // Telling the language server to open the file instead of using + // ``` + // vscode.env.openExternal(exportUri); + // ``` + // , which is buggy. + // + // See https://github.com/Myriad-Dreamin/tinymist/issues/837 + // Also see https://github.com/microsoft/vscode/issues/85930 + const openBySystemDefault = openIn === "systemDefault"; + if (openBySystemDefault) { + extraOpts = extraOpts || {}; + extraOpts.open = true; + } + // only create pdf if it does not exist yet const exportPath = await commandExport(kind, extraOpts); @@ -494,37 +526,33 @@ async function commandShow(kind: "Pdf" | "Svg" | "Png", extraOpts?: any): Promis return; } - const exportUri = Uri.file(exportPath); - - // find and replace exportUri - // todo: we may find them in tabs - vscode.window.tabGroups; - - let uriToFind = exportUri.toString(); - findTab: for (const editor of vscode.window.tabGroups.all) { - for (const tab of editor.tabs) { - if ((tab.input as any)?.uri?.toString() === uriToFind) { - await vscode.window.tabGroups.close(tab, true); - break findTab; - } - } - } - - const conf = vscode.workspace.getConfiguration("tinymist"); - const openIn: string = conf.get("showExportFileIn", "editorTab"); - switch (openIn) { + case "systemDefault": + break; default: - case "editorTab": + vscode.window.showWarningMessage( + `Unknown value of "tinymist.showExportFileIn", expected "systemDefault" or "editorTab", got "${openIn}"`, + ); + case "editorTab": { + // find and replace exportUri + const exportUri = Uri.file(exportPath); + let uriToFind = exportUri.toString(); + findTab: for (const editor of vscode.window.tabGroups.all) { + for (const tab of editor.tabs) { + if ((tab.input as any)?.uri?.toString() === uriToFind) { + await vscode.window.tabGroups.close(tab, true); + break findTab; + } + } + } + // here we can be sure that the pdf exists await commands.executeCommand("vscode.open", exportUri, { viewColumn: ViewColumn.Beside, preserveFocus: true, } as vscode.TextDocumentShowOptions); break; - case "systemDefault": - await vscode.env.openExternal(exportUri); - break; + } } } @@ -823,7 +851,7 @@ async function commandRunCodeLens(...args: string[]): Promise { } } -function triggerNamedCompletion() { +function triggerSuggestAndParameterHints() { vscode.commands.executeCommand("editor.action.triggerSuggest"); vscode.commands.executeCommand("editor.action.triggerParameterHints"); } diff --git a/editors/vscode/src/features/package.ts b/editors/vscode/src/features/package.ts index f9cf1329b..6e9513f23 100644 --- a/editors/vscode/src/features/package.ts +++ b/editors/vscode/src/features/package.ts @@ -99,10 +99,8 @@ class PackageViewProvider implements vscode.TreeDataProvider { } async getPackageSymbols(element: SymbolsItem): Promise { - return createPackageSymbols( - element.pkg, - await tinymist.getResource("/package/symbol", element.pkg.pkg), - ); + const symbols = await tinymist.getResource("/package/symbol", element.pkg.pkg); + return createPackageSymbols(element.pkg, symbols.children); } private async getPackageActions(pkg: PackageItem): Promise { @@ -250,7 +248,7 @@ export class SymbolItem extends vscode.TreeItem { } function createPackageSymbols(pkgItem: PackageItem, bases: SymbolInfo[]): vscode.TreeItem[] { - const symbols = bases.map((info) => new SymbolItem(pkgItem, info)); + const symbols = (bases || []).map((info) => new SymbolItem(pkgItem, info)); symbols.sort((a, b) => { if (a.info.kind !== b.info.kind) { return a.info.kind.localeCompare(b.info.kind); diff --git a/editors/vscode/src/lsp.on-enter.ts b/editors/vscode/src/lsp.on-enter.ts index 3dacddc93..3bd2be796 100644 --- a/editors/vscode/src/lsp.on-enter.ts +++ b/editors/vscode/src/lsp.on-enter.ts @@ -5,9 +5,22 @@ import { applySnippetTextEdits } from "./snippets"; import { activeTypstEditor } from "./util"; import { extensionState } from "./state"; -const onEnter = new lc.RequestType( - "experimental/onEnter", -); +/** + * A parameter literal used in requests to pass a text document and a range inside that + * document. + */ +export interface OnEnterParams { + /** + * The text document. + */ + textDocument: lc.TextDocumentIdentifier; + /** + * The range inside the text document. + */ + range: lc.Range; +} + +const onEnter = new lc.RequestType("experimental/onEnter"); export async function onEnterHandler() { try { @@ -19,6 +32,8 @@ export async function onEnterHandler() { await vscode.commands.executeCommand("default:type", { text: "\n" }); } +// The code copied from https://github.com/rust-lang/rust-analyzer/blob/fc98e0657abf3ce07eed513e38274c89bbb2f8ad/editors/code/src/commands.ts#L199 +// doesn't work, so we change `onEnter` to pass the `range` instead of `position` to the server. async function handleKeypress() { if (!extensionState.features.onEnter) return false; @@ -29,7 +44,7 @@ async function handleKeypress() { const lcEdits = await client .sendRequest(onEnter, { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), - position: client.code2ProtocolConverter.asPosition(editor.selection.active), + range: client.code2ProtocolConverter.asRange(editor.selection), }) .catch((_error: any) => { // client.handleFailedRequest(OnEnterRequest.type, error, null); diff --git a/editors/vscode/src/lsp.ts b/editors/vscode/src/lsp.ts index dd78e6dd3..950f7e216 100644 --- a/editors/vscode/src/lsp.ts +++ b/editors/vscode/src/lsp.ts @@ -1,3 +1,4 @@ +import * as vscode from "vscode"; import { LanguageClient, SymbolInformation } from "vscode-languageclient/node"; import { spawnSync } from "child_process"; import { resolve } from "path"; @@ -36,7 +37,7 @@ interface ResourceRoutes { "/dir/package": string; "/dir/package/local": string; "/package/by-namespace": PackageInfo[]; - "/package/symbol": SymbolInfo[]; + "/package/symbol": SymbolInfo; "/package/docs": string; } @@ -71,6 +72,99 @@ export const tinymist = { client.outputChannel.show(); } }, + + /** + * The code is borrowed from https://github.com/rust-lang/rust-analyzer/blob/fc98e0657abf3ce07eed513e38274c89bbb2f8ad/editors/code/src/config.ts#L98 + * Last checked time: 2024-11-14 + * + * Sets up additional language configuration that's impossible to do via a + * separate language-configuration.json file. See [1] for more information. + * + * [1]: https://github.com/Microsoft/vscode/issues/11514#issuecomment-244707076 + */ + configureLang: undefined as vscode.Disposable | undefined, + configureLanguage(typingContinueCommentsOnNewline: boolean) { + // Only need to dispose of the config if there's a change + if (this.configureLang) { + this.configureLang.dispose(); + this.configureLang = undefined; + } + + let onEnterRules: vscode.OnEnterRule[] = [ + { + // Carry indentation from the previous line + // if it's only whitespace + beforeText: /^\s+$/, + action: { indentAction: vscode.IndentAction.None }, + }, + { + // After the end of a function/field chain, + // with the semicolon on the same line + beforeText: /^\s+\..*;/, + action: { indentAction: vscode.IndentAction.Outdent }, + }, + { + // After the end of a function/field chain, + // with semicolon detached from the rest + beforeText: /^\s+;/, + previousLineText: /^\s+\..*/, + action: { indentAction: vscode.IndentAction.Outdent }, + }, + ]; + + if (typingContinueCommentsOnNewline) { + const indentAction = vscode.IndentAction.None; + + onEnterRules = [ + ...onEnterRules, + { + // Doc single-line comment + // e.g. ///| + beforeText: /^\s*\/{3}.*$/, + action: { indentAction, appendText: "/// " }, + }, + { + // Parent doc single-line comment + // e.g. //!| + beforeText: /^\s*\/{2}\!.*$/, + action: { indentAction, appendText: "//! " }, + }, + { + // Begins an auto-closed multi-line comment (standard or parent doc) + // e.g. /** | */ or /*! | */ + beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/, + afterText: /^\s*\*\/$/, + action: { + indentAction: vscode.IndentAction.IndentOutdent, + appendText: " * ", + }, + }, + { + // Begins a multi-line comment (standard or parent doc) + // e.g. /** ...| or /*! ...| + beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/, + action: { indentAction, appendText: " * " }, + }, + { + // Continues a multi-line comment + // e.g. * ...| + beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/, + action: { indentAction, appendText: "* " }, + }, + { + // Dedents after closing a multi-line comment + // e.g. */| + beforeText: /^(\ \ )*\ \*\/\s*$/, + action: { indentAction, removeText: 1 }, + }, + ]; + } + + console.log("Setting up language configuration", typingContinueCommentsOnNewline); + this.configureLang = vscode.languages.setLanguageConfiguration("typst", { + onEnterRules, + }); + }, }; /// kill the probe task after 60s diff --git a/syntaxes/textmate/main.mts b/syntaxes/textmate/main.mts index 42b01fa3f..f2f89b9d0 100644 --- a/syntaxes/textmate/main.mts +++ b/syntaxes/textmate/main.mts @@ -75,10 +75,10 @@ const contentBlock: textmate.Pattern = { }, patterns: [ { - include: "#markup", + include: "#contentBlock", }, { - include: "#markupBrace", + include: "#markup", }, ], }; @@ -323,6 +323,9 @@ const markup: textmate.Pattern = { { include: "#markupReference", }, + { + include: "#markupBrace", + }, ], }; diff --git a/syntaxes/textmate/package.json b/syntaxes/textmate/package.json index b1ebf9044..b5a36edbd 100644 --- a/syntaxes/textmate/package.json +++ b/syntaxes/textmate/package.json @@ -1,6 +1,6 @@ { "name": "typst-textmate", - "version": "0.12.0", + "version": "0.12.2", "private": true, "scripts": { "compile": "npx tsc && node ./dist/main.mjs", diff --git a/syntaxes/textmate/tests/unit/basic/bracket.typ.snap b/syntaxes/textmate/tests/unit/basic/bracket.typ.snap index 05defae45..89474a8c7 100644 --- a/syntaxes/textmate/tests/unit/basic/bracket.typ.snap +++ b/syntaxes/textmate/tests/unit/basic/bracket.typ.snap @@ -29,7 +29,7 @@ #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst # ^ source.typst meta.expr.if.typst -# ^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst markup.content.brace.typst @@ -39,7 +39,7 @@ # ^ source.typst meta.expr.if.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst # ^ source.typst meta.expr.if.typst -# ^^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst markup.content.brace.typst @@ -55,7 +55,7 @@ #^ source.typst keyword.control.hash.typst # ^^^^^ source.typst meta.expr.while.typst keyword.control.loop.typst # ^ source.typst meta.expr.while.typst -# ^^^^^ source.typst meta.expr.while.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.while.typst constant.language.boolean.typst # ^ source.typst meta.expr.while.typst # ^ source.typst meta.expr.while.typst meta.brace.square.typst # ^ source.typst meta.expr.while.typst markup.content.brace.typst diff --git a/syntaxes/textmate/tests/unit/basic/call-ident.typ.snap b/syntaxes/textmate/tests/unit/basic/call-ident.typ.snap index df5ae1179..25919c988 100644 --- a/syntaxes/textmate/tests/unit/basic/call-ident.typ.snap +++ b/syntaxes/textmate/tests/unit/basic/call-ident.typ.snap @@ -47,27 +47,37 @@ # ^ source.typst meta.expr.call.typst entity.name.function.typst # ^ source.typst meta.expr.call.typst meta.brace.round.typst # ^ source.typst meta.expr.call.typst meta.brace.round.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#f() () #^ source.typst entity.name.function.hash.typst # ^ source.typst meta.expr.call.typst entity.name.function.typst # ^ source.typst meta.expr.call.typst meta.brace.round.typst # ^ source.typst meta.expr.call.typst meta.brace.round.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#f () #^ source.typst variable.other.readwrite.hash.typst # ^ source.typst variable.other.readwrite.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#f [] #^ source.typst variable.other.readwrite.hash.typst # ^ source.typst variable.other.readwrite.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#f[] [] #^ source.typst entity.name.function.hash.typst # ^ source.typst meta.expr.call.typst entity.name.function.typst # ^ source.typst meta.expr.call.typst meta.brace.square.typst # ^ source.typst meta.expr.call.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst > >#(f())() #^ source.typst keyword.control.hash.typst @@ -184,7 +194,9 @@ # ^ source.typst variable.other.readwrite.typst # ^ source.typst # ^ source.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#({ f }) () #^ source.typst keyword.control.hash.typst # ^ source.typst meta.brace.round.typst @@ -194,7 +206,9 @@ # ^ source.typst # ^ source.typst meta.brace.curly.typst # ^ source.typst meta.brace.round.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst > >#(list./*g*/item[]) #^ source.typst keyword.control.hash.typst diff --git a/syntaxes/textmate/tests/unit/basic/context.typ.snap b/syntaxes/textmate/tests/unit/basic/context.typ.snap index ddf57f3f6..965676f37 100644 --- a/syntaxes/textmate/tests/unit/basic/context.typ.snap +++ b/syntaxes/textmate/tests/unit/basic/context.typ.snap @@ -11,14 +11,16 @@ # ^ source.typst meta.expr.context.typst # ^ source.typst meta.expr.context.typst constant.numeric.integer.typst # ^ source.typst punctuation.terminator.statement.typst -# ^^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#context {}{} #^ source.typst keyword.control.hash.typst # ^^^^^^^ source.typst meta.expr.context.typst keyword.control.other.typst # ^ source.typst meta.expr.context.typst # ^ source.typst meta.expr.context.typst meta.brace.curly.typst # ^ source.typst meta.expr.context.typst meta.brace.curly.typst -# ^^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#context [][] #^ source.typst keyword.control.hash.typst # ^^^^^^^ source.typst meta.expr.context.typst keyword.control.other.typst @@ -43,7 +45,8 @@ # ^ source.typst meta.expr.context.typst meta.expr.call.typst meta.brace.round.typst >}{} #^ source.typst meta.expr.context.typst meta.brace.curly.typst -# ^^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#context [Citation @distress on page #here().page()]{} #^ source.typst keyword.control.hash.typst # ^^^^^^^ source.typst meta.expr.context.typst keyword.control.other.typst @@ -62,4 +65,5 @@ # ^ source.typst meta.expr.context.typst meta.expr.call.typst meta.brace.round.typst # ^ source.typst meta.expr.context.typst meta.expr.call.typst meta.brace.round.typst # ^ source.typst meta.expr.context.typst meta.brace.square.typst -# ^^^ source.typst \ No newline at end of file +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst \ No newline at end of file diff --git a/syntaxes/textmate/tests/unit/basic/control-flow-for-content.typ.snap b/syntaxes/textmate/tests/unit/basic/control-flow-for-content.typ.snap index c09e525a6..bffc2f2b7 100644 --- a/syntaxes/textmate/tests/unit/basic/control-flow-for-content.typ.snap +++ b/syntaxes/textmate/tests/unit/basic/control-flow-for-content.typ.snap @@ -171,7 +171,9 @@ # ^ source.typst meta.expr.for.typst meta.brace.square.typst # ^ source.typst meta.expr.for.typst meta.brace.square.typst # ^ source.typst punctuation.terminator.statement.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#for i in range(1) [] [] #^ source.typst keyword.control.hash.typst # ^^^ source.typst meta.expr.for.typst keyword.control.loop.typst @@ -187,6 +189,8 @@ # ^ source.typst meta.expr.for.typst # ^ source.typst meta.expr.for.typst meta.brace.square.typst # ^ source.typst meta.expr.for.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >1 #^^ source.typst \ No newline at end of file diff --git a/syntaxes/textmate/tests/unit/basic/control-flow-for.typ.snap b/syntaxes/textmate/tests/unit/basic/control-flow-for.typ.snap index 9a2247c7a..321f46c53 100644 --- a/syntaxes/textmate/tests/unit/basic/control-flow-for.typ.snap +++ b/syntaxes/textmate/tests/unit/basic/control-flow-for.typ.snap @@ -171,7 +171,9 @@ # ^ source.typst meta.expr.for.typst meta.brace.curly.typst # ^ source.typst meta.expr.for.typst meta.brace.curly.typst # ^ source.typst punctuation.terminator.statement.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#for i in range(1) {} {} #^ source.typst keyword.control.hash.typst # ^^^ source.typst meta.expr.for.typst keyword.control.loop.typst @@ -187,6 +189,8 @@ # ^ source.typst meta.expr.for.typst # ^ source.typst meta.expr.for.typst meta.brace.curly.typst # ^ source.typst meta.expr.for.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >1 #^^ source.typst \ No newline at end of file diff --git a/syntaxes/textmate/tests/unit/basic/control-flow-if-content.typ.snap b/syntaxes/textmate/tests/unit/basic/control-flow-if-content.typ.snap index d6fb7673f..3e7f66ead 100644 --- a/syntaxes/textmate/tests/unit/basic/control-flow-if-content.typ.snap +++ b/syntaxes/textmate/tests/unit/basic/control-flow-if-content.typ.snap @@ -68,7 +68,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if () [] else [] # a #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -120,7 +122,8 @@ # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst >[] -#^^^ source.typst +#^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst > >#if () [] else [] #^ source.typst keyword.control.hash.typst @@ -137,7 +140,7 @@ # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst >{ -#^^ source.typst +#^ source.typst markup.content.brace.typst >#if () [] else [] #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -159,7 +162,15 @@ ># if () [] else [] #^ source.typst punctuation.definition.hash.typst # ^ source.typst -# ^^^^^^^^^^^^^^^^^ source.typst +# ^^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +# ^^^^^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >1 #^^ source.typst > @@ -168,7 +179,7 @@ # ^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst # ^ source.typst meta.expr.if.typst -# ^^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst diff --git a/syntaxes/textmate/tests/unit/basic/control-flow-if.typ.snap b/syntaxes/textmate/tests/unit/basic/control-flow-if.typ.snap index 6b3fde63b..9c09bde2b 100644 --- a/syntaxes/textmate/tests/unit/basic/control-flow-if.typ.snap +++ b/syntaxes/textmate/tests/unit/basic/control-flow-if.typ.snap @@ -68,7 +68,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if () {} else {} # a #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -120,7 +122,8 @@ # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst >{} -#^^^ source.typst +#^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst > >#if () {} else {} #^ source.typst keyword.control.hash.typst @@ -137,7 +140,7 @@ # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst >{ -#^^ source.typst +#^ source.typst markup.content.brace.typst >#if () {} else {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -159,7 +162,15 @@ ># if () {} else {} #^ source.typst punctuation.definition.hash.typst # ^ source.typst -# ^^^^^^^^^^^^^^^^^ source.typst +# ^^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +# ^^^^^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >1 #^^ source.typst > @@ -183,11 +194,11 @@ #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst # ^ source.typst meta.expr.if.typst -# ^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^^ source.typst meta.expr.if.typst keyword.operator.relational.typst # ^ source.typst meta.expr.if.typst -# ^^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst > {Bad}, but we {dont-care}! @@ -208,7 +219,7 @@ # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst @@ -226,7 +237,7 @@ # ^ source.typst meta.expr.if.typst # ^^ source.typst meta.expr.if.typst keyword.operator.relational.typst # ^ source.typst meta.expr.if.typst -# ^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.if.typst keyword.other.none.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst > Two. @@ -275,7 +286,7 @@ #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst # ^ source.typst meta.expr.if.typst -# ^^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst > Bad. @@ -376,7 +387,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if () {} {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -386,7 +399,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if [] () {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -408,7 +423,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if [] {} {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -418,7 +435,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if {} () {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -440,7 +459,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if {} {} {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -450,7 +471,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst > >#if () == () () {} #^ source.typst keyword.control.hash.typst @@ -483,7 +506,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if () == () {} {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -498,7 +523,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if [] == [] () {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -530,7 +557,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if [] == [] {} {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -545,7 +574,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if {} == {} () {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -577,7 +608,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if {} == {} {} {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -592,7 +625,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst > >#if () and () () {} #^ source.typst keyword.control.hash.typst @@ -625,7 +660,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if () and () {} {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -640,7 +677,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if [] and [] () {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -672,7 +711,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if [] and [] {} {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -687,7 +728,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if {} and {} () {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -719,7 +762,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if {} and {} {} {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -734,7 +779,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst > >#if not () () {} #^ source.typst keyword.control.hash.typst @@ -761,7 +808,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if not () {} {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -773,7 +822,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if not [] () {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -799,7 +850,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if not [] {} {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -811,7 +864,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if not {} () {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -837,7 +892,9 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst # ^ source.typst meta.expr.if.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#if not {} {} {} #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst @@ -849,5 +906,7 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst > \ No newline at end of file diff --git a/syntaxes/textmate/tests/unit/basic/control-flow-while.typ.snap b/syntaxes/textmate/tests/unit/basic/control-flow-while.typ.snap index 89a968f14..a019a229d 100644 --- a/syntaxes/textmate/tests/unit/basic/control-flow-while.typ.snap +++ b/syntaxes/textmate/tests/unit/basic/control-flow-while.typ.snap @@ -86,7 +86,9 @@ # ^ source.typst meta.expr.while.typst # ^ source.typst meta.expr.while.typst meta.brace.curly.typst # ^ source.typst meta.expr.while.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#while i [] [] #^ source.typst keyword.control.hash.typst # ^^^^^ source.typst meta.expr.while.typst keyword.control.loop.typst @@ -95,7 +97,9 @@ # ^ source.typst meta.expr.while.typst # ^ source.typst meta.expr.while.typst meta.brace.square.typst # ^ source.typst meta.expr.while.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#while i [] {} #^ source.typst keyword.control.hash.typst # ^^^^^ source.typst meta.expr.while.typst keyword.control.loop.typst @@ -104,7 +108,9 @@ # ^ source.typst meta.expr.while.typst # ^ source.typst meta.expr.while.typst meta.brace.square.typst # ^ source.typst meta.expr.while.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst > >#while i {} #^ source.typst keyword.control.hash.typst diff --git a/syntaxes/textmate/tests/unit/basic/let_fn.typ.snap b/syntaxes/textmate/tests/unit/basic/let_fn.typ.snap index 962302fef..57fd13669 100644 --- a/syntaxes/textmate/tests/unit/basic/let_fn.typ.snap +++ b/syntaxes/textmate/tests/unit/basic/let_fn.typ.snap @@ -33,7 +33,7 @@ # ^ source.typst meta.expr.let.typst variable.other.readwrite.typst # ^ source.typst meta.expr.let.typst punctuation.separator.colon.typst # ^ source.typst meta.expr.let.typst -# ^^^^ source.typst meta.expr.let.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.let.typst keyword.other.none.typst # ^ source.typst meta.expr.let.typst meta.brace.round.typst # ^ source.typst meta.expr.let.typst # ^^ source.typst meta.expr.let.typst keyword.operator.assignment.typst diff --git a/syntaxes/textmate/tests/unit/basic/set.typ.snap b/syntaxes/textmate/tests/unit/basic/set.typ.snap index 4a05198e3..31195d90c 100644 --- a/syntaxes/textmate/tests/unit/basic/set.typ.snap +++ b/syntaxes/textmate/tests/unit/basic/set.typ.snap @@ -66,11 +66,27 @@ >#set (text(fill: red)); #^ source.typst keyword.control.hash.typst # ^^^ source.typst variable.other.readwrite.typst -# ^^^^^^^^^^^^^^^^^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^^^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^^^^^^^^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +# ^^ source.typst >#set ((text(fill: red))); #^ source.typst keyword.control.hash.typst # ^^^ source.typst variable.other.readwrite.typst -# ^^^^^^^^^^^^^^^^^^^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +# ^^^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^^^^^^^^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +# ^^ source.typst >#set text("") if {} #^ source.typst keyword.control.hash.typst # ^^^ source.typst meta.expr.set.typst keyword.control.other.typst @@ -127,7 +143,8 @@ # ^ source.typst meta.expr.set.typst # ^ source.typst meta.expr.set.typst meta.brace.curly.typst # ^ source.typst meta.expr.set.typst meta.brace.curly.typst -# ^^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#set text("") if [][] #^ source.typst keyword.control.hash.typst # ^^^ source.typst meta.expr.set.typst keyword.control.other.typst @@ -174,7 +191,9 @@ # ^ source.typst meta.expr.set.typst # ^ source.typst meta.expr.set.typst meta.brace.curly.typst # ^ source.typst meta.expr.set.typst meta.brace.curly.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#set text("") if [] [] #^ source.typst keyword.control.hash.typst # ^^^ source.typst meta.expr.set.typst keyword.control.other.typst @@ -189,7 +208,9 @@ # ^ source.typst meta.expr.set.typst # ^ source.typst meta.expr.set.typst meta.brace.square.typst # ^ source.typst meta.expr.set.typst meta.brace.square.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#set text("") if () () #^ source.typst keyword.control.hash.typst # ^^^ source.typst meta.expr.set.typst keyword.control.other.typst @@ -204,7 +225,9 @@ # ^ source.typst meta.expr.set.typst # ^ source.typst meta.expr.set.typst meta.brace.round.typst # ^ source.typst meta.expr.set.typst meta.brace.round.typst -# ^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst >#set text("") if {}; #^ source.typst keyword.control.hash.typst # ^^^ source.typst meta.expr.set.typst keyword.control.other.typst @@ -250,4 +273,6 @@ # ^ source.typst meta.expr.set.typst meta.brace.round.typst # ^ source.typst meta.expr.set.typst meta.brace.round.typst # ^ source.typst punctuation.terminator.statement.typst -# ^^^^ source.typst \ No newline at end of file +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst \ No newline at end of file diff --git a/syntaxes/textmate/tests/unit/basic/show.typ.snap b/syntaxes/textmate/tests/unit/basic/show.typ.snap index ab6a801ca..74716b98d 100644 --- a/syntaxes/textmate/tests/unit/basic/show.typ.snap +++ b/syntaxes/textmate/tests/unit/basic/show.typ.snap @@ -100,7 +100,7 @@ # ^^^^^ source.typst meta.expr.show.typst meta.expr.call.typst variable.other.readwrite.typst # ^ source.typst meta.expr.show.typst meta.expr.call.typst punctuation.separator.colon.typst # ^ source.typst meta.expr.show.typst meta.expr.call.typst -# ^^^^ source.typst meta.expr.show.typst meta.expr.call.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.show.typst meta.expr.call.typst constant.language.boolean.typst # ^ source.typst meta.expr.show.typst meta.expr.call.typst meta.brace.round.typst # ^ source.typst meta.expr.show.typst punctuation.separator.colon.typst # ^ source.typst meta.expr.show.typst diff --git a/syntaxes/textmate/tests/unit/basic/space-control-flow.typ.snap b/syntaxes/textmate/tests/unit/basic/space-control-flow.typ.snap index ba627674a..407610220 100644 --- a/syntaxes/textmate/tests/unit/basic/space-control-flow.typ.snap +++ b/syntaxes/textmate/tests/unit/basic/space-control-flow.typ.snap @@ -28,7 +28,10 @@ # ^ source.typst meta.expr.for.typst variable.other.readwrite.typst # ^ source.typst meta.expr.for.typst # ^ source.typst meta.expr.for.typst meta.brace.curly.typst -# ^^^^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^^^ source.typst +# ^ source.typst markup.content.brace.typst >#for i in { range(0, 10) } { A } { A } #^ source.typst keyword.control.hash.typst # ^^^ source.typst meta.expr.for.typst keyword.control.loop.typst @@ -54,14 +57,17 @@ # ^ source.typst meta.expr.for.typst variable.other.readwrite.typst # ^ source.typst meta.expr.for.typst # ^ source.typst meta.expr.for.typst meta.brace.curly.typst -# ^^^^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^^^ source.typst +# ^ source.typst markup.content.brace.typst >#if { true } { A } { A } #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst -# ^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst @@ -70,7 +76,10 @@ # ^ source.typst meta.expr.if.typst variable.other.readwrite.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^^^ source.typst +# ^ source.typst markup.content.brace.typst > >#for i in range(0, 10){A}{A} #^ source.typst keyword.control.hash.typst @@ -122,7 +131,7 @@ #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst variable.other.readwrite.typst @@ -185,7 +194,7 @@ # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst -# ^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst @@ -242,7 +251,7 @@ #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst -# ^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst variable.other.readwrite.typst diff --git a/syntaxes/textmate/tests/unit/bugs/hover.typ.snap b/syntaxes/textmate/tests/unit/bugs/hover.typ.snap index ebdfaf40c..82910902b 100644 --- a/syntaxes/textmate/tests/unit/bugs/hover.typ.snap +++ b/syntaxes/textmate/tests/unit/bugs/hover.typ.snap @@ -16,7 +16,7 @@ # ^^^ source.typst meta.expr.let.typst variable.other.readwrite.typst # ^ source.typst meta.expr.let.typst punctuation.separator.colon.typst # ^ source.typst meta.expr.let.typst -# ^^^^ source.typst meta.expr.let.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.let.typst keyword.other.none.typst # ^ source.typst meta.expr.let.typst punctuation.separator.comma.typst # ^ source.typst meta.expr.let.typst # ^^^^^ source.typst meta.expr.let.typst variable.other.readwrite.typst diff --git a/syntaxes/textmate/tests/unit/bugs/link.typ.snap b/syntaxes/textmate/tests/unit/bugs/link.typ.snap index 0c7c0d815..03d87f6ee 100644 --- a/syntaxes/textmate/tests/unit/bugs/link.typ.snap +++ b/syntaxes/textmate/tests/unit/bugs/link.typ.snap @@ -1,8 +1,17 @@ >("https://github.com/Myriad-Dreamin/tinymist/tree/main/editors/vscode#symbol-view")[integrating] -#^^ source.typst +#^ source.typst markup.content.brace.typst +# ^ source.typst # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ source.typst markup.underline.link.typst -# ^^^^^^^^^^^^^^^^ source.typst +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +# ^^^^^^^^^^^ source.typst +# ^ source.typst markup.content.brace.typst >("https://github.com/istudyatuni/sublimelsp-LSP/blob/40ea8ea01af19b8719b0e2e827dbfb8651261199/docs/src/language_servers.md#tinymist")[] -#^^ source.typst +#^ source.typst markup.content.brace.typst +# ^ source.typst # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ source.typst markup.underline.link.typst -# ^^^^^ source.typst \ No newline at end of file +# ^ source.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst \ No newline at end of file diff --git a/syntaxes/textmate/tests/unit/bugs/tinymist-issue853.typ b/syntaxes/textmate/tests/unit/bugs/tinymist-issue853.typ new file mode 100644 index 000000000..f4eeedb48 --- /dev/null +++ b/syntaxes/textmate/tests/unit/bugs/tinymist-issue853.typ @@ -0,0 +1,7 @@ +[] + +[[[[] + +#text(red)[\[]] + +#text(red)[[]] \ No newline at end of file diff --git a/syntaxes/textmate/tests/unit/bugs/tinymist-issue853.typ.snap b/syntaxes/textmate/tests/unit/bugs/tinymist-issue853.typ.snap new file mode 100644 index 000000000..e37e59032 --- /dev/null +++ b/syntaxes/textmate/tests/unit/bugs/tinymist-issue853.typ.snap @@ -0,0 +1,32 @@ +>[] +#^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +> +>[[[[] +#^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +# ^ source.typst markup.content.brace.typst +> +>#text(red)[\[]] +#^ source.typst entity.name.function.hash.typst +# ^^^^ source.typst meta.expr.call.typst entity.name.function.typst +# ^ source.typst meta.expr.call.typst meta.brace.round.typst +# ^^^ source.typst meta.expr.call.typst support.type.builtin.typst +# ^ source.typst meta.expr.call.typst meta.brace.round.typst +# ^ source.typst meta.expr.call.typst meta.brace.square.typst +# ^^ source.typst meta.expr.call.typst constant.character.escape.content.typst +# ^ source.typst meta.expr.call.typst meta.brace.square.typst +# ^ source.typst markup.content.brace.typst +> +>#text(red)[[]] +#^ source.typst entity.name.function.hash.typst +# ^^^^ source.typst meta.expr.call.typst entity.name.function.typst +# ^ source.typst meta.expr.call.typst meta.brace.round.typst +# ^^^ source.typst meta.expr.call.typst support.type.builtin.typst +# ^ source.typst meta.expr.call.typst meta.brace.round.typst +# ^ source.typst meta.expr.call.typst meta.brace.square.typst +# ^ source.typst meta.expr.call.typst meta.brace.square.typst +# ^ source.typst meta.expr.call.typst meta.brace.square.typst +# ^ source.typst meta.expr.call.typst meta.brace.square.typst \ No newline at end of file diff --git a/syntaxes/textmate/tests/unit/expr/cond.typ.snap b/syntaxes/textmate/tests/unit/expr/cond.typ.snap index 16ff2ad8a..22f12da10 100644 --- a/syntaxes/textmate/tests/unit/expr/cond.typ.snap +++ b/syntaxes/textmate/tests/unit/expr/cond.typ.snap @@ -2,11 +2,11 @@ #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst # ^ source.typst meta.expr.if.typst -# ^^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^^^ source.typst meta.expr.if.typst keyword.other.logical.typst # ^ source.typst meta.expr.if.typst -# ^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst @@ -16,7 +16,7 @@ # ^ source.typst meta.expr.if.typst # ^^^ source.typst meta.expr.if.typst keyword.other.logical.typst # ^ source.typst meta.expr.if.typst -# ^^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst @@ -40,11 +40,11 @@ #^ source.typst keyword.control.hash.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst # ^ source.typst meta.expr.if.typst -# ^^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^^^ source.typst meta.expr.if.typst keyword.other.logical.typst # ^ source.typst meta.expr.if.typst -# ^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst @@ -53,11 +53,11 @@ # ^ source.typst meta.expr.if.typst # ^^ source.typst meta.expr.if.typst keyword.control.conditional.typst # ^ source.typst meta.expr.if.typst -# ^^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^^^ source.typst meta.expr.if.typst keyword.other.logical.typst # ^ source.typst meta.expr.if.typst -# ^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst @@ -67,7 +67,7 @@ # ^ source.typst meta.expr.if.typst # ^^^ source.typst meta.expr.if.typst keyword.other.logical.typst # ^ source.typst meta.expr.if.typst -# ^^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst @@ -78,7 +78,7 @@ # ^ source.typst meta.expr.if.typst # ^^^ source.typst meta.expr.if.typst keyword.other.logical.typst # ^ source.typst meta.expr.if.typst -# ^^^^ source.typst meta.expr.if.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.if.typst constant.language.boolean.typst # ^ source.typst meta.expr.if.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst # ^ source.typst meta.expr.if.typst meta.brace.curly.typst @@ -119,11 +119,11 @@ #^ source.typst keyword.control.hash.typst # ^^^^^ source.typst meta.expr.while.typst keyword.control.loop.typst # ^ source.typst meta.expr.while.typst -# ^^^^^ source.typst meta.expr.while.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.while.typst constant.language.boolean.typst # ^ source.typst meta.expr.while.typst # ^^^ source.typst meta.expr.while.typst keyword.other.logical.typst # ^ source.typst meta.expr.while.typst -# ^^^^ source.typst meta.expr.while.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.while.typst constant.language.boolean.typst # ^ source.typst meta.expr.while.typst # ^ source.typst meta.expr.while.typst meta.brace.curly.typst # ^ source.typst meta.expr.while.typst meta.brace.curly.typst @@ -155,11 +155,11 @@ # ^ source.typst meta.expr.set.typst # ^^ source.typst meta.expr.set.typst keyword.control.conditional.typst # ^ source.typst meta.expr.set.typst -# ^^^^^ source.typst meta.expr.set.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.set.typst constant.language.boolean.typst # ^^^ source.typst meta.expr.set.typst # ^^^ source.typst meta.expr.set.typst keyword.other.logical.typst # ^^^^ source.typst meta.expr.set.typst -# ^^^^ source.typst meta.expr.set.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.set.typst constant.language.boolean.typst >#set text(red) if not true #^ source.typst keyword.control.hash.typst # ^^^ source.typst meta.expr.set.typst keyword.control.other.typst @@ -173,5 +173,5 @@ # ^^^ source.typst meta.expr.set.typst # ^^^ source.typst meta.expr.set.typst keyword.other.logical.typst # ^^^^^^^^^^ source.typst meta.expr.set.typst -# ^^^^ source.typst meta.expr.set.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.set.typst constant.language.boolean.typst > \ No newline at end of file diff --git a/syntaxes/textmate/tests/unit/expr/in_block.typ.snap b/syntaxes/textmate/tests/unit/expr/in_block.typ.snap index 166d35346..8037ec0b8 100644 --- a/syntaxes/textmate/tests/unit/expr/in_block.typ.snap +++ b/syntaxes/textmate/tests/unit/expr/in_block.typ.snap @@ -3,11 +3,11 @@ # ^ source.typst meta.brace.curly.typst > false and true; #^^ source.typst -# ^^^^^ source.typst entity.name.type.primitive.typst +# ^^^^^ source.typst constant.language.boolean.typst # ^^^^^^^^^^^^^^^^^^^ source.typst # ^^^ source.typst keyword.other.logical.typst # ^^^^^^^^^^^ source.typst -# ^^^^ source.typst entity.name.type.primitive.typst +# ^^^^ source.typst constant.language.boolean.typst # ^ source.typst punctuation.separator.colon.typst > > if 1 + 2 == 3 { @@ -39,7 +39,7 @@ #^^ source.typst # ^^^^^ source.typst meta.expr.while.typst keyword.control.loop.typst # ^ source.typst meta.expr.while.typst -# ^^^^^ source.typst meta.expr.while.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.while.typst constant.language.boolean.typst # ^^ source.typst meta.expr.while.typst # ^^ source.typst meta.expr.while.typst keyword.operator.relational.typst # ^ source.typst meta.expr.while.typst @@ -65,11 +65,11 @@ # ^^^^^^^^^^^^^^^^^ source.typst meta.expr.set.typst # ^^ source.typst meta.expr.set.typst keyword.control.conditional.typst # ^^^^^^^^^^ source.typst meta.expr.set.typst -# ^^^^^ source.typst meta.expr.set.typst entity.name.type.primitive.typst +# ^^^^^ source.typst meta.expr.set.typst constant.language.boolean.typst > and true #^^ source.typst # ^^^ source.typst keyword.other.logical.typst # ^ source.typst -# ^^^^ source.typst entity.name.type.primitive.typst +# ^^^^ source.typst constant.language.boolean.typst >} #^ source.typst meta.brace.curly.typst \ No newline at end of file diff --git a/syntaxes/textmate/tests/unit/expr/nary.typ.snap b/syntaxes/textmate/tests/unit/expr/nary.typ.snap index 7d774eb7d..4785486fd 100644 --- a/syntaxes/textmate/tests/unit/expr/nary.typ.snap +++ b/syntaxes/textmate/tests/unit/expr/nary.typ.snap @@ -5,7 +5,7 @@ # ^ source.typst meta.expr.let.typst variable.other.readwrite.typst # ^ source.typst meta.expr.let.typst # ^^ source.typst meta.expr.let.typst keyword.operator.assignment.typst -# ^^^^ source.typst meta.expr.let.typst entity.name.type.primitive.typst +# ^^^^ source.typst meta.expr.let.typst keyword.other.none.typst # ^ source.typst punctuation.terminator.statement.typst >#red = red #^ source.typst variable.other.readwrite.hash.typst diff --git a/syntaxes/textmate/tests/unit/markup/broken-bold2.typ.snap b/syntaxes/textmate/tests/unit/markup/broken-bold2.typ.snap index b9bc4f52a..bf7094341 100644 --- a/syntaxes/textmate/tests/unit/markup/broken-bold2.typ.snap +++ b/syntaxes/textmate/tests/unit/markup/broken-bold2.typ.snap @@ -1,5 +1,9 @@ >a [*a] b -#^^^^^^^^^ source.typst +#^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^^ source.typst +# ^ source.typst markup.content.brace.typst +# ^^^ source.typst > >b #^^ source.typst diff --git a/syntaxes/textmate/tests/unit/markup/escape.typ.snap b/syntaxes/textmate/tests/unit/markup/escape.typ.snap index aff760dcf..ed6cff6ff 100644 --- a/syntaxes/textmate/tests/unit/markup/escape.typ.snap +++ b/syntaxes/textmate/tests/unit/markup/escape.typ.snap @@ -1,7 +1,7 @@ >[\]] -#^ source.typst +#^ source.typst markup.content.brace.typst # ^^ source.typst constant.character.escape.content.typst -# ^^ source.typst +# ^ source.typst markup.content.brace.typst >\#1pt #^^ source.typst constant.character.escape.content.typst # ^^^^ source.typst diff --git a/tests/e2e/main.rs b/tests/e2e/main.rs index 29b38f3fc..8ed6fa2cc 100644 --- a/tests/e2e/main.rs +++ b/tests/e2e/main.rs @@ -374,7 +374,7 @@ fn e2e() { }); let hash = replay_log(&tinymist_binary, &root.join("neovim")); - insta::assert_snapshot!(hash, @"siphash128_13:bafb35d07c168f6630fc455df6ba0a3"); + insta::assert_snapshot!(hash, @"siphash128_13:6b94fdf913e670825d2b4daf6ef8c7f5"); } { @@ -385,7 +385,7 @@ fn e2e() { }); let hash = replay_log(&tinymist_binary, &root.join("vscode")); - insta::assert_snapshot!(hash, @"siphash128_13:ca76d8fc2bce9988ae2d2ed33b9bb21"); + insta::assert_snapshot!(hash, @"siphash128_13:afe8f09344dbbd1ff501368282065404"); } } diff --git a/tests/fixtures/initialization/vscode-1.87.2.json b/tests/fixtures/initialization/vscode-1.87.2.json index 90eb500f1..b73971f59 100644 --- a/tests/fixtures/initialization/vscode-1.87.2.json +++ b/tests/fixtures/initialization/vscode-1.87.2.json @@ -274,7 +274,8 @@ "trace": { "server": "off" }, "triggerSuggest": true, "triggerParameterHints": true, - "triggerNamedCompletion": true, + "triggerSuggestAndParameterHints": true, + "supportHtmlInMarkdown": true, "experimentalFormatterMode": "disable" }, "trace": "off" diff --git a/tools/editor-tools/src/features/docs.ts b/tools/editor-tools/src/features/docs.ts index cebdf4082..597d4d0a2 100644 --- a/tools/editor-tools/src/features/docs.ts +++ b/tools/editor-tools/src/features/docs.ts @@ -38,7 +38,7 @@ export const Docs = () => { }, (_dom?: Element) => { const v = parsedDocs.val; - console.log("updated", v); + // console.log("updated", v); return div(MakeDoc(v)); } ) @@ -213,7 +213,7 @@ async function recoverDocsStructure(content: string) { current = structStack.pop()!; break; case TokenKind.Comment: - console.log("Comment", token[1]); + // console.log("Comment", token[1]); break; case TokenKind.Text: current.contents.push(token[1]); @@ -298,7 +298,7 @@ function MakeDoc(root: DocElement) { // module-symbol-module-src.lib-barchart getKnownPackages(root); processInternalModules(root); - console.log("MakeDoc", root, knownFiles, knownPackages); + // console.log("MakeDoc", root, knownFiles, knownPackages); function getKnownPackages(v: DocElement) { for (const child of v.children) { @@ -391,7 +391,7 @@ function MakeDoc(root: DocElement) { } function ShortItemDoc(v: DocElement): ChildDom[] { - console.log("item ref to ", v); + // console.log("item ref to ", v); return [ItemDoc(v)]; } @@ -484,7 +484,7 @@ function MakeDoc(root: DocElement) { const fileLoc = v.data.loc; const fid = genFileId(knownFiles[fileLoc]); const isInternal = knownFiles[fileLoc]?.isInternal; - console.log("ModuleItem", v, fid); + // console.log("ModuleItem", v, fid); const title = []; if (isInternal) { @@ -510,7 +510,7 @@ function MakeDoc(root: DocElement) { } function PackageItem(v: DocElement) { - console.log("PackageItem", v); + // console.log("PackageItem", v); return div( h1(`@${v.data.namespace}/${v.data.name}:${v.data.version}`), p( diff --git a/tools/typst-dom/package.json b/tools/typst-dom/package.json index b8c42378b..45c544f41 100644 --- a/tools/typst-dom/package.json +++ b/tools/typst-dom/package.json @@ -13,12 +13,12 @@ "unlink:local": "yarn unlink @myriaddreamin/typst.ts @myriaddreamin/typst-ts-renderer" }, "peerDependencies": { - "@myriaddreamin/typst-ts-renderer": "0.5.0-rc8", - "@myriaddreamin/typst.ts": "0.5.0-rc8" + "@myriaddreamin/typst-ts-renderer": "0.5.0-rc9", + "@myriaddreamin/typst.ts": "0.5.0-rc9" }, "devDependencies": { - "@myriaddreamin/typst-ts-renderer": "0.5.0-rc8", - "@myriaddreamin/typst.ts": "0.5.0-rc8", + "@myriaddreamin/typst-ts-renderer": "0.5.0-rc9", + "@myriaddreamin/typst.ts": "0.5.0-rc9", "typescript": "^5.0.2" }, "exports": { diff --git a/tools/typst-preview-frontend/package.json b/tools/typst-preview-frontend/package.json index d106574e5..675ceba39 100644 --- a/tools/typst-preview-frontend/package.json +++ b/tools/typst-preview-frontend/package.json @@ -13,8 +13,8 @@ "unlink:local": "yarn unlink @myriaddreamin/typst.ts @myriaddreamin/typst-ts-renderer" }, "dependencies": { - "@myriaddreamin/typst-ts-renderer": "0.5.0-rc8", - "@myriaddreamin/typst.ts": "0.5.0-rc8", + "@myriaddreamin/typst-ts-renderer": "0.5.0-rc9", + "@myriaddreamin/typst.ts": "0.5.0-rc9", "typst-dom": "link:../typst-dom", "rxjs": "^7.8.1" } diff --git a/yarn.lock b/yarn.lock index f69c84dfa..c4751c157 100644 --- a/yarn.lock +++ b/yarn.lock @@ -408,15 +408,15 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== -"@myriaddreamin/typst-ts-renderer@0.5.0-rc8": - version "0.5.0-rc8" - resolved "https://registry.yarnpkg.com/@myriaddreamin/typst-ts-renderer/-/typst-ts-renderer-0.5.0-rc8.tgz#ba164f957a1f80843793efd0b09764655180268c" - integrity sha512-Ct7Sx0axOXt5rvOGrqcOQv4d+M0gWrgVIx766THzkKigru3oaogBRCCCrtsKSS+Ckp836LRvTEmzcwmJFwZtjw== +"@myriaddreamin/typst-ts-renderer@0.5.0-rc9": + version "0.5.0-rc9" + resolved "https://registry.yarnpkg.com/@myriaddreamin/typst-ts-renderer/-/typst-ts-renderer-0.5.0-rc9.tgz#c6ed3ce01c7ce61a83b396bdd39c412b56dedcd8" + integrity sha512-YyKvGcTmCpzzv+M54vQA8zaDfMM/PqsQrThDi9DG1D5FOKt50w8+xE5POEFPfDu5y9iVyvJ/AhkRqGyy4njkcQ== -"@myriaddreamin/typst.ts@0.5.0-rc8": - version "0.5.0-rc8" - resolved "https://registry.yarnpkg.com/@myriaddreamin/typst.ts/-/typst.ts-0.5.0-rc8.tgz#aec112f6bb33c766ebdb182dcb8cfa5bec2653cf" - integrity sha512-am/z6SAa+dnex9zmdqK1uOyBdAT6xMpGVoh2vuvnzM3XoqhnyGRtphTdJqo/yCcdjG4/P3nzS2M9TlfSIAi3pw== +"@myriaddreamin/typst.ts@0.5.0-rc9": + version "0.5.0-rc9" + resolved "https://registry.yarnpkg.com/@myriaddreamin/typst.ts/-/typst.ts-0.5.0-rc9.tgz#0d9c4c61406b0245105544d821dae5a0a88a39fc" + integrity sha512-6mnxNzuEp4ALFwzuvvCTijM756G1VUnXie9TwjCb01ey3f6jv/Xh1rWNwLds2KUYAtDdaOqO7RMctOhvqdq0rg== dependencies: idb "^7.1.1" @@ -3768,6 +3768,7 @@ stoppable@^1.1.0: integrity sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw== "string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0: + name string-width-cjs version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -3837,6 +3838,7 @@ string_decoder@~1.1.1: safe-buffer "~5.1.0" "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + name strip-ansi-cjs version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -4285,6 +4287,7 @@ workerpool@^6.5.1: integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: + name wrap-ansi-cjs version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==