Merge pull request #49 from hexedtech/chore/rename

chore: enforcing API consistency (also across FFI)
This commit is contained in:
zaaarf 2024-10-16 17:34:34 +02:00 committed by GitHub
commit d7c9acd928
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 906 additions and 766 deletions

334
Cargo.lock generated
View file

@ -4,9 +4,9 @@ version = 3
[[package]]
name = "addr2line"
version = "0.24.1"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [
"gimli",
]
@ -49,9 +49,9 @@ checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
[[package]]
name = "async-stream"
version = "0.3.5"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51"
checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
dependencies = [
"async-stream-impl",
"futures-core",
@ -60,24 +60,24 @@ dependencies = [
[[package]]
name = "async-stream-impl"
version = "0.3.5"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
name = "async-trait"
version = "0.1.82"
version = "0.1.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -88,15 +88,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
version = "1.3.0"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "axum"
version = "0.7.5"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf"
checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae"
dependencies = [
"async-trait",
"axum-core",
@ -114,16 +114,16 @@ dependencies = [
"rustversion",
"serde",
"sync_wrapper 1.0.1",
"tower",
"tower 0.5.1",
"tower-layer",
"tower-service",
]
[[package]]
name = "axum-core"
version = "0.4.3"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3"
checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
dependencies = [
"async-trait",
"bytes",
@ -134,7 +134,7 @@ dependencies = [
"mime",
"pin-project-lite",
"rustversion",
"sync_wrapper 0.1.2",
"sync_wrapper 1.0.1",
"tower-layer",
"tower-service",
]
@ -190,15 +190,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.7.1"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
[[package]]
name = "cc"
version = "1.1.20"
version = "1.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45bcde016d64c21da4be18b655631e5ab6d3107607e71a73a9f53eb48aae23fb"
checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945"
dependencies = [
"shlex",
]
@ -343,7 +343,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
dependencies = [
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -440,36 +440,36 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "futures-channel"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-sink"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]]
name = "futures-task"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-util"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-core",
"futures-task",
@ -490,9 +490,9 @@ dependencies = [
[[package]]
name = "gimli"
version = "0.31.0"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "glob"
@ -512,7 +512,7 @@ dependencies = [
"futures-core",
"futures-sink",
"http",
"indexmap 2.5.0",
"indexmap 2.6.0",
"slab",
"tokio",
"tokio-util",
@ -531,6 +531,12 @@ version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hashbrown"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
[[package]]
name = "heck"
version = "0.5.0"
@ -579,9 +585,9 @@ dependencies = [
[[package]]
name = "httparse"
version = "1.9.4"
version = "1.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
[[package]]
name = "httpdate"
@ -597,9 +603,9 @@ checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026"
[[package]]
name = "hyper"
version = "1.4.1"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05"
checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a"
dependencies = [
"bytes",
"futures-channel",
@ -631,9 +637,9 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.8"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba"
checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b"
dependencies = [
"bytes",
"futures-channel",
@ -644,7 +650,6 @@ dependencies = [
"pin-project-lite",
"socket2",
"tokio",
"tower",
"tower-service",
"tracing",
]
@ -684,12 +689,12 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.5.0"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
dependencies = [
"equivalent",
"hashbrown 0.14.5",
"hashbrown 0.15.0",
]
[[package]]
@ -698,6 +703,12 @@ version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
[[package]]
name = "inventory"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767"
[[package]]
name = "itertools"
version = "0.13.0"
@ -749,9 +760,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "jni-toolbox"
version = "0.2.0"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eeae2881d819e208fcfceea81eb5a8ca6c131c6fb1605dfe2f3a31dea061ec7c"
checksum = "cce03cf89bc32b81de142a323a71e9903ee88127a0e04bbd7f215ab74ab6b10a"
dependencies = [
"jni",
"jni-toolbox-macro",
@ -760,20 +771,20 @@ dependencies = [
[[package]]
name = "jni-toolbox-macro"
version = "0.2.0"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e480850db18f0cc95120e7bf86af772c31b3c0f0dd3d3600682d8bd8399f4ae"
checksum = "609491ce00edcf12946945a514d033bf6e8bfbab02c6a25a46ed8cd4749707da"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
name = "js-sys"
version = "0.3.70"
version = "0.3.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
dependencies = [
"wasm-bindgen",
]
@ -796,9 +807,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.158"
version = "0.2.159"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
[[package]]
name = "libloading"
@ -935,7 +946,7 @@ checksum = "13e6f40fa1fd8426285688f4a37b56beac69284743d057ee6db352b543f4b621"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -946,9 +957,9 @@ checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
[[package]]
name = "napi"
version = "2.16.10"
version = "2.16.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04409e8c2d61995696e44d2181b79b68c1dd41f7e24a17cde60bbd9f54ddddef"
checksum = "3a84fdaf64da2b2d86b1be5db1b81963353bf00f7bef4b9e2668bbe6f72e8eb3"
dependencies = [
"bitflags",
"chrono",
@ -979,7 +990,7 @@ dependencies = [
"napi-derive-backend",
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -994,7 +1005,7 @@ dependencies = [
"quote",
"regex",
"semver",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1048,18 +1059,18 @@ dependencies = [
[[package]]
name = "object"
version = "0.36.4"
version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.19.0"
version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "openssl-probe"
@ -1118,27 +1129,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
dependencies = [
"fixedbitset",
"indexmap 2.5.0",
"indexmap 2.6.0",
]
[[package]]
name = "pin-project"
version = "1.1.5"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.5"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1155,15 +1166,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "portable-atomic"
version = "1.7.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265"
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
[[package]]
name = "ppv-lite86"
@ -1181,7 +1192,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
dependencies = [
"proc-macro2",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1196,18 +1207,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.86"
version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
dependencies = [
"unicode-ident",
]
[[package]]
name = "prost"
version = "0.13.2"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995"
checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f"
dependencies = [
"bytes",
"prost-derive",
@ -1215,9 +1226,9 @@ dependencies = [
[[package]]
name = "prost-build"
version = "0.13.2"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302"
checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15"
dependencies = [
"bytes",
"heck",
@ -1230,40 +1241,41 @@ dependencies = [
"prost",
"prost-types",
"regex",
"syn 2.0.77",
"syn 2.0.79",
"tempfile",
]
[[package]]
name = "prost-derive"
version = "0.13.2"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac"
checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
name = "prost-types"
version = "0.13.2"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519"
checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670"
dependencies = [
"prost",
]
[[package]]
name = "pyo3"
version = "0.22.3"
version = "0.22.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15ee168e30649f7f234c3d49ef5a7a6cbf5134289bc46c29ff3155fa3221c225"
checksum = "3d922163ba1f79c04bc49073ba7b32fd5a8d3b76a87c955921234b8e77333c51"
dependencies = [
"cfg-if",
"indoc",
"inventory",
"libc",
"memoffset",
"once_cell",
@ -1276,9 +1288,9 @@ dependencies = [
[[package]]
name = "pyo3-build-config"
version = "0.22.3"
version = "0.22.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e61cef80755fe9e46bb8a0b8f20752ca7676dcc07a5277d8b7768c6172e529b3"
checksum = "bc38c5feeb496c8321091edf3d63e9a6829eab4b863b4a6a65f26f3e9cc6b179"
dependencies = [
"once_cell",
"target-lexicon",
@ -1286,9 +1298,9 @@ dependencies = [
[[package]]
name = "pyo3-ffi"
version = "0.22.3"
version = "0.22.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67ce096073ec5405f5ee2b8b31f03a68e02aa10d5d4f565eca04acc41931fa1c"
checksum = "94845622d88ae274d2729fcefc850e63d7a3ddff5e3ce11bd88486db9f1d357d"
dependencies = [
"libc",
"pyo3-build-config",
@ -1296,27 +1308,27 @@ dependencies = [
[[package]]
name = "pyo3-macros"
version = "0.22.3"
version = "0.22.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2440c6d12bc8f3ae39f1e775266fa5122fd0c8891ce7520fa6048e683ad3de28"
checksum = "e655aad15e09b94ffdb3ce3d217acf652e26bbc37697ef012f5e5e348c716e5e"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.22.3"
version = "0.22.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1be962f0e06da8f8465729ea2cb71a416d2257dff56cbe40a70d3e62a93ae5d1"
checksum = "ae1e3f09eecd94618f60a455a23def79f79eba4dc561a97324bf9ac8c6df30ce"
dependencies = [
"heck",
"proc-macro2",
"pyo3-build-config",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1360,18 +1372,18 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.5.4"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853"
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
version = "1.10.6"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
dependencies = [
"aho-corasick",
"memchr",
@ -1381,9 +1393,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.7"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
dependencies = [
"aho-corasick",
"memchr",
@ -1392,9 +1404,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.8.4"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "ring"
@ -1447,9 +1459,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.23.13"
version = "0.23.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8"
checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8"
dependencies = [
"log",
"once_cell",
@ -1462,9 +1474,9 @@ dependencies = [
[[package]]
name = "rustls-native-certs"
version = "0.7.3"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5"
checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a"
dependencies = [
"openssl-probe",
"rustls-pemfile",
@ -1475,19 +1487,18 @@ dependencies = [
[[package]]
name = "rustls-pemfile"
version = "2.1.3"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425"
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
dependencies = [
"base64",
"rustls-pki-types",
]
[[package]]
name = "rustls-pki-types"
version = "1.8.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0"
checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
[[package]]
name = "rustls-webpki"
@ -1502,9 +1513,9 @@ dependencies = [
[[package]]
name = "rustversion"
version = "1.0.17"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
[[package]]
name = "ryu"
@ -1523,9 +1534,9 @@ dependencies = [
[[package]]
name = "schannel"
version = "0.1.24"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b"
checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1"
dependencies = [
"windows-sys 0.59.0",
]
@ -1551,9 +1562,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
version = "2.11.1"
version = "2.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf"
checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6"
dependencies = [
"core-foundation-sys",
"libc",
@ -1592,7 +1603,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1701,9 +1712,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.77"
version = "2.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
dependencies = [
"proc-macro2",
"quote",
@ -1730,9 +1741,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "tempfile"
version = "3.12.0"
version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
dependencies = [
"cfg-if",
"fastrand",
@ -1743,22 +1754,22 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.63"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.63"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1795,7 +1806,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1845,16 +1856,16 @@ version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
"indexmap 2.5.0",
"indexmap 2.6.0",
"toml_datetime",
"winnow",
]
[[package]]
name = "tonic"
version = "0.12.2"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad"
checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52"
dependencies = [
"async-stream",
"async-trait",
@ -1877,7 +1888,7 @@ dependencies = [
"tokio",
"tokio-rustls",
"tokio-stream",
"tower",
"tower 0.4.13",
"tower-layer",
"tower-service",
"tracing",
@ -1885,15 +1896,16 @@ dependencies = [
[[package]]
name = "tonic-build"
version = "0.12.2"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe4ee8877250136bd7e3d2331632810a4df4ea5e004656990d8d66d2f5ee8a67"
checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11"
dependencies = [
"prettyplease",
"proc-macro2",
"prost-build",
"prost-types",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -1916,6 +1928,20 @@ dependencies = [
"tracing",
]
[[package]]
name = "tower"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
"sync_wrapper 0.1.2",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
@ -1947,7 +1973,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]
@ -2080,9 +2106,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.93"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
dependencies = [
"cfg-if",
"once_cell",
@ -2091,24 +2117,24 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.93"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.93"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -2116,22 +2142,22 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.93"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.93"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
[[package]]
name = "winapi"
@ -2354,7 +2380,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.79",
]
[[package]]

View file

@ -51,7 +51,7 @@ napi = { version = "2.16", features = ["full"], optional = true }
napi-derive = { version="2.16", optional = true}
# glue (python)
pyo3 = { version = "0.22", features = ["extension-module"], optional = true}
pyo3 = { version = "0.22", features = ["extension-module", "multiple-pymethods"], optional = true}
# extra
async-trait = { version = "0.1", optional = true }

View file

@ -34,17 +34,17 @@ public final class Client {
*/
public static native Client connect(Config config) throws ConnectionException;
private static native User get_user(long self);
private static native User current_user(long self);
/**
* Gets information about the current user.
* @return a {@link User} object representing the user
*/
public User getUser() {
return get_user(this.ptr);
public User currentUser() {
return current_user(this.ptr);
}
private static native Workspace join_workspace(long self, String workspaceId) throws ConnectionException;
private static native Workspace attach_workspace(long self, String workspaceId) throws ConnectionException;
/**
* Joins a {@link Workspace} and returns it.
@ -52,8 +52,8 @@ public final class Client {
* @return the relevant {@link Workspace}
* @throws ConnectionException if an error occurs in communicating with the server
*/
public Workspace joinWorkspace(String workspaceId) throws ConnectionException {
return join_workspace(this.ptr, workspaceId);
public Workspace attachWorkspace(String workspaceId) throws ConnectionException {
return attach_workspace(this.ptr, workspaceId);
}
private static native void create_workspace(long self, String workspaceId) throws ConnectionRemoteException;
@ -91,17 +91,26 @@ public final class Client {
invite_to_workspace(this.ptr, workspaceId, user);
}
private static native String[] list_workspaces(long self, boolean owned, boolean invited) throws ConnectionRemoteException;
private static native String[] fetch_owned_workspaces(long self) throws ConnectionRemoteException;
/**
* Lists available workspaces according to certain filters.
* @param owned if owned workspaces should be included
* @param invited if workspaces the user is invited to should be included
* Lists workspaces owned by the current user.
* @return an array of workspace IDs
* @throws ConnectionRemoteException if an error occurs in communicating with the server
*/
public String[] listWorkspaces(boolean owned, boolean invited) throws ConnectionRemoteException {
return list_workspaces(this.ptr, owned, invited);
public String[] fetchOwnedWorkspaces() throws ConnectionRemoteException {
return fetch_owned_workspaces(this.ptr);
}
private static native String[] fetch_joined_workspaces(long self) throws ConnectionRemoteException;
/**
* Lists workspaces the current user has joined.
* @return an array of workspace IDs
* @throws ConnectionRemoteException if an error occurs in communicating with the server
*/
public String[] fetchJoinedWorkspaces() throws ConnectionRemoteException {
return fetch_joined_workspaces(this.ptr);
}
private static native String[] active_workspaces(long self);

View file

@ -1,9 +1,10 @@
package mp.code;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Consumer;
import lombok.Getter;
import mp.code.data.User;
import mp.code.exceptions.ConnectionException;
import mp.code.exceptions.ConnectionRemoteException;
import mp.code.exceptions.ControllerException;
@ -24,24 +25,24 @@ public final class Workspace {
Extensions.CLEANER.register(this, () -> free(ptr));
}
private static native String get_workspace_id(long self);
private static native String id(long self);
/**
* Gets the unique identifier of the current workspace.
* @return the identifier
*/
public String getWorkspaceId() {
return get_workspace_id(this.ptr);
public String id() {
return id(this.ptr);
}
private static native CursorController get_cursor(long self);
private static native CursorController cursor(long self);
/**
* Gets the {@link CursorController} for the current workspace.
* @return the {@link CursorController}
*/
public CursorController getCursor() {
return get_cursor(this.ptr);
public CursorController cursor() {
return cursor(this.ptr);
}
private static native BufferController get_buffer(long self, String path);
@ -56,17 +57,16 @@ public final class Workspace {
return Optional.ofNullable(get_buffer(this.ptr, path));
}
private static native String[] get_file_tree(long self, String filter, boolean strict);
private static native String[] search_buffers(long self, String filter);
/**
* Gets the file tree for this workspace, optionally filtering it.
* @param filter applies an optional filter to the outputs
* @param strict whether it should be a strict match (equals) or not (startsWith)
* Searches for buffers matching the filter in this workspace.
* @param filter the filter to apply
* @return an array containing file tree as flat paths
*/
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public String[] getFileTree(Optional<String> filter, boolean strict) {
return get_file_tree(this.ptr, filter.orElse(null), strict);
public String[] searchBuffers(Optional<String> filter) {
return search_buffers(this.ptr, filter.orElse(null));
}
private static native String[] active_buffers(long self);
@ -101,7 +101,7 @@ public final class Workspace {
create_buffer(this.ptr, path);
}
private static native BufferController attach_to_buffer(long self, String path) throws ConnectionException;
private static native BufferController attach_buffer(long self, String path) throws ConnectionException;
/**
* Attaches to an existing buffer with the given path, if present.
@ -109,52 +109,54 @@ public final class Workspace {
* @return the {@link BufferController} associated with that path
* @throws ConnectionException if an error occurs in communicating with the server, or if the buffer did not exist
*/
public BufferController attachToBuffer(String path) throws ConnectionException {
return attach_to_buffer(ptr, path);
public BufferController attachBuffer(String path) throws ConnectionException {
return attach_buffer(ptr, path);
}
private static native boolean detach_from_buffer(long self, String path);
private static native boolean detach_buffer(long self, String path);
/**
* Detaches from a given buffer.
* @param path the path of the buffer to detach from
* @return a boolean, true only if there are still dangling references preventing controller from stopping
*/
public boolean detachFromBuffer(String path) {
return detach_from_buffer(this.ptr, path);
public boolean detachBuffer(String path) {
return detach_buffer(this.ptr, path);
}
private static native void fetch_buffers(long self) throws ConnectionRemoteException;
private static native String[] fetch_buffers(long self) throws ConnectionRemoteException;
/**
* Updates the local list of buffers.
* Updates and fetches the local list of buffers.
* @return the updated list
* @throws ConnectionRemoteException if an error occurs in communicating with the server
*/
public void fetchBuffers() throws ConnectionRemoteException {
fetch_buffers(this.ptr);
public String[] fetchBuffers() throws ConnectionRemoteException {
return fetch_buffers(this.ptr);
}
private static native void fetch_users(long self) throws ConnectionRemoteException;
private static native User[] fetch_users(long self) throws ConnectionRemoteException;
/**
* Updates the local list of users.
* Updates and fetches the local list of users.
* @return the updated list
* @throws ConnectionRemoteException if an error occurs in communicating with the server
*/
public void fetchUsers() throws ConnectionRemoteException {
fetch_buffers(this.ptr);
public User[] fetchUsers() throws ConnectionRemoteException {
return fetch_users(this.ptr);
}
private static native UUID[] list_buffer_users(long self, String path) throws ConnectionRemoteException;
private static native User[] fetch_buffer_users(long self, String path) throws ConnectionRemoteException;
/**
* Lists the user attached to a certain buffer.
* Fetches the users attached to a certain buffer.
* The user must be attached to the buffer to perform this operation.
* @param path the path of the buffer to search
* @return an array of user {@link UUID UUIDs}
* @return an array of {@link User}s
* @throws ConnectionRemoteException if an error occurs in communicating with the server, or the user wasn't attached
*/
public UUID[] listBufferUsers(String path) throws ConnectionRemoteException {
return list_buffer_users(this.ptr, path);
public User[] fetchBufferUsers(String path) throws ConnectionRemoteException {
return fetch_buffer_users(this.ptr, path);
}
private static native void delete_buffer(long self, String path) throws ConnectionRemoteException;
@ -234,7 +236,8 @@ public final class Workspace {
* Represents a workspace-wide event.
*/
public static final class Event {
private final Type type;
/** The type of the event. */
public final @Getter Type type;
private final String argument;
Event(Type type, String argument) {
@ -272,9 +275,24 @@ public final class Workspace {
} else return Optional.empty();
}
enum Type {
/**
* The type of workspace event.
*/
public enum Type {
/**
* Somebody joined a workspace.
* @see #getUserJoined() to get the name
*/
USER_JOIN,
/**
* Somebody left a workspace
* @see #getUserLeft() to get the name
*/
USER_LEAVE,
/**
* The filetree was updated.
* @see #getChangedBuffer() to see the buffer that changed
*/
FILE_TREE_UPDATED
}
}

View file

@ -10,19 +10,18 @@ import lombok.ToString;
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public class TextChange {
/**
* The starting position of the change.
* If negative, it is clamped to 0.
*/
public final long start;
public final long startIdx;
/**
* The ending position of the change.
* If negative, it is clamped to 0.
*/
public final long end;
public final long endIdx;
/**
* The content of the change.
@ -37,7 +36,7 @@ public class TextChange {
* @return true if this change represents a deletion
*/
public boolean isDelete() {
return this.start < this.end;
return this.startIdx < this.endIdx;
}
/**
@ -64,14 +63,14 @@ public class TextChange {
* @return the mutated string
*/
public String apply(String input) {
long preIndex = Math.min(this.start, input.length());
long preIndex = Math.min(this.startIdx, input.length());
String pre = "";
try {
pre = input.substring(0, (int) preIndex);
} catch(IndexOutOfBoundsException ignored) {}
String post = "";
try {
post = input.substring((int) this.end);
post = input.substring((int) this.endIdx);
} catch(IndexOutOfBoundsException ignored) {}
return pre + this.content + post;
}

View file

@ -158,16 +158,32 @@ function MaybeBufferUpdatePromise:cancel() end
---invoke callback asynchronously as soon as promise is ready
function MaybeBufferUpdatePromise:and_then(cb) end
---@class (exact) UserListPromise : Promise
local UserListPromise = {}
--- block until promise is ready and return value
--- @return User[]
function UserListPromise:await() end
--- cancel promise execution
function UserListPromise:cancel() end
---@param cb fun(x: User[]) callback to invoke
---invoke callback asynchronously as soon as promise is ready
function UserListPromise:and_then(cb) end
-- [[ END ASYNC STUFF ]]
---@class (exact) Client
---@field id string uuid of local user
---@field username string name of local user
---@field active_workspaces string[] array of all currently active workspace names
---the effective local client, handling connecting to codemp server
local Client = {}
---@return User
---current logged in user for this client
function Client:current_user() end
---@return string[]
---array of all currently active workspace names
function Client:active_workspaces() end
---@return NilPromise
---@async
---@nodiscard
@ -179,7 +195,7 @@ function Client:refresh() end
---@async
---@nodiscard
---join requested workspace if possible and subscribe to event bus
function Client:join_workspace(ws) end
function Client:attach_workspace(ws) end
---@param ws string workspace id to create
---@return NilPromise
@ -207,13 +223,17 @@ function Client:delete_workspace(ws) end
---grant user acccess to workspace
function Client:invite_to_workspace(ws, user) end
---@param owned boolean? list owned workspaces, default true
---@param invited boolean? list invited workspaces, default true
---@return StringArrayPromise
---@async
---@nodiscard
---grant user acccess to workspace
function Client:list_workspaces(owned, invited) end
---fetch and list owned workspaces
function Client:fetch_owned_workspaces() end
---@return StringArrayPromise
---@async
---@nodiscard
---fetch and list joined workspaces
function Client:fetch_joined_workspaces() end
---@param ws string workspace id to get
---@return Workspace?
@ -222,26 +242,41 @@ function Client:get_workspace(ws) end
---@class User
---@field id string user uuid
---@field name string user display name
---@class (exact) Workspace
---@field name string workspace name
---@field cursor CursorController workspace cursor controller
---@field active_buffers string[] array of all currently active buffer names
---a joined codemp workspace
local Workspace = {}
---@return string
---workspace id
function Workspace:id() end
---@return string[]
---array of all currently active buffer names
function Workspace:active_buffers() end
---@return CursorController
---reference to workspace's CursorController
function Workspace:cursor() end
---@param path string relative path ("name") of new buffer
---@return NilPromise
---@async
---@nodiscard
---create a new empty buffer
function Workspace:create(path) end
function Workspace:create_buffer(path) end
---@param path string relative path ("name") of buffer to delete
---@return NilPromise
---@async
---@nodiscard
---delete buffer from workspace
function Workspace:delete(path) end
function Workspace:delete_buffer(path) end
---@param path string relative path ("name") of buffer to get
---@return BufferController?
@ -253,20 +288,19 @@ function Workspace:get_buffer(path) end
---@async
---@nodiscard
---attach to a remote buffer, synching content and changes and returning its controller
function Workspace:attach(path) end
function Workspace:attach_buffer(path) end
---@param path string relative path ("name") of buffer to detach from
---@return boolean success
---detach from an active buffer, closing all streams. returns false if there are still dangling references
function Workspace:detach(path) end
function Workspace:detach_buffer(path) end
---@param filter? string apply a filter to the return elements
---@param strict? boolean whether to strictly match or just check whether it starts with it
---@return string[]
---return the list of available buffers in this workspace, as relative paths from workspace root
function Workspace:filetree(filter, strict) end
function Workspace:search_buffers(filter) end
---@return string[]
---@return User[]
---return all names of users currently in this workspace
function Workspace:user_list() end
@ -282,6 +316,13 @@ function Workspace:fetch_buffers(path) end
---force refresh users list from workspace
function Workspace:fetch_users(path) end
---@param path string the buffer to look in
---@return UserListPromise
---@async
---@nodiscard
---fetch the list of users in the given buffer
function Workspace:fetch_buffer_users(path) end
---@class (exact) WorkspaceEvent
---@field type string
---@field value string
@ -320,8 +361,8 @@ local BufferController = {}
---@class TextChange
---@field content string text content of change
---@field start integer start index of change
---@field finish integer end index of change
---@field start_idx integer start index of change
---@field end_idx integer end index of change
local TextChange = {}
---@class (exact) BufferUpdate

View file

@ -7,6 +7,13 @@ class Driver:
"""
def stop(self) -> None: ...
class User:
"""
A remote user, with uuid and username
"""
id: str
name: str
class Config:
"""
Configuration data structure for codemp clients
@ -17,7 +24,7 @@ class Config:
port: Optional[int]
tls: Optional[bool]
def __new__(cls, *, username: str, password: str, **kwargs) -> Config: ...
def __new__(cls, username: str, password: str, **kwargs) -> Config: ...
def init() -> Driver: ...
def set_logger(logger_cb: Callable[[str], None], debug: bool) -> bool: ...
@ -40,16 +47,16 @@ class Client:
Handle to the actual client that manages the session. It manages the connection
to a server and joining/creating new workspaces
"""
def join_workspace(self, workspace: str) -> Promise[Workspace]: ...
def attach_workspace(self, workspace: str) -> Promise[Workspace]: ...
def create_workspace(self, workspace: str) -> Promise[None]: ...
def delete_workspace(self, workspace: str) -> Promise[None]: ...
def invite_to_workspace(self, workspace: str, username: str) -> Promise[None]: ...
def list_workspaces(self, owned: bool, invited: bool) -> Promise[list[str]]: ...
def fetch_owned_workspaces(self) -> Promise[list[str]]: ...
def fetch_joined_workspaces(self) -> Promise[list[str]]: ...
def leave_workspace(self, workspace: str) -> bool: ...
def get_workspace(self, id: str) -> Workspace: ...
def active_workspaces(self) -> list[str]: ...
def user_id(self) -> str: ...
def user_name(self) -> str: ...
def current_user(self) -> User: ...
def refresh(self) -> Promise[None]: ...
class Event:
@ -60,18 +67,19 @@ class Workspace:
Handle to a workspace inside codemp. It manages buffers.
A cursor is tied to the single workspace.
"""
def create(self, path: str) -> Promise[None]: ...
def attach(self, path: str) -> Promise[BufferController]: ...
def detach(self, path: str) -> bool: ...
def fetch_buffers(self) -> Promise[None]: ...
def fetch_users(self) -> Promise[None]: ...
def list_buffer_users(self, path: str) -> Promise[list[str]]: ...
def delete(self, path: str) -> Promise[None]: ...
def create_buffer(self, path: str) -> Promise[None]: ...
def attach_buffer(self, path: str) -> Promise[BufferController]: ...
def detach_buffer(self, path: str) -> bool: ...
def fetch_buffers(self) -> Promise[list[str]]: ...
def fetch_users(self) -> Promise[list[User]]: ...
def fetch_buffer_users(self, path: str) -> Promise[list[User]]: ...
def delete_buffer(self, path: str) -> Promise[None]: ...
def id(self) -> str: ...
def cursor(self) -> CursorController: ...
def buffer_by_name(self, path: str) -> Optional[BufferController]: ...
def buffer_list(self) -> list[str]: ...
def filetree(self, filter: Optional[str], strict: bool) -> list[str]: ...
def get_buffer(self, path: str) -> Optional[BufferController]: ...
def user_list(self) -> list[User]: ...
def active_buffers(self) -> list[str]: ...
def search_buffers(self, filter: Optional[str]) -> list[str]: ...
def recv(self) -> Promise[Event]: ...
def try_recv(self) -> Promise[Optional[Event]]: ...
def poll(self) -> Promise[None]: ...
@ -109,10 +117,7 @@ class BufferController:
def path(self) -> str: ...
def content(self) -> Promise[str]: ...
def ack(self, v: list[int]) -> None: ...
def send(self,
start: int,
end: int,
txt: str) -> Promise[None]: ...
def send(self, op: TextChange) -> None: ...
def try_recv(self) -> Promise[Optional[TextChange]]: ...
def recv(self) -> Promise[TextChange]: ...
def poll(self) -> Promise[None]: ...
@ -143,10 +148,7 @@ class CursorController:
Handle to the controller for a workspace, which manages the back and forth of
cursor movements to and from other peers
"""
def send(self,
path: str,
start: Tuple[int, int],
end: Tuple[int, int]) -> Promise[None]: ...
def send(self, pos: Selection) -> None: ...
def try_recv(self) -> Promise[Optional[Cursor]]: ...
def recv(self) -> Promise[Cursor]: ...
def poll(self) -> Promise[None]: ...

View file

@ -31,18 +31,18 @@ pub struct BufferUpdate {
/// ### Examples
/// To insert 'a' after 4th character we should send:
/// ```
/// codemp::api::TextChange { start: 4, end: 4, content: "a".into() };
/// codemp::api::TextChange { start_idx: 4, end_idx: 4, content: "a".into() };
/// ```
///
/// To delete the fourth character we should send:
/// ```
/// codemp::api::TextChange { start: 3, end: 4, content: "".into() };
/// codemp::api::TextChange { start_idx: 3, end_idx: 4, content: "".into() };
/// ```
///
/// ```
/// let change = codemp::api::TextChange {
/// start: 6,
/// end: 11,
/// start_idx: 6,
/// end_idx: 11,
/// content: "mom".to_string()
/// };
/// let before = "hello world!";
@ -55,10 +55,9 @@ pub struct BufferUpdate {
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub struct TextChange {
/// Range start of text change, as char indexes in buffer previous state.
pub start: u32,
pub start_idx: u32,
/// Range end of text change, as char indexes in buffer previous state.
#[cfg_attr(feature = "serialize", serde(alias = "finish"))] // Lua uses `end` as keyword
pub end: u32,
pub end_idx: u32,
/// New content of text inside span.
pub content: String,
}
@ -66,7 +65,7 @@ pub struct TextChange {
impl TextChange {
/// Returns the [`std::ops::Range`] representing this change's span.
pub fn span(&self) -> std::ops::Range<usize> {
self.start as usize..self.end as usize
self.start_idx as usize..self.end_idx as usize
}
}
@ -76,7 +75,7 @@ impl TextChange {
///
/// Note that this is is **not** mutually exclusive with [TextChange::is_insert].
pub fn is_delete(&self) -> bool {
self.start < self.end
self.start_idx < self.end_idx
}
/// Returns true if this [`TextChange`] adds new text.
@ -93,9 +92,9 @@ impl TextChange {
/// Applies this text change to given text, returning a new string.
pub fn apply(&self, txt: &str) -> String {
let pre_index = std::cmp::min(self.start as usize, txt.len());
let pre_index = std::cmp::min(self.start_idx as usize, txt.len());
let pre = txt.get(..pre_index).unwrap_or("").to_string();
let post = txt.get(self.end as usize..).unwrap_or("").to_string();
let post = txt.get(self.end_idx as usize..).unwrap_or("").to_string();
format!("{}{}{}", pre, self.content, post)
}
}
@ -105,8 +104,8 @@ mod tests {
#[test]
fn textchange_apply_works_for_insertions() {
let change = super::TextChange {
start: 5,
end: 5,
start_idx: 5,
end_idx: 5,
content: " cruel".to_string(),
};
let result = change.apply("hello world!");
@ -116,8 +115,8 @@ mod tests {
#[test]
fn textchange_apply_works_for_deletions() {
let change = super::TextChange {
start: 5,
end: 11,
start_idx: 5,
end_idx: 11,
content: "".to_string(),
};
let result = change.apply("hello cruel world!");
@ -127,8 +126,8 @@ mod tests {
#[test]
fn textchange_apply_works_for_replacements() {
let change = super::TextChange {
start: 5,
end: 11,
start_idx: 5,
end_idx: 11,
content: " not very pleasant".to_string(),
};
let result = change.apply("hello cruel world!");
@ -138,8 +137,8 @@ mod tests {
#[test]
fn textchange_apply_never_panics() {
let change = super::TextChange {
start: 100,
end: 110,
start_idx: 100,
end_idx: 110,
content: "a very long string \n which totally matters".to_string(),
};
let result = change.apply("a short text");
@ -152,8 +151,8 @@ mod tests {
#[test]
fn empty_textchange_doesnt_alter_buffer() {
let change = super::TextChange {
start: 42,
end: 42,
start_idx: 42,
end_idx: 42,
content: "".to_string(),
};
let result = change.apply("some important text");

View file

@ -1,29 +1,32 @@
//! # Event
//! Real time notification of changes in a workspace, to either users or buffers.
#![allow(non_upper_case_globals, non_camel_case_types)] // pyo3 fix your shit
use codemp_proto::workspace::workspace_event::Event as WorkspaceEventInner;
/// Event in a [crate::Workspace].
#[derive(Debug, Clone)]
#[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3::pyclass)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub enum Event {
/// Fired when the file tree changes.
/// Contains the modified buffer path (deleted, created or renamed).
FileTreeUpdated(String),
FileTreeUpdated { path: String },
/// Fired when an user joins the current workspace.
UserJoin(String),
UserJoin { name: String },
/// Fired when an user leaves the current workspace.
UserLeave(String),
UserLeave { name: String },
}
impl From<WorkspaceEventInner> for Event {
fn from(event: WorkspaceEventInner) -> Self {
match event {
WorkspaceEventInner::Join(e) => Self::UserJoin(e.user.name),
WorkspaceEventInner::Leave(e) => Self::UserLeave(e.user.name),
WorkspaceEventInner::Create(e) => Self::FileTreeUpdated(e.path),
WorkspaceEventInner::Delete(e) => Self::FileTreeUpdated(e.path),
WorkspaceEventInner::Rename(e) => Self::FileTreeUpdated(e.after),
WorkspaceEventInner::Join(e) => Self::UserJoin { name: e.user.name },
WorkspaceEventInner::Leave(e) => Self::UserLeave { name: e.user.name },
WorkspaceEventInner::Create(e) => Self::FileTreeUpdated { path: e.path },
WorkspaceEventInner::Delete(e) => Self::FileTreeUpdated { path: e.path },
WorkspaceEventInner::Rename(e) => Self::FileTreeUpdated { path: e.after },
}
}
}

View file

@ -19,11 +19,9 @@ pub mod event;
/// data structure for remote users
pub mod user;
pub use change::BufferUpdate;
pub use change::TextChange;
pub use change::{BufferUpdate, TextChange};
pub use config::Config;
pub use controller::Controller;
pub use cursor::Cursor;
pub use cursor::Selection;
pub use controller::{AsyncReceiver, AsyncSender, Controller};
pub use cursor::{Cursor, Selection};
pub use event::Event;
pub use user::User;

View file

@ -6,6 +6,7 @@ use uuid::Uuid;
/// Represents a service user
#[derive(Debug, Clone)]
#[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3::pyclass)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub struct User {
/// User unique identifier, should never change.

View file

@ -160,8 +160,8 @@ impl BufferWorker {
async fn handle_editor_change(&mut self, change: TextChange, tx: &mpsc::Sender<Operation>) {
let last_ver = self.oplog.local_version();
// clip to buffer extents
let clip_start = change.start as usize;
let mut clip_end = change.end as usize;
let clip_start = change.start_idx as usize;
let mut clip_end = change.end_idx as usize;
let b_len = self.branch.len();
if clip_end > b_len {
tracing::warn!("clipping TextChange end span from {clip_end} to {b_len}");
@ -170,8 +170,11 @@ impl BufferWorker {
// in case we have a "replace" span
if change.is_delete() {
self.branch
.delete_without_content(&mut self.oplog, self.agent_id, clip_start..clip_end);
self.branch.delete_without_content(
&mut self.oplog,
self.agent_id,
clip_start..clip_end,
);
}
if change.is_insert() {
@ -247,7 +250,9 @@ impl BufferWorker {
{
tracing::warn!(
"Insert span ({}, {}) differs from effective content len ({})",
dtop.start(), dtop.end(), dtop.content_as_str().unwrap_or_default().len()
dtop.start(),
dtop.end(),
dtop.content_as_str().unwrap_or_default().len()
);
}
crate::api::BufferUpdate {
@ -257,8 +262,8 @@ impl BufferWorker {
.map(|x| i64::from_ne_bytes(x.to_ne_bytes()))
.collect(), // TODO this is wasteful
change: crate::api::TextChange {
start: dtop.start() as u32,
end: dtop.start() as u32,
start_idx: dtop.start() as u32,
end_idx: dtop.start() as u32,
content: dtop.content_as_str().unwrap_or_default().to_string(),
},
}
@ -271,8 +276,8 @@ impl BufferWorker {
.map(|x| i64::from_ne_bytes(x.to_ne_bytes()))
.collect(), // TODO this is wasteful
change: crate::api::TextChange {
start: dtop.start() as u32,
end: dtop.end() as u32,
start_idx: dtop.start() as u32,
end_idx: dtop.end() as u32,
content: dtop.content_as_str().unwrap_or_default().to_string(),
},
},

View file

@ -130,9 +130,18 @@ impl Client {
Ok(())
}
/// List all available workspaces, also filtering between those owned and those invited to.
pub async fn list_workspaces(&self, owned: bool, invited: bool) -> RemoteResult<Vec<String>> {
let mut workspaces = self
/// Fetch the names of all workspaces owned by the current user.
pub async fn fetch_owned_workspaces(&self) -> RemoteResult<Vec<String>> {
self.fetch_workspaces(true).await
}
/// Fetch the names of all workspaces the current user has joined.
pub async fn fetch_joined_workspaces(&self) -> RemoteResult<Vec<String>> {
self.fetch_workspaces(false).await
}
async fn fetch_workspaces(&self, owned: bool) -> RemoteResult<Vec<String>> {
let workspaces = self
.0
.session
.clone()
@ -140,20 +149,18 @@ impl Client {
.await?
.into_inner();
let mut out = Vec::new();
if owned {
out.append(&mut workspaces.owned)
Ok(workspaces.owned)
} else {
Ok(workspaces.invited)
}
if invited {
out.append(&mut workspaces.invited)
}
Ok(out)
}
/// Join and return a [`Workspace`].
pub async fn join_workspace(&self, workspace: impl AsRef<str>) -> ConnectionResult<Workspace> {
pub async fn attach_workspace(
&self,
workspace: impl AsRef<str>,
) -> ConnectionResult<Workspace> {
let token = self
.0
.session
@ -203,7 +210,7 @@ impl Client {
}
/// Get the currently logged in user.
pub fn user(&self) -> &User {
pub fn current_user(&self) -> &User {
&self.0.user
}
}

View file

@ -2,10 +2,7 @@ use jni::{objects::JObject, JNIEnv};
use jni_toolbox::jni;
use crate::{
api::{
controller::{AsyncReceiver, AsyncSender},
BufferUpdate, TextChange,
},
api::{AsyncReceiver, AsyncSender, BufferUpdate, TextChange},
errors::ControllerError,
};

View file

@ -7,21 +7,21 @@ use crate::{
use jni_toolbox::jni;
/// Connect using the given credentials to the default server, and return a [Client] to interact with it.
#[jni(package = "mp.code", class = "Client", ptr)]
#[jni(package = "mp.code", class = "Client")]
fn connect(config: Config) -> Result<Client, ConnectionError> {
super::tokio().block_on(Client::connect(config))
}
/// Gets the current [crate::api::User].
#[jni(package = "mp.code", class = "Client", ptr)]
fn get_user(client: &mut Client) -> crate::api::User {
client.user().clone()
#[jni(package = "mp.code", class = "Client")]
fn current_user(client: &mut Client) -> crate::api::User {
client.current_user().clone()
}
/// Join a [Workspace] and return a pointer to it.
#[jni(package = "mp.code", class = "Client")]
fn join_workspace(client: &mut Client, workspace: String) -> Result<Workspace, ConnectionError> {
super::tokio().block_on(client.join_workspace(workspace))
fn attach_workspace(client: &mut Client, workspace: String) -> Result<Workspace, ConnectionError> {
super::tokio().block_on(client.attach_workspace(workspace))
}
/// Create a workspace on server, if allowed to.
@ -46,14 +46,16 @@ fn invite_to_workspace(
super::tokio().block_on(client.invite_to_workspace(workspace, user))
}
/// List available workspaces.
/// List owned workspaces.
#[jni(package = "mp.code", class = "Client")]
fn list_workspaces(
client: &mut Client,
owned: bool,
invited: bool,
) -> Result<Vec<String>, RemoteError> {
super::tokio().block_on(client.list_workspaces(owned, invited))
fn fetch_owned_workspaces(client: &mut Client) -> Result<Vec<String>, RemoteError> {
super::tokio().block_on(client.fetch_owned_workspaces())
}
/// List joined workspaces.
#[jni(package = "mp.code", class = "Client")]
fn fetch_joined_workspaces(client: &mut Client) -> Result<Vec<String>, RemoteError> {
super::tokio().block_on(client.fetch_joined_workspaces())
}
/// List available workspaces.

View file

@ -1,8 +1,5 @@
use crate::{
api::{
controller::{AsyncReceiver, AsyncSender},
Cursor, Selection,
},
api::{AsyncReceiver, AsyncSender, Cursor, Selection},
errors::ControllerError,
};
use jni::{objects::JObject, JNIEnv};

View file

@ -170,9 +170,9 @@ impl<'j> jni_toolbox::IntoJavaObject<'j> for crate::api::Event {
env: &mut jni::JNIEnv<'j>,
) -> Result<jni::objects::JObject<'j>, jni::errors::Error> {
let (ordinal, arg) = match self {
crate::api::Event::UserJoin(arg) => (0, env.new_string(arg)?),
crate::api::Event::UserLeave(arg) => (1, env.new_string(arg)?),
crate::api::Event::FileTreeUpdated(arg) => (2, env.new_string(arg)?),
crate::api::Event::UserJoin { name: arg } => (0, env.new_string(arg)?),
crate::api::Event::UserLeave { name: arg } => (1, env.new_string(arg)?),
crate::api::Event::FileTreeUpdated { path: arg } => (2, env.new_string(arg)?),
};
let type_class = env.find_class("mp/code/Workspace$Event$Type")?;
@ -242,8 +242,8 @@ impl<'j> jni_toolbox::IntoJavaObject<'j> for crate::api::TextChange {
class,
"(JJLjava/lang/String;)V",
&[
jni::objects::JValueGen::Long(self.start.into()),
jni::objects::JValueGen::Long(self.end.into()),
jni::objects::JValueGen::Long(self.start_idx.into()),
jni::objects::JValueGen::Long(self.end_idx.into()),
jni::objects::JValueGen::Object(&content),
],
)
@ -438,11 +438,11 @@ impl<'j> jni_toolbox::FromJava<'j> for crate::api::TextChange {
change: Self::From,
) -> Result<Self, jni::errors::Error> {
let start = env
.get_field(&change, "start", "J")?
.get_field(&change, "startIdx", "J")?
.j()?
.clamp(0, u32::MAX.into()) as u32;
let end = env
.get_field(&change, "end", "J")?
.get_field(&change, "endIdx", "J")?
.j()?
.clamp(0, u32::MAX.into()) as u32;
@ -457,8 +457,8 @@ impl<'j> jni_toolbox::FromJava<'j> for crate::api::TextChange {
};
Ok(Self {
start,
end,
start_idx: start,
end_idx: end,
content,
})
}

View file

@ -1,5 +1,5 @@
use crate::{
api::controller::AsyncReceiver,
api::{controller::AsyncReceiver, User},
errors::{ConnectionError, ControllerError, RemoteError},
ffi::java::null_check,
Workspace,
@ -9,86 +9,86 @@ use jni_toolbox::jni;
/// Get the workspace id.
#[jni(package = "mp.code", class = "Workspace")]
fn get_workspace_id(workspace: &mut Workspace) -> String {
fn id(workspace: &mut Workspace) -> String {
workspace.id()
}
/// Get a cursor controller by name and returns a pointer to it.
#[jni(package = "mp.code", class = "Workspace")]
fn get_cursor(workspace: &mut Workspace) -> crate::cursor::Controller {
fn cursor(workspace: &mut Workspace) -> crate::cursor::Controller {
workspace.cursor()
}
/// Get a buffer controller by name and returns a pointer to it.
#[jni(package = "mp.code", class = "Workspace")]
fn get_buffer(workspace: &mut Workspace, path: String) -> Option<crate::buffer::Controller> {
workspace.buffer_by_name(&path)
workspace.get_buffer(&path)
}
/// Get the filetree.
/// Searches for buffers matching the filter.
#[jni(package = "mp.code", class = "Workspace")]
fn get_file_tree(workspace: &mut Workspace, filter: Option<String>, strict: bool) -> Vec<String> {
workspace.filetree(filter.as_deref(), strict)
fn search_buffers(workspace: &mut Workspace, filter: Option<String>) -> Vec<String> {
workspace.search_buffers(filter.as_deref())
}
/// Gets a list of the active buffers.
#[jni(package = "mp.code", class = "Workspace")]
fn active_buffers(workspace: &mut Workspace) -> Vec<String> {
workspace.buffer_list()
workspace.active_buffers()
}
/// Gets a list of the active buffers.
#[jni(package = "mp.code", class = "Workspace")]
fn user_list(workspace: &mut Workspace) -> Vec<String> {
fn user_list(workspace: &mut Workspace) -> Vec<User> {
workspace.user_list()
}
/// Create a new buffer.
#[jni(package = "mp.code", class = "Workspace")]
fn create_buffer(workspace: &mut Workspace, path: String) -> Result<(), RemoteError> {
super::tokio().block_on(workspace.create(&path))
super::tokio().block_on(workspace.create_buffer(&path))
}
/// Attach to a buffer and return a pointer to its [crate::buffer::Controller].
/// Attach to a buffer and return a pointer to its [`crate::buffer::Controller`].
#[jni(package = "mp.code", class = "Workspace")]
fn attach_to_buffer(
fn attach_buffer(
workspace: &mut Workspace,
path: String,
) -> Result<crate::buffer::Controller, ConnectionError> {
super::tokio().block_on(workspace.attach(&path))
super::tokio().block_on(workspace.attach_buffer(&path))
}
/// Detach from a buffer.
#[jni(package = "mp.code", class = "Workspace")]
fn detach_from_buffer(workspace: &mut Workspace, path: String) -> bool {
workspace.detach(&path)
fn detach_buffer(workspace: &mut Workspace, path: String) -> bool {
workspace.detach_buffer(&path)
}
/// Update the local buffer list.
#[jni(package = "mp.code", class = "Workspace")]
fn fetch_buffers(workspace: &mut Workspace) -> Result<(), RemoteError> {
fn fetch_buffers(workspace: &mut Workspace) -> Result<Vec<String>, RemoteError> {
super::tokio().block_on(workspace.fetch_buffers())
}
/// Update the local user list.
#[jni(package = "mp.code", class = "Workspace")]
fn fetch_users(workspace: &mut Workspace) -> Result<(), RemoteError> {
fn fetch_users(workspace: &mut Workspace) -> Result<Vec<User>, RemoteError> {
super::tokio().block_on(workspace.fetch_users())
}
/// List users attached to a buffer.
/// Fetch users attached to a buffer.
#[jni(package = "mp.code", class = "Workspace")]
fn list_buffer_users(
fn fetch_buffer_users(
workspace: &mut Workspace,
path: String,
) -> Result<Vec<crate::api::User>, RemoteError> {
super::tokio().block_on(workspace.list_buffer_users(&path))
super::tokio().block_on(workspace.fetch_buffer_users(&path))
}
/// Delete a buffer.
#[jni(package = "mp.code", class = "Workspace")]
fn delete_buffer(workspace: &mut Workspace, path: String) -> Result<(), RemoteError> {
super::tokio().block_on(workspace.delete(&path))
super::tokio().block_on(workspace.delete_buffer(&path))
}
/// Block and receive a workspace event.

View file

@ -32,13 +32,13 @@ impl BufferController {
}
/// Remove registered buffer callback
#[napi(js_name = "clear_callback")]
#[napi(js_name = "clearCallback")]
pub fn js_clear_callback(&self) {
self.clear_callback();
}
/// Get buffer path
#[napi(js_name = "get_path")]
#[napi(js_name = "path")]
pub fn js_path(&self) -> &str {
self.path()
}
@ -50,7 +50,7 @@ impl BufferController {
}
/// Return next buffer event if present
#[napi(js_name = "try_recv")]
#[napi(js_name = "tryRecv")]
pub async fn js_try_recv(&self) -> napi::Result<Option<BufferUpdate>> {
Ok(self.try_recv().await?)
}

View file

@ -34,29 +34,31 @@ pub async fn connect(config: crate::api::Config) -> napi::Result<crate::Client>
#[napi]
impl Client {
#[napi(js_name = "create_workspace")]
#[napi(js_name = "createWorkspace")]
/// create workspace with given id, if able to
pub async fn js_create_workspace(&self, workspace: String) -> napi::Result<()> {
Ok(self.create_workspace(workspace).await?)
}
#[napi(js_name = "delete_workspace")]
#[napi(js_name = "deleteWorkspace")]
/// delete workspace with given id, if able to
pub async fn js_delete_workspace(&self, workspace: String) -> napi::Result<()> {
Ok(self.delete_workspace(workspace).await?)
}
#[napi(js_name = "list_workspaces")]
/// list available workspaces
pub async fn js_list_workspaces(
&self,
owned: bool,
invited: bool,
) -> napi::Result<Vec<String>> {
Ok(self.list_workspaces(owned, invited).await?)
#[napi(js_name = "fetchOwnedWorkspaces")]
/// fetch owned workspaces
pub async fn js_fetch_owned_workspaces(&self) -> napi::Result<Vec<String>> {
Ok(self.fetch_owned_workspaces().await?)
}
#[napi(js_name = "invite_to_workspace")]
#[napi(js_name = "fetchJoinedWorkspaces")]
/// fetch joined workspaces
pub async fn js_fetch_joined_workspaces(&self) -> napi::Result<Vec<String>> {
Ok(self.fetch_joined_workspaces().await?)
}
#[napi(js_name = "inviteToWorkspace")]
/// invite user to given workspace, if able to
pub async fn js_invite_to_workspace(
&self,
@ -66,31 +68,31 @@ impl Client {
Ok(self.invite_to_workspace(workspace, user).await?)
}
#[napi(js_name = "join_workspace")]
#[napi(js_name = "attachWorkspace")]
/// join workspace with given id (will start its cursor controller)
pub async fn js_join_workspace(&self, workspace: String) -> napi::Result<Workspace> {
Ok(self.join_workspace(workspace).await?)
pub async fn js_attach_workspace(&self, workspace: String) -> napi::Result<Workspace> {
Ok(self.attach_workspace(workspace).await?)
}
#[napi(js_name = "leave_workspace")]
#[napi(js_name = "leaveWorkspace")]
/// leave workspace and disconnect, returns true if workspace was active
pub async fn js_leave_workspace(&self, workspace: String) -> bool {
self.leave_workspace(&workspace)
}
#[napi(js_name = "get_workspace")]
#[napi(js_name = "getWorkspace")]
/// get workspace with given id, if it exists
pub fn js_get_workspace(&self, workspace: String) -> Option<Workspace> {
self.get_workspace(&workspace)
}
#[napi(js_name = "user")]
#[napi(js_name = "currentUser")]
/// return current sessions's user id
pub fn js_user(&self) -> JsUser {
self.user().clone().into()
pub fn js_current_user(&self) -> JsUser {
self.current_user().clone().into()
}
#[napi(js_name = "active_workspaces")]
#[napi(js_name = "activeWorkspaces")]
/// get list of all active workspaces
pub fn js_active_workspaces(&self) -> Vec<String> {
self.active_workspaces()

View file

@ -32,7 +32,7 @@ impl CursorController {
}
/// Clear the registered callback
#[napi(js_name = "clear_callback")]
#[napi(js_name = "clearCallback")]
pub fn js_clear_callback(&self) {
self.clear_callback();
}
@ -44,7 +44,7 @@ impl CursorController {
}
/// Get next cursor event if available without blocking
#[napi(js_name = "try_recv")]
#[napi(js_name = "tryRecv")]
pub async fn js_try_recv(&self) -> napi::Result<Option<crate::api::Cursor>> {
Ok(self.try_recv().await?.map(crate::api::Cursor::from))
}

View file

@ -8,6 +8,8 @@ use napi::threadsafe_function::{
};
use napi_derive::napi;
use super::client::JsUser;
#[napi(object, js_name = "Event")]
pub struct JsEvent {
pub r#type: String,
@ -17,15 +19,15 @@ pub struct JsEvent {
impl From<crate::api::Event> for JsEvent {
fn from(value: crate::api::Event) -> Self {
match value {
crate::api::Event::FileTreeUpdated(value) => Self {
crate::api::Event::FileTreeUpdated { path: value } => Self {
r#type: "filetree".into(),
value,
},
crate::api::Event::UserJoin(value) => Self {
crate::api::Event::UserJoin { name: value } => Self {
r#type: "join".into(),
value,
},
crate::api::Event::UserLeave(value) => Self {
crate::api::Event::UserLeave { name: value } => Self {
r#type: "leave".into(),
value,
},
@ -42,21 +44,21 @@ impl Workspace {
}
/// List all available buffers in this workspace
#[napi(js_name = "filetree")]
pub fn js_filetree(&self, filter: Option<&str>, strict: bool) -> Vec<String> {
self.filetree(filter, strict)
#[napi(js_name = "searchBuffers")]
pub fn js_search_buffers(&self, filter: Option<&str>) -> Vec<String> {
self.search_buffers(filter)
}
/// List all user names currently in this workspace
#[napi(js_name = "user_list")]
pub fn js_user_list(&self) -> Vec<String> {
self.user_list()
#[napi(js_name = "userList")]
pub fn js_user_list(&self) -> Vec<JsUser> {
self.user_list().into_iter().map(JsUser::from).collect()
}
/// List all currently active buffers
#[napi(js_name = "buffer_list")]
pub fn js_buffer_list(&self) -> Vec<String> {
self.buffer_list()
#[napi(js_name = "activeBuffers")]
pub fn js_active_buffers(&self) -> Vec<String> {
self.active_buffers()
}
/// Get workspace's Cursor Controller
@ -66,27 +68,27 @@ impl Workspace {
}
/// Get a buffer controller by its name (path)
#[napi(js_name = "buffer_by_name")]
pub fn js_buffer_by_name(&self, path: String) -> Option<BufferController> {
self.buffer_by_name(&path)
#[napi(js_name = "getBuffer")]
pub fn js_get_buffer(&self, path: String) -> Option<BufferController> {
self.get_buffer(&path)
}
/// Create a new buffer in the current workspace
#[napi(js_name = "create")]
pub async fn js_create(&self, path: String) -> napi::Result<()> {
Ok(self.create(&path).await?)
#[napi(js_name = "createBuffer")]
pub async fn js_create_buffer(&self, path: String) -> napi::Result<()> {
Ok(self.create_buffer(&path).await?)
}
/// Attach to a workspace buffer, starting a BufferController
#[napi(js_name = "attach")]
pub async fn js_attach(&self, path: String) -> napi::Result<BufferController> {
Ok(self.attach(&path).await?)
#[napi(js_name = "attachBuffer")]
pub async fn js_attach_buffer(&self, path: String) -> napi::Result<BufferController> {
Ok(self.attach_buffer(&path).await?)
}
/// Delete a buffer from workspace
#[napi(js_name = "delete")]
pub async fn js_delete(&self, path: String) -> napi::Result<()> {
Ok(self.delete(&path).await?)
#[napi(js_name = "deleteBuffer")]
pub async fn js_delete_buffer(&self, path: String) -> napi::Result<()> {
Ok(self.delete_buffer(&path).await?)
}
#[napi(js_name = "recv")]
@ -94,7 +96,7 @@ impl Workspace {
Ok(JsEvent::from(self.recv().await?))
}
#[napi(js_name = "try_recv")]
#[napi(js_name = "tryRecv")]
pub async fn js_try_recv(&self) -> napi::Result<Option<JsEvent>> {
Ok(self.try_recv().await?.map(JsEvent::from))
}
@ -105,7 +107,7 @@ impl Workspace {
Ok(())
}
#[napi(js_name = "clear_callback")]
#[napi(js_name = "clearCallback")]
pub fn js_clear_callback(&self) -> napi::Result<()> {
self.clear_callback();
Ok(())
@ -128,30 +130,35 @@ impl Workspace {
/// Detach from an active buffer, stopping its underlying worker
/// this method returns true if no reference or last reference was held, false if there are still
/// dangling references to clear
#[napi(js_name = "detach")]
pub async fn js_detach(&self, path: String) -> bool {
self.detach(&path)
#[napi(js_name = "detachBuffer")]
pub async fn js_detach_buffer(&self, path: String) -> bool {
self.detach_buffer(&path)
}
/// Re-fetch remote buffer list
#[napi(js_name = "fetch_buffers")]
pub async fn js_fetch_buffers(&self) -> napi::Result<()> {
#[napi(js_name = "fetchBuffers")]
pub async fn js_fetch_buffers(&self) -> napi::Result<Vec<String>> {
Ok(self.fetch_buffers().await?)
}
/// Re-fetch the list of all users in the workspace.
#[napi(js_name = "fetch_users")]
pub async fn js_fetch_users(&self) -> napi::Result<()> {
Ok(self.fetch_users().await?)
#[napi(js_name = "fetchUsers")]
pub async fn js_fetch_users(&self) -> napi::Result<Vec<JsUser>> {
Ok(self
.fetch_users()
.await?
.into_iter()
.map(JsUser::from)
.collect())
}
/// List users attached to a specific buffer
#[napi(js_name = "list_buffer_users")]
pub async fn js_list_buffer_users(
#[napi(js_name = "fetchBufferUsers")]
pub async fn js_fetch_buffer_users(
&self,
path: String,
) -> napi::Result<Vec<crate::ffi::js::client::JsUser>> {
Ok(self
.list_buffer_users(&path)
.fetch_buffer_users(&path)
.await?
.into_iter()
.map(super::client::JsUser::from)

View file

@ -3,7 +3,8 @@ use mlua::prelude::*;
use mlua_codemp_patch as mlua;
use super::ext::a_sync::a_sync;
use super::ext::from_lua_serde;
super::ext::impl_lua_serde! { CodempTextChange CodempBufferUpdate }
impl LuaUserData for CodempBufferController {
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
@ -38,36 +39,3 @@ impl LuaUserData for CodempBufferController {
});
}
}
from_lua_serde! { CodempTextChange }
impl LuaUserData for CodempTextChange {
fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("content", |_, this| Ok(this.content.clone()));
fields.add_field_method_get("start", |_, this| Ok(this.start));
fields.add_field_method_get("end", |_, this| Ok(this.end));
// add a 'finish' accessor too because in Lua 'end' is reserved
fields.add_field_method_get("finish", |_, this| Ok(this.end));
}
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| {
Ok(format!("{:?}", this))
});
methods.add_method("apply", |_, this, (txt,): (String,)| Ok(this.apply(&txt)));
}
}
from_lua_serde! { CodempBufferUpdate }
impl LuaUserData for CodempBufferUpdate {
fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("hash", |_, this| Ok(this.hash));
fields.add_field_method_get("version", |_, this| Ok(this.version.clone()));
fields.add_field_method_get("change", |_, this| Ok(this.change.clone()));
}
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| {
Ok(format!("{:?}", this))
});
}
}

View file

@ -3,28 +3,30 @@ use mlua::prelude::*;
use mlua_codemp_patch as mlua;
use super::ext::a_sync::a_sync;
use super::ext::from_lua_serde;
super::ext::impl_lua_serde! { CodempConfig CodempUser }
impl LuaUserData for CodempClient {
fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("id", |_, this| Ok(this.user().id.to_string()));
fields.add_field_method_get("username", |_, this| Ok(this.user().name.clone()));
fields.add_field_method_get("active_workspaces", |_, this| Ok(this.active_workspaces()));
}
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| {
Ok(format!("{:?}", this))
});
methods.add_method("current_user", |_, this, ()| {
Ok(this.current_user().clone())
});
methods.add_method("active_workspaces", |_, this, ()| {
Ok(this.active_workspaces())
});
methods.add_method(
"refresh",
|_, this, ()| a_sync! { this => this.refresh().await? },
);
methods.add_method(
"join_workspace",
|_, this, (ws,): (String,)| a_sync! { this => this.join_workspace(ws).await? },
"attach_workspace",
|_, this, (ws,): (String,)| a_sync! { this => this.attach_workspace(ws).await? },
);
methods.add_method(
@ -41,8 +43,14 @@ impl LuaUserData for CodempClient {
a_sync! { this => this.invite_to_workspace(ws, user).await? }
);
methods.add_method("list_workspaces", |_, this, (owned,invited):(Option<bool>,Option<bool>)|
a_sync! { this => this.list_workspaces(owned.unwrap_or(true), invited.unwrap_or(true)).await? }
methods.add_method(
"fetch_owned_workspaces",
|_, this, ()| a_sync! { this => this.fetch_owned_workspaces().await? },
);
methods.add_method(
"fetch_joined_workspaces",
|_, this, ()| a_sync! { this => this.fetch_joined_workspaces().await? },
);
methods.add_method("leave_workspace", |_, this, (ws,): (String,)| {
@ -54,14 +62,3 @@ impl LuaUserData for CodempClient {
});
}
}
from_lua_serde! { CodempConfig }
impl LuaUserData for CodempConfig {
fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("username", |_, this| Ok(this.username.clone()));
fields.add_field_method_get("password", |_, this| Ok(this.password.clone()));
fields.add_field_method_get("host", |_, this| Ok(this.host.clone()));
fields.add_field_method_get("port", |_, this| Ok(this.port));
fields.add_field_method_get("tls", |_, this| Ok(this.tls));
}
}

View file

@ -3,7 +3,8 @@ use mlua::prelude::*;
use mlua_codemp_patch as mlua;
use super::ext::a_sync::a_sync;
use super::ext::from_lua_serde;
super::ext::impl_lua_serde! { CodempCursor CodempSelection }
impl LuaUserData for CodempCursorController {
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
@ -29,34 +30,3 @@ impl LuaUserData for CodempCursorController {
});
}
}
from_lua_serde! { CodempCursor }
impl LuaUserData for CodempCursor {
fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("user", |_, this| Ok(this.user.clone()));
fields.add_field_method_get("sel", |_, this| Ok(this.sel.clone()));
}
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| {
Ok(format!("{:?}", this))
});
}
}
from_lua_serde! { CodempSelection }
impl LuaUserData for CodempSelection {
fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("buffer", |_, this| Ok(this.buffer.clone()));
fields.add_field_method_get("start_row", |_, this| Ok(this.start_row));
fields.add_field_method_get("start_col", |_, this| Ok(this.start_col));
fields.add_field_method_get("end_row", |_, this| Ok(this.end_row));
fields.add_field_method_get("end_col", |_, this| Ok(this.end_col));
}
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| {
Ok(format!("{:?}", this))
});
}
}

View file

@ -101,6 +101,7 @@ macro_rules! callback_args {
callback_args! {
Str: String,
VecStr: Vec<String>,
VecUser: Vec<CodempUser>,
Client: CodempClient,
CursorController: CodempCursorController,
BufferController: CodempBufferController,

View file

@ -5,7 +5,7 @@ pub mod log;
pub(crate) use a_sync::tokio;
pub(crate) use callback::callback;
macro_rules! from_lua_serde {
macro_rules! impl_lua_serde {
($($t:ty)*) => {
$(
impl FromLua for $t {
@ -13,8 +13,14 @@ macro_rules! from_lua_serde {
lua.from_value(value)
}
}
impl IntoLua for $t {
fn into_lua(self, lua: &Lua) -> LuaResult<LuaValue> {
lua.to_value(&self)
}
}
)*
};
}
pub(crate) use from_lua_serde;
pub(crate) use impl_lua_serde;

View file

@ -3,7 +3,8 @@ use mlua::prelude::*;
use mlua_codemp_patch as mlua;
use super::ext::a_sync::a_sync;
use super::ext::from_lua_serde;
super::ext::impl_lua_serde! { CodempEvent }
impl LuaUserData for CodempWorkspace {
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
@ -11,26 +12,26 @@ impl LuaUserData for CodempWorkspace {
Ok(format!("{:?}", this))
});
methods.add_method(
"create",
|_, this, (name,): (String,)| a_sync! { this => this.create(&name).await? },
"create_buffer",
|_, this, (name,): (String,)| a_sync! { this => this.create_buffer(&name).await? },
);
methods.add_method(
"attach",
|_, this, (name,): (String,)| a_sync! { this => this.attach(&name).await? },
"attach_buffer",
|_, this, (name,): (String,)| a_sync! { this => this.attach_buffer(&name).await? },
);
methods.add_method("detach", |_, this, (name,): (String,)| {
Ok(this.detach(&name))
methods.add_method("detach_buffer", |_, this, (name,): (String,)| {
Ok(this.detach_buffer(&name))
});
methods.add_method(
"delete",
|_, this, (name,): (String,)| a_sync! { this => this.delete(&name).await? },
"delete_buffer",
|_, this, (name,): (String,)| a_sync! { this => this.delete_buffer(&name).await? },
);
methods.add_method("get_buffer", |_, this, (name,): (String,)| {
Ok(this.buffer_by_name(&name))
Ok(this.get_buffer(&name))
});
methods.add_method(
@ -42,13 +43,19 @@ impl LuaUserData for CodempWorkspace {
|_, this, ()| a_sync! { this => this.fetch_users().await? },
);
methods.add_method(
"filetree",
|_, this, (filter, strict): (Option<String>, Option<bool>)| {
Ok(this.filetree(filter.as_deref(), strict.unwrap_or(false)))
},
);
methods.add_method("search_buffers", |_, this, (filter,): (Option<String>,)| {
Ok(this.search_buffers(filter.as_deref()))
});
methods.add_method("fetch_buffer_users", |_, this, (path,): (String,)| {
a_sync! {
this => this.fetch_buffer_users(&path).await?
}
});
methods.add_method("id", |_, this, ()| Ok(this.id()));
methods.add_method("cursor", |_, this, ()| Ok(this.cursor()));
methods.add_method("active_buffers", |_, this, ()| Ok(this.active_buffers()));
methods.add_method("user_list", |_, this, ()| Ok(this.user_list()));
methods.add_method("recv", |_, this, ()| a_sync! { this => this.recv().await? });
@ -68,33 +75,4 @@ impl LuaUserData for CodempWorkspace {
methods.add_method("clear_callback", |_, this, ()| Ok(this.clear_callback()));
}
fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("name", |_, this| Ok(this.id()));
fields.add_field_method_get("cursor", |_, this| Ok(this.cursor()));
fields.add_field_method_get("active_buffers", |_, this| Ok(this.buffer_list()));
// fields.add_field_method_get("users", |_, this| Ok(this.0.users())); // TODO
}
}
from_lua_serde! { CodempEvent }
impl LuaUserData for CodempEvent {
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| {
Ok(format!("{:?}", this))
});
}
fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("type", |_, this| match this {
CodempEvent::FileTreeUpdated(_) => Ok("filetree"),
CodempEvent::UserJoin(_) => Ok("join"),
CodempEvent::UserLeave(_) => Ok("leave"),
});
fields.add_field_method_get("value", |_, this| match this {
CodempEvent::FileTreeUpdated(x)
| CodempEvent::UserJoin(x)
| CodempEvent::UserLeave(x) => Ok(x.clone()),
});
}
}

View file

@ -13,15 +13,15 @@
//!
//! // create and join a workspace
//! client.create_workspace("some-workspace").await?;
//! let workspace = client.join_workspace("some-workspace").await?;
//! let workspace = client.attach_workspace("some-workspace").await?;
//!
//! // create a new buffer in this workspace and attach to it
//! workspace.create("/my/file.txt").await?;
//! let buffer = workspace.attach("/my/file.txt").await?;
//! workspace.create_buffer("/my/file.txt").await?;
//! let buffer = workspace.attach_buffer("/my/file.txt").await?;
//!
//! // write `hello!` at the beginning of this buffer
//! buffer.send(codemp::api::TextChange {
//! start: 0, end: 0,
//! start_idx: 0, end_idx: 0,
//! content: "hello!".to_string(),
//! })?;
//!
@ -49,16 +49,16 @@
//! });
//!
//! // create and join a workspace
//! await client.create_workspace("some-workspace");
//! let workspace = await client.join_workspace("some-workspace");
//! await client.createWorkspace("some-workspace");
//! let workspace = await client.attachWorkspace("some-workspace");
//!
//! // create a new buffer in this workspace and attach to it
//! await workspace.create("/my/file.txt");
//! let buffer = await workspace.attach("/my/file.txt");
//! await workspace.createBuffer("/my/file.txt");
//! let buffer = await workspace.attachBuffer("/my/file.txt");
//!
//! // write `hello!` at the beginning of this buffer
//! await buffer.send({
//! start: 0, end: 0,
//! start_idx: 0, end_idx: 0,
//! content: "hello!",
//! });
//!
@ -80,28 +80,29 @@
//! import codemp
//!
//! # connect first, api.code.mp is managed by hexed.technology
//! config = codemp.get_default_config()
//! config.username = "mail@example.net"
//! config.password = "dont-use-this-password"
//! client = codemp.connect(config).wait()
//! client = codemp.connect(
//! codemp.Config('mail@example.net', 'dont-use-this-password')
//! ).wait()
//!
//! # create and join a workspace
//! client.create_workspace("some-workspace").wait()
//! workspace = client.join_workspace("some-workspace").wait()
//! workspace = client.attach_workspace("some-workspace").wait()
//!
//! # create a new buffer in this workspace and attach to it
//! workspace.create("/my/file.txt").wait()
//! buffer = workspace.attach("/my/file.txt").wait()
//! buffer = workspace.attach_buffer("/my/file.txt").wait()
//!
//! # write `hello!` at the beginning of this buffer
//! buffer.send(
//! 0, 0, "hello!"
//! ).wait()
//! buffer.send(codemp.TextChange(
//! start_idx=0, end_idx=0,
//! content="hello!"
//! )).wait()
//!
//! # wait for cursor movements
//! while true:
//! event = workspace.cursor().recv().wait()
//! print(f"user {event.user} moved on buffer {event.buffer}")
//!
//! ```
//!
//! ## Lua
@ -132,7 +133,7 @@
//!
//! -- create and join a workspace
//! client:create_workspace("my-workspace"):await()
//! local workspace = client:join_workspace("my-workspace"):await()
//! local workspace = client:attach_workspace("my-workspace"):await()
//!
//! -- create a new buffer in this workspace and attach to it
//! workspace:create_buffer("/my/file.txt"):await()
@ -140,7 +141,7 @@
//!
//! -- write `hello!` at the beginning of this buffer
//! buffer:send({
//! start = 0, finish = 0,
//! start_idx = 0, end_idx = 0,
//! content = "hello!"
//! }):await()
//!
@ -170,11 +171,11 @@
//!
//! // create and join a workspace
//! client.createWorkspace("some-workspace");
//! Workspace workspace = client.joinWorkspace("some-workspace");
//! Workspace workspace = client.attachWorkspace("some-workspace");
//!
//! // create a new buffer in this workspace and attach to it
//! workspace.createBuffer("/my/file.txt");
//! BufferController buffer = workspace.attachToBuffer("/my/file.txt");
//! BufferController buffer = workspace.attachBuffer("/my/file.txt");
//!
//! // write `hello!` at the beginning of this buffer
//! buffer.send(new data.TextChange(
@ -184,7 +185,7 @@
//!
//! // wait for cursor movements
//! while (true) {
//! data.Cursor event = workspace.getCursor().recv();
//! data.Cursor event = workspace.cursor().recv();
//! System.out.printf("user %s moved on buffer %s\n", event.user, event.buffer);
//! }
//! ```

View file

@ -1,5 +1,6 @@
use super::a_sync_allow_threads;
use super::Client;
use crate::api::User;
use crate::workspace::Workspace;
use pyo3::prelude::*;
@ -14,11 +15,11 @@ impl Client {
// super::tokio().block_on(Client::connect(host, username, password))
// }
#[pyo3(name = "join_workspace")]
fn pyjoin_workspace(&self, py: Python<'_>, workspace: String) -> PyResult<super::Promise> {
#[pyo3(name = "attach_workspace")]
fn pyattach_workspace(&self, py: Python<'_>, workspace: String) -> PyResult<super::Promise> {
tracing::info!("attempting to join the workspace {}", workspace);
let this = self.clone();
a_sync_allow_threads!(py, this.join_workspace(workspace).await)
a_sync_allow_threads!(py, this.attach_workspace(workspace).await)
// let this = self.clone();
// Ok(super::Promise(Some(tokio().spawn(async move {
// Ok(this
@ -54,16 +55,18 @@ impl Client {
a_sync_allow_threads!(py, this.invite_to_workspace(workspace, user).await)
}
#[pyo3(name = "list_workspaces")]
fn pylist_workspaces(
&self,
py: Python<'_>,
owned: bool,
invited: bool,
) -> PyResult<super::Promise> {
tracing::info!("attempting to list workspaces");
#[pyo3(name = "fetch_owned_workspaces")]
fn pyfetch_owned_workspaces(&self, py: Python<'_>) -> PyResult<super::Promise> {
tracing::info!("attempting to fetch owned workspaces");
let this = self.clone();
a_sync_allow_threads!(py, this.list_workspaces(owned, invited).await)
a_sync_allow_threads!(py, this.fetch_owned_workspaces().await)
}
#[pyo3(name = "fetch_joined_workspaces")]
fn pyfetch_joined_workspaces(&self, py: Python<'_>) -> PyResult<super::Promise> {
tracing::info!("attempting to fetch joined workspaces");
let this = self.clone();
a_sync_allow_threads!(py, this.fetch_joined_workspaces().await)
}
#[pyo3(name = "leave_workspace")]
@ -82,14 +85,9 @@ impl Client {
self.active_workspaces()
}
#[pyo3(name = "user_id")]
fn pyuser_id(&self) -> String {
self.user().id.to_string()
}
#[pyo3(name = "user_name")]
fn pyuser_name(&self) -> String {
self.user().name.clone()
#[pyo3(name = "current_user")]
fn pycurrent_user(&self) -> User {
self.current_user().clone()
}
#[pyo3(name = "refresh")]

View file

@ -13,22 +13,8 @@ use super::Promise;
#[pymethods]
impl CursorController {
#[pyo3(name = "send")]
fn pysend(
&self,
_py: Python,
path: String,
start: (i32, i32),
end: (i32, i32),
) -> PyResult<()> {
let pos = Selection {
start_row: start.0,
start_col: start.1,
end_row: end.0,
end_col: end.1,
buffer: path,
};
let this = self.clone();
this.send(pos)?;
fn pysend(&self, _py: Python, pos: Selection) -> PyResult<()> {
self.send(pos)?;
Ok(())
}
@ -86,12 +72,7 @@ impl BufferController {
}
#[pyo3(name = "send")]
fn pysend(&self, _py: Python, start: u32, end: u32, txt: String) -> PyResult<()> {
let op = TextChange {
start,
end,
content: txt,
};
fn pysend(&self, _py: Python, op: TextChange) -> PyResult<()> {
let this = self.clone();
this.send(op)?;
Ok(())

View file

@ -3,15 +3,15 @@ pub mod controllers;
pub mod workspace;
use crate::{
api::{Config, Cursor, TextChange},
api::{BufferUpdate, Config, Cursor, Selection, TextChange, User},
buffer::Controller as BufferController,
cursor::Controller as CursorController,
Client, Workspace,
};
use pyo3::prelude::*;
use pyo3::{
exceptions::{PyConnectionError, PyRuntimeError, PySystemError},
prelude::*,
types::PyDict,
};
@ -153,13 +153,37 @@ fn init() -> PyResult<Driver> {
Ok(Driver(Some(rt_stop_tx)))
}
#[pyfunction]
fn get_default_config() -> crate::api::Config {
let mut conf = crate::api::Config::new("".to_string(), "".to_string());
conf.host = Some(conf.host().to_string());
conf.port = Some(conf.port());
conf.tls = Some(false);
conf
#[pymethods]
impl User {
#[getter]
fn get_id(&self) -> pyo3::PyResult<String> {
Ok(self.id.to_string())
}
#[setter]
fn set_id(&mut self, value: String) -> pyo3::PyResult<()> {
self.id = value
.parse()
.map_err(|x: <uuid::Uuid as std::str::FromStr>::Err| {
pyo3::exceptions::PyRuntimeError::new_err(x.to_string())
})?;
Ok(())
}
#[getter]
fn get_name(&self) -> pyo3::PyResult<String> {
Ok(self.name.clone())
}
#[setter]
fn set_name(&mut self, value: String) -> pyo3::PyResult<()> {
self.name = value;
Ok(())
}
fn __str__(&self) -> String {
format!("{self:?}")
}
}
#[pymethods]
@ -176,7 +200,7 @@ impl Config {
let port = kwgs.get_item("port")?.and_then(|e| e.extract().ok());
let tls = kwgs.get_item("tls")?.and_then(|e| e.extract().ok());
Ok(Config {
Ok(Self {
username,
password,
host,
@ -184,9 +208,119 @@ impl Config {
tls,
})
} else {
Ok(Config::new(username, password))
Ok(Self::new(username, password))
}
}
fn __str__(&self) -> String {
format!("{self:?}")
}
}
#[pymethods]
impl Cursor {
fn __str__(&self) -> String {
format!("{self:?}")
}
}
#[pymethods]
impl Selection {
#[new]
#[pyo3(signature = (**kwds))]
pub fn py_new(kwds: Option<&Bound<'_, PyDict>>) -> PyResult<Self> {
if let Some(kwds) = kwds {
let start_row = if let Some(e) = kwds.get_item("start_row")? {
e.extract()?
} else {
0
};
let start_col = if let Some(e) = kwds.get_item("start_col")? {
e.extract()?
} else {
0
};
let end_row = if let Some(e) = kwds.get_item("end_row")? {
e.extract()?
} else {
0
};
let end_col = if let Some(e) = kwds.get_item("end_col")? {
e.extract()?
} else {
0
};
let buffer = if let Some(e) = kwds.get_item("buffer")? {
e.extract()?
} else {
String::default()
};
Ok(Self {
start_row,
start_col,
end_row,
end_col,
buffer,
})
} else {
Ok(Self::default())
}
}
fn __str__(&self) -> String {
format!("{self:?}")
}
}
#[pymethods]
impl BufferUpdate {
fn __str__(&self) -> String {
format!("{self:?}")
}
}
#[pymethods]
impl TextChange {
#[new]
#[pyo3(signature = (**kwds))]
pub fn py_new(kwds: Option<&Bound<'_, PyDict>>) -> PyResult<Self> {
if let Some(kwds) = kwds {
let start_idx = if let Some(e) = kwds.get_item("start")? {
e.extract()?
} else {
0
};
let end_idx = if let Some(e) = kwds.get_item("end")? {
e.extract()?
} else {
0
};
let content = if let Some(e) = kwds.get_item("content")? {
e.extract()?
} else {
String::default()
};
Ok(Self {
start_idx,
end_idx,
content,
})
} else {
Ok(Self::default())
}
}
fn __str__(&self) -> String {
format!("{self:?}")
}
}
#[pyfunction]
@ -254,27 +388,24 @@ impl From<crate::errors::ControllerError> for PyErr {
}
}
impl IntoPy<PyObject> for crate::api::User {
fn into_py(self, py: Python<'_>) -> PyObject {
self.id.to_string().into_py(py)
}
}
#[pymodule]
fn codemp(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(version, m)?)?;
m.add_function(wrap_pyfunction!(init, m)?)?;
m.add_function(wrap_pyfunction!(get_default_config, m)?)?;
m.add_function(wrap_pyfunction!(connect, m)?)?;
m.add_function(wrap_pyfunction!(set_logger, m)?)?;
m.add_class::<Driver>()?;
m.add_class::<BufferUpdate>()?;
m.add_class::<TextChange>()?;
m.add_class::<BufferController>()?;
m.add_class::<Cursor>()?;
m.add_class::<Selection>()?;
m.add_class::<CursorController>()?;
m.add_class::<User>()?;
m.add_class::<Workspace>()?;
m.add_class::<Client>()?;
m.add_class::<Config>()?;

View file

@ -1,4 +1,5 @@
use crate::api::controller::AsyncReceiver;
use crate::api::User;
use crate::buffer::Controller as BufferController;
use crate::cursor::Controller as CursorController;
use crate::workspace::Workspace;
@ -11,21 +12,21 @@ use super::Promise;
#[pymethods]
impl Workspace {
// join a workspace
#[pyo3(name = "create")]
fn pycreate(&self, py: Python, path: String) -> PyResult<Promise> {
#[pyo3(name = "create_buffer")]
fn pycreate_buffer(&self, py: Python, path: String) -> PyResult<Promise> {
let this = self.clone();
a_sync_allow_threads!(py, this.create(path.as_str()).await)
a_sync_allow_threads!(py, this.create_buffer(path.as_str()).await)
}
#[pyo3(name = "attach")]
fn pyattach(&self, py: Python, path: String) -> PyResult<Promise> {
#[pyo3(name = "attach_buffer")]
fn pyattach_buffer(&self, py: Python, path: String) -> PyResult<Promise> {
let this = self.clone();
a_sync_allow_threads!(py, this.attach(path.as_str()).await)
a_sync_allow_threads!(py, this.attach_buffer(path.as_str()).await)
}
#[pyo3(name = "detach")]
fn pydetach(&self, path: String) -> bool {
self.detach(path.as_str())
#[pyo3(name = "detach_buffer")]
fn pydetach_buffer(&self, path: String) -> bool {
self.detach_buffer(path.as_str())
}
#[pyo3(name = "fetch_buffers")]
@ -40,17 +41,17 @@ impl Workspace {
a_sync_allow_threads!(py, this.fetch_users().await)
}
#[pyo3(name = "list_buffer_users")]
fn pylist_buffer_users(&self, py: Python, path: String) -> PyResult<Promise> {
#[pyo3(name = "fetch_buffer_users")]
fn pyfetch_buffer_users(&self, py: Python, path: String) -> PyResult<Promise> {
// crate::Result<Vec<crate::api::User>>
let this = self.clone();
a_sync_allow_threads!(py, this.list_buffer_users(path.as_str()).await)
a_sync_allow_threads!(py, this.fetch_buffer_users(path.as_str()).await)
}
#[pyo3(name = "delete")]
fn pydelete(&self, py: Python, path: String) -> PyResult<Promise> {
#[pyo3(name = "delete_buffer")]
fn pydelete_buffer(&self, py: Python, path: String) -> PyResult<Promise> {
let this = self.clone();
a_sync_allow_threads!(py, this.delete(path.as_str()).await)
a_sync_allow_threads!(py, this.delete_buffer(path.as_str()).await)
}
#[pyo3(name = "id")]
@ -63,24 +64,24 @@ impl Workspace {
self.cursor()
}
#[pyo3(name = "buffer_by_name")]
fn pybuffer_by_name(&self, path: String) -> Option<BufferController> {
self.buffer_by_name(path.as_str())
#[pyo3(name = "get_buffer")]
fn pyget_buffer(&self, path: String) -> Option<BufferController> {
self.get_buffer(path.as_str())
}
#[pyo3(name = "buffer_list")]
fn pybuffer_list(&self) -> Vec<String> {
self.buffer_list()
#[pyo3(name = "active_buffers")]
fn pyactive_buffers(&self) -> Vec<String> {
self.active_buffers()
}
#[pyo3(name = "filetree")]
#[pyo3(signature = (filter=None, strict=false))]
fn pyfiletree(&self, filter: Option<&str>, strict: bool) -> Vec<String> {
self.filetree(filter, strict)
#[pyo3(name = "search_buffers")]
#[pyo3(signature = (filter=None))]
fn pysearch_buffers(&self, filter: Option<&str>) -> Vec<String> {
self.search_buffers(filter)
}
#[pyo3(name = "user_list")]
fn pyuser_list(&self) -> Vec<String> {
fn pyuser_list(&self) -> Vec<User> {
self.user_list()
}

View file

@ -32,13 +32,13 @@
//! ```
//!
//! A [`Client`] can acquire a [`Workspace`] handle by joining an existing one it can access with
//! [`Client::join_workspace`] or create a new one with [`Client::create_workspace`].
//! [`Client::attach_workspace`] or create a new one with [`Client::create_workspace`].
//!
//! ```no_run
//! # async {
//! # let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap();
//! client.create_workspace("my-workspace").await.expect("failed to create workspace!");
//! let workspace = client.join_workspace("my-workspace").await.expect("failed to attach!");
//! let workspace = client.attach_workspace("my-workspace").await.expect("failed to attach!");
//! # };
//! ```
//!
@ -49,7 +49,7 @@
//! # async {
//! # let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap();
//! # client.create_workspace("").await.unwrap();
//! # let workspace = client.join_workspace("").await.unwrap();
//! # let workspace = client.attach_workspace("").await.unwrap();
//! use codemp::api::controller::{AsyncSender, AsyncReceiver}; // needed to access trait methods
//! let cursor = workspace.cursor();
//! let event = cursor.recv().await.expect("disconnected while waiting for event!");
@ -65,14 +65,14 @@
//! # async {
//! # let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap();
//! # client.create_workspace("").await.unwrap();
//! # let workspace = client.join_workspace("").await.unwrap();
//! # let workspace = client.attach_workspace("").await.unwrap();
//! # use codemp::api::controller::{AsyncSender, AsyncReceiver};
//! let buffer = workspace.attach("/some/file.txt").await.expect("failed to attach");
//! let buffer = workspace.attach_buffer("/some/file.txt").await.expect("failed to attach");
//! buffer.content(); // force-sync
//! if let Some(mut update) = buffer.try_recv().await.unwrap() {
//! println!(
//! "content: {}, span: {}-{}",
//! update.change.content, update.change.start, update.change.end
//! update.change.content, update.change.start_idx, update.change.end_idx
//! );
//! buffer.ack(update.version);
//! } // if None, no changes are currently available

View file

@ -2,7 +2,7 @@
//! All-in-one renamed imports with `use codemp::prelude::*`.
pub use crate::api::{
controller::AsyncReceiver as CodempAsyncReceiver, controller::AsyncSender as CodempAsyncSender,
AsyncReceiver as CodempAsyncReceiver, AsyncSender as CodempAsyncSender,
BufferUpdate as CodempBufferUpdate, Config as CodempConfig, Controller as CodempController,
Cursor as CodempCursor, Event as CodempEvent, Selection as CodempSelection,
TextChange as CodempTextChange, User as CodempUser,

View file

@ -26,7 +26,7 @@ use codemp_proto::{
};
use dashmap::{DashMap, DashSet};
use std::{collections::BTreeSet, sync::Arc};
use std::sync::Arc;
use tokio::sync::{mpsc, mpsc::error::TryRecvError};
use tonic::Streaming;
use uuid::Uuid;
@ -140,7 +140,7 @@ impl Workspace {
}
/// Create a new buffer in the current workspace.
pub async fn create(&self, path: &str) -> RemoteResult<()> {
pub async fn create_buffer(&self, path: &str) -> RemoteResult<()> {
let mut workspace_client = self.0.services.ws();
workspace_client
.create_buffer(tonic::Request::new(BufferNode {
@ -158,7 +158,7 @@ impl Workspace {
}
/// Attach to a buffer and return a handle to it.
pub async fn attach(&self, path: &str) -> ConnectionResult<buffer::Controller> {
pub async fn attach_buffer(&self, path: &str) -> ConnectionResult<buffer::Controller> {
let mut worskspace_client = self.0.services.ws();
let request = tonic::Request::new(BufferNode {
path: path.to_string(),
@ -190,7 +190,7 @@ impl Workspace {
/// If this method returns `false` you have a dangling ref, maybe just waiting for garbage
/// collection or maybe preventing the controller from being dropped completely
#[allow(clippy::redundant_pattern_matching)] // all cases are clearer this way
pub fn detach(&self, path: &str) -> bool {
pub fn detach_buffer(&self, path: &str) -> bool {
match self.0.buffers.remove(path) {
None => true, // noop: we werent attached in the first place
Some((_name, controller)) => match Arc::into_inner(controller.0) {
@ -201,45 +201,48 @@ impl Workspace {
}
/// Re-fetch the list of available buffers in the workspace.
pub async fn fetch_buffers(&self) -> RemoteResult<()> {
pub async fn fetch_buffers(&self) -> RemoteResult<Vec<String>> {
let mut workspace_client = self.0.services.ws();
let buffers = workspace_client
let resp = workspace_client
.list_buffers(tonic::Request::new(Empty {}))
.await?
.into_inner()
.buffers;
.into_inner();
let mut out = Vec::new();
self.0.filetree.clear();
for b in buffers {
self.0.filetree.insert(b.path);
for b in resp.buffers {
self.0.filetree.insert(b.path.clone());
out.push(b.path);
}
Ok(())
Ok(out)
}
/// Re-fetch the list of all users in the workspace.
pub async fn fetch_users(&self) -> RemoteResult<()> {
pub async fn fetch_users(&self) -> RemoteResult<Vec<User>> {
let mut workspace_client = self.0.services.ws();
let users = BTreeSet::from_iter(
workspace_client
let users = workspace_client
.list_users(tonic::Request::new(Empty {}))
.await?
.into_inner()
.users
.into_iter()
.map(User::from),
);
.map(User::from);
let mut result = Vec::new();
self.0.users.clear();
for u in users {
self.0.users.insert(u.id, u);
self.0.users.insert(u.id, u.clone());
result.push(u);
}
Ok(())
Ok(result)
}
/// Get a list of the [User]s attached to a specific buffer.
pub async fn list_buffer_users(&self, path: &str) -> RemoteResult<Vec<User>> {
/// Fetch a list of the [User]s attached to a specific buffer.
pub async fn fetch_buffer_users(&self, path: &str) -> RemoteResult<Vec<User>> {
let mut workspace_client = self.0.services.ws();
let buffer_users = workspace_client
.list_buffer_users(tonic::Request::new(BufferNode {
@ -256,8 +259,8 @@ impl Workspace {
}
/// Delete a buffer.
pub async fn delete(&self, path: &str) -> RemoteResult<()> {
self.detach(path); // just in case
pub async fn delete_buffer(&self, path: &str) -> RemoteResult<()> {
self.detach_buffer(path); // just in case
let mut workspace_client = self.0.services.ws();
workspace_client
@ -285,13 +288,13 @@ impl Workspace {
/// Return a handle to the [buffer::Controller] with the given path, if present.
// #[cfg_attr(feature = "js", napi)] // https://github.com/napi-rs/napi-rs/issues/1120
pub fn buffer_by_name(&self, path: &str) -> Option<buffer::Controller> {
pub fn get_buffer(&self, path: &str) -> Option<buffer::Controller> {
self.0.buffers.get(path).map(|x| x.clone())
}
/// Get a list of all the currently attached buffers.
// #[cfg_attr(feature = "js", napi)] // https://github.com/napi-rs/napi-rs/issues/1120
pub fn buffer_list(&self) -> Vec<String> {
pub fn active_buffers(&self) -> Vec<String> {
self.0
.buffers
.iter()
@ -300,31 +303,23 @@ impl Workspace {
}
/// Get all names of users currently in this workspace
pub fn user_list(&self) -> Vec<String> {
pub fn user_list(&self) -> Vec<User> {
self.0
.users
.iter()
.map(|elem| elem.value().name.clone())
.map(|elem| elem.value().clone())
.collect()
}
/// Get the filetree as it is currently cached.
/// A filter may be applied, and it may be strict (equality check) or not (starts_with check).
// #[cfg_attr(feature = "js", napi)] // https://github.com/napi-rs/napi-rs/issues/1120
pub fn filetree(&self, filter: Option<&str>, strict: bool) -> Vec<String> {
pub fn search_buffers(&self, filter: Option<&str>) -> Vec<String> {
let mut tree = self
.0
.filetree
.iter()
.filter(|f| {
filter.map_or(true, |flt| {
if strict {
f.as_str() == flt
} else {
f.starts_with(flt)
}
})
})
.filter(|f| filter.map_or(true, |flt| f.starts_with(flt)))
.map(|f| f.clone())
.collect::<Vec<String>>();
tree.sort();