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

View file

@ -51,7 +51,7 @@ napi = { version = "2.16", features = ["full"], optional = true }
napi-derive = { version="2.16", optional = true} napi-derive = { version="2.16", optional = true}
# glue (python) # glue (python)
pyo3 = { version = "0.22", features = ["extension-module"], optional = true} pyo3 = { version = "0.22", features = ["extension-module", "multiple-pymethods"], optional = true}
# extra # extra
async-trait = { version = "0.1", optional = true } 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; 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. * Gets information about the current user.
* @return a {@link User} object representing the user * @return a {@link User} object representing the user
*/ */
public User getUser() { public User currentUser() {
return get_user(this.ptr); 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. * Joins a {@link Workspace} and returns it.
@ -52,8 +52,8 @@ public final class Client {
* @return the relevant {@link Workspace} * @return the relevant {@link Workspace}
* @throws ConnectionException if an error occurs in communicating with the server * @throws ConnectionException if an error occurs in communicating with the server
*/ */
public Workspace joinWorkspace(String workspaceId) throws ConnectionException { public Workspace attachWorkspace(String workspaceId) throws ConnectionException {
return join_workspace(this.ptr, workspaceId); return attach_workspace(this.ptr, workspaceId);
} }
private static native void create_workspace(long self, String workspaceId) throws ConnectionRemoteException; 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); 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. * Lists workspaces owned by the current user.
* @param owned if owned workspaces should be included
* @param invited if workspaces the user is invited to should be included
* @return an array of workspace IDs * @return an array of workspace IDs
* @throws ConnectionRemoteException if an error occurs in communicating with the server * @throws ConnectionRemoteException if an error occurs in communicating with the server
*/ */
public String[] listWorkspaces(boolean owned, boolean invited) throws ConnectionRemoteException { public String[] fetchOwnedWorkspaces() throws ConnectionRemoteException {
return list_workspaces(this.ptr, owned, invited); 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); private static native String[] active_workspaces(long self);

View file

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

View file

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

View file

@ -158,16 +158,32 @@ function MaybeBufferUpdatePromise:cancel() end
---invoke callback asynchronously as soon as promise is ready ---invoke callback asynchronously as soon as promise is ready
function MaybeBufferUpdatePromise:and_then(cb) end 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 ]] -- [[ END ASYNC STUFF ]]
---@class (exact) Client ---@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 ---the effective local client, handling connecting to codemp server
local Client = {} 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 ---@return NilPromise
---@async ---@async
---@nodiscard ---@nodiscard
@ -179,7 +195,7 @@ function Client:refresh() end
---@async ---@async
---@nodiscard ---@nodiscard
---join requested workspace if possible and subscribe to event bus ---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 ---@param ws string workspace id to create
---@return NilPromise ---@return NilPromise
@ -207,13 +223,17 @@ function Client:delete_workspace(ws) end
---grant user acccess to workspace ---grant user acccess to workspace
function Client:invite_to_workspace(ws, user) end 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 ---@return StringArrayPromise
---@async ---@async
---@nodiscard ---@nodiscard
---grant user acccess to workspace ---fetch and list owned workspaces
function Client:list_workspaces(owned, invited) end 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 ---@param ws string workspace id to get
---@return Workspace? ---@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 ---@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 ---a joined codemp workspace
local 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 ---@param path string relative path ("name") of new buffer
---@return NilPromise ---@return NilPromise
---@async ---@async
---@nodiscard ---@nodiscard
---create a new empty buffer ---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 ---@param path string relative path ("name") of buffer to delete
---@return NilPromise ---@return NilPromise
---@async ---@async
---@nodiscard ---@nodiscard
---delete buffer from workspace ---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 ---@param path string relative path ("name") of buffer to get
---@return BufferController? ---@return BufferController?
@ -253,20 +288,19 @@ function Workspace:get_buffer(path) end
---@async ---@async
---@nodiscard ---@nodiscard
---attach to a remote buffer, synching content and changes and returning its controller ---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 ---@param path string relative path ("name") of buffer to detach from
---@return boolean success ---@return boolean success
---detach from an active buffer, closing all streams. returns false if there are still dangling references ---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 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 string[]
---return the list of available buffers in this workspace, as relative paths from workspace root ---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 ---return all names of users currently in this workspace
function Workspace:user_list() end function Workspace:user_list() end
@ -282,6 +316,13 @@ function Workspace:fetch_buffers(path) end
---force refresh users list from workspace ---force refresh users list from workspace
function Workspace:fetch_users(path) end 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 ---@class (exact) WorkspaceEvent
---@field type string ---@field type string
---@field value string ---@field value string
@ -320,8 +361,8 @@ local BufferController = {}
---@class TextChange ---@class TextChange
---@field content string text content of change ---@field content string text content of change
---@field start integer start index of change ---@field start_idx integer start index of change
---@field finish integer end index of change ---@field end_idx integer end index of change
local TextChange = {} local TextChange = {}
---@class (exact) BufferUpdate ---@class (exact) BufferUpdate

View file

@ -7,6 +7,13 @@ class Driver:
""" """
def stop(self) -> None: ... def stop(self) -> None: ...
class User:
"""
A remote user, with uuid and username
"""
id: str
name: str
class Config: class Config:
""" """
Configuration data structure for codemp clients Configuration data structure for codemp clients
@ -17,7 +24,7 @@ class Config:
port: Optional[int] port: Optional[int]
tls: Optional[bool] 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 init() -> Driver: ...
def set_logger(logger_cb: Callable[[str], None], debug: bool) -> bool: ... def set_logger(logger_cb: Callable[[str], None], debug: bool) -> bool: ...
@ -32,25 +39,25 @@ class Promise[T]:
It can either be used directly or you can wrap it inside a future python side. It can either be used directly or you can wrap it inside a future python side.
""" """
def wait(self) -> T: ... def wait(self) -> T: ...
def is_done(self) -> bool: ... def is_done(self) -> bool: ...
class Client: class Client:
""" """
Handle to the actual client that manages the session. It manages the connection Handle to the actual client that manages the session. It manages the connection
to a server and joining/creating new workspaces 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 create_workspace(self, workspace: str) -> Promise[None]: ...
def delete_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 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 leave_workspace(self, workspace: str) -> bool: ... def fetch_joined_workspaces(self) -> Promise[list[str]]: ...
def get_workspace(self, id: str) -> Workspace: ... def leave_workspace(self, workspace: str) -> bool: ...
def active_workspaces(self) -> list[str]: ... def get_workspace(self, id: str) -> Workspace: ...
def user_id(self) -> str: ... def active_workspaces(self) -> list[str]: ...
def user_name(self) -> str: ... def current_user(self) -> User: ...
def refresh(self) -> Promise[None]: ... def refresh(self) -> Promise[None]: ...
class Event: class Event:
pass pass
@ -60,22 +67,23 @@ class Workspace:
Handle to a workspace inside codemp. It manages buffers. Handle to a workspace inside codemp. It manages buffers.
A cursor is tied to the single workspace. A cursor is tied to the single workspace.
""" """
def create(self, path: str) -> Promise[None]: ... def create_buffer(self, path: str) -> Promise[None]: ...
def attach(self, path: str) -> Promise[BufferController]: ... def attach_buffer(self, path: str) -> Promise[BufferController]: ...
def detach(self, path: str) -> bool: ... def detach_buffer(self, path: str) -> bool: ...
def fetch_buffers(self) -> Promise[None]: ... def fetch_buffers(self) -> Promise[list[str]]: ...
def fetch_users(self) -> Promise[None]: ... def fetch_users(self) -> Promise[list[User]]: ...
def list_buffer_users(self, path: str) -> Promise[list[str]]: ... def fetch_buffer_users(self, path: str) -> Promise[list[User]]: ...
def delete(self, path: str) -> Promise[None]: ... def delete_buffer(self, path: str) -> Promise[None]: ...
def id(self) -> str: ... def id(self) -> str: ...
def cursor(self) -> CursorController: ... def cursor(self) -> CursorController: ...
def buffer_by_name(self, path: str) -> Optional[BufferController]: ... def get_buffer(self, path: str) -> Optional[BufferController]: ...
def buffer_list(self) -> list[str]: ... def user_list(self) -> list[User]: ...
def filetree(self, filter: Optional[str], strict: bool) -> list[str]: ... def active_buffers(self) -> list[str]: ...
def recv(self) -> Promise[Event]: ... def search_buffers(self, filter: Optional[str]) -> list[str]: ...
def try_recv(self) -> Promise[Optional[Event]]: ... def recv(self) -> Promise[Event]: ...
def poll(self) -> Promise[None]: ... def try_recv(self) -> Promise[Optional[Event]]: ...
def clear_callback(self) -> None: ... def poll(self) -> Promise[None]: ...
def clear_callback(self) -> None: ...
def callback(self, cb: Callable[[Workspace], None]) -> None: ... def callback(self, cb: Callable[[Workspace], None]) -> None: ...
class TextChange: class TextChange:
@ -87,10 +95,10 @@ class TextChange:
end: int end: int
content: str content: str
def is_delete(self) -> bool: ... def is_delete(self) -> bool: ...
def is_insert(self) -> bool: ... def is_insert(self) -> bool: ...
def is_empty(self) -> bool: ... def is_empty(self) -> bool: ...
def apply(self, txt: str) -> str: ... def apply(self, txt: str) -> str: ...
class BufferUpdate: class BufferUpdate:
""" """
@ -106,19 +114,16 @@ class BufferController:
Handle to the controller for a specific buffer, which manages the back and forth Handle to the controller for a specific buffer, which manages the back and forth
of operations to and from other peers. of operations to and from other peers.
""" """
def path(self) -> str: ... def path(self) -> str: ...
def content(self) -> Promise[str]: ... def content(self) -> Promise[str]: ...
def ack(self, v: list[int]) -> None: ... def ack(self, v: list[int]) -> None: ...
def send(self, def send(self, op: TextChange) -> None: ...
start: int, def try_recv(self) -> Promise[Optional[TextChange]]: ...
end: int, def recv(self) -> Promise[TextChange]: ...
txt: str) -> Promise[None]: ... def poll(self) -> Promise[None]: ...
def try_recv(self) -> Promise[Optional[TextChange]]: ...
def recv(self) -> Promise[TextChange]: ...
def poll(self) -> Promise[None]: ...
def callback(self, def callback(self,
cb: Callable[[BufferController], None]) -> None: ... cb: Callable[[BufferController], None]) -> None: ...
def clear_callback(self) -> None: ... def clear_callback(self) -> None: ...
@ -143,14 +148,11 @@ class CursorController:
Handle to the controller for a workspace, which manages the back and forth of Handle to the controller for a workspace, which manages the back and forth of
cursor movements to and from other peers cursor movements to and from other peers
""" """
def send(self, def send(self, pos: Selection) -> None: ...
path: str, def try_recv(self) -> Promise[Optional[Cursor]]: ...
start: Tuple[int, int], def recv(self) -> Promise[Cursor]: ...
end: Tuple[int, int]) -> Promise[None]: ... def poll(self) -> Promise[None]: ...
def try_recv(self) -> Promise[Optional[Cursor]]: ...
def recv(self) -> Promise[Cursor]: ...
def poll(self) -> Promise[None]: ...
def callback(self, def callback(self,
cb: Callable[[CursorController], None]) -> None: ... cb: Callable[[CursorController], None]) -> None: ...
def clear_callback(self) -> None: ... def clear_callback(self) -> None: ...

View file

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

View file

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

View file

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

View file

@ -6,6 +6,7 @@ use uuid::Uuid;
/// Represents a service user /// Represents a service user
#[derive(Debug, Clone)] #[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", derive(serde::Serialize, serde::Deserialize))]
pub struct User { pub struct User {
/// User unique identifier, should never change. /// 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>) { async fn handle_editor_change(&mut self, change: TextChange, tx: &mpsc::Sender<Operation>) {
let last_ver = self.oplog.local_version(); let last_ver = self.oplog.local_version();
// clip to buffer extents // clip to buffer extents
let clip_start = change.start as usize; let clip_start = change.start_idx as usize;
let mut clip_end = change.end as usize; let mut clip_end = change.end_idx as usize;
let b_len = self.branch.len(); let b_len = self.branch.len();
if clip_end > b_len { if clip_end > b_len {
tracing::warn!("clipping TextChange end span from {clip_end} to {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 // in case we have a "replace" span
if change.is_delete() { if change.is_delete() {
self.branch self.branch.delete_without_content(
.delete_without_content(&mut self.oplog, self.agent_id, clip_start..clip_end); &mut self.oplog,
self.agent_id,
clip_start..clip_end,
);
} }
if change.is_insert() { if change.is_insert() {
@ -247,7 +250,9 @@ impl BufferWorker {
{ {
tracing::warn!( tracing::warn!(
"Insert span ({}, {}) differs from effective content len ({})", "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 { crate::api::BufferUpdate {
@ -257,8 +262,8 @@ impl BufferWorker {
.map(|x| i64::from_ne_bytes(x.to_ne_bytes())) .map(|x| i64::from_ne_bytes(x.to_ne_bytes()))
.collect(), // TODO this is wasteful .collect(), // TODO this is wasteful
change: crate::api::TextChange { change: crate::api::TextChange {
start: dtop.start() as u32, start_idx: dtop.start() as u32,
end: dtop.start() as u32, end_idx: dtop.start() as u32,
content: dtop.content_as_str().unwrap_or_default().to_string(), 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())) .map(|x| i64::from_ne_bytes(x.to_ne_bytes()))
.collect(), // TODO this is wasteful .collect(), // TODO this is wasteful
change: crate::api::TextChange { change: crate::api::TextChange {
start: dtop.start() as u32, start_idx: dtop.start() as u32,
end: dtop.end() as u32, end_idx: dtop.end() as u32,
content: dtop.content_as_str().unwrap_or_default().to_string(), content: dtop.content_as_str().unwrap_or_default().to_string(),
}, },
}, },

View file

@ -130,9 +130,18 @@ impl Client {
Ok(()) Ok(())
} }
/// List all available workspaces, also filtering between those owned and those invited to. /// Fetch the names of all workspaces owned by the current user.
pub async fn list_workspaces(&self, owned: bool, invited: bool) -> RemoteResult<Vec<String>> { pub async fn fetch_owned_workspaces(&self) -> RemoteResult<Vec<String>> {
let mut workspaces = self 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 .0
.session .session
.clone() .clone()
@ -140,20 +149,18 @@ impl Client {
.await? .await?
.into_inner(); .into_inner();
let mut out = Vec::new();
if owned { 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`]. /// 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 let token = self
.0 .0
.session .session
@ -203,7 +210,7 @@ impl Client {
} }
/// Get the currently logged in user. /// Get the currently logged in user.
pub fn user(&self) -> &User { pub fn current_user(&self) -> &User {
&self.0.user &self.0.user
} }
} }

View file

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

View file

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

View file

@ -1,8 +1,5 @@
use crate::{ use crate::{
api::{ api::{AsyncReceiver, AsyncSender, Cursor, Selection},
controller::{AsyncReceiver, AsyncSender},
Cursor, Selection,
},
errors::ControllerError, errors::ControllerError,
}; };
use jni::{objects::JObject, JNIEnv}; 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>, env: &mut jni::JNIEnv<'j>,
) -> Result<jni::objects::JObject<'j>, jni::errors::Error> { ) -> Result<jni::objects::JObject<'j>, jni::errors::Error> {
let (ordinal, arg) = match self { let (ordinal, arg) = match self {
crate::api::Event::UserJoin(arg) => (0, env.new_string(arg)?), crate::api::Event::UserJoin { name: arg } => (0, env.new_string(arg)?),
crate::api::Event::UserLeave(arg) => (1, env.new_string(arg)?), crate::api::Event::UserLeave { name: arg } => (1, env.new_string(arg)?),
crate::api::Event::FileTreeUpdated(arg) => (2, 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")?; 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, class,
"(JJLjava/lang/String;)V", "(JJLjava/lang/String;)V",
&[ &[
jni::objects::JValueGen::Long(self.start.into()), jni::objects::JValueGen::Long(self.start_idx.into()),
jni::objects::JValueGen::Long(self.end.into()), jni::objects::JValueGen::Long(self.end_idx.into()),
jni::objects::JValueGen::Object(&content), jni::objects::JValueGen::Object(&content),
], ],
) )
@ -438,11 +438,11 @@ impl<'j> jni_toolbox::FromJava<'j> for crate::api::TextChange {
change: Self::From, change: Self::From,
) -> Result<Self, jni::errors::Error> { ) -> Result<Self, jni::errors::Error> {
let start = env let start = env
.get_field(&change, "start", "J")? .get_field(&change, "startIdx", "J")?
.j()? .j()?
.clamp(0, u32::MAX.into()) as u32; .clamp(0, u32::MAX.into()) as u32;
let end = env let end = env
.get_field(&change, "end", "J")? .get_field(&change, "endIdx", "J")?
.j()? .j()?
.clamp(0, u32::MAX.into()) as u32; .clamp(0, u32::MAX.into()) as u32;
@ -457,8 +457,8 @@ impl<'j> jni_toolbox::FromJava<'j> for crate::api::TextChange {
}; };
Ok(Self { Ok(Self {
start, start_idx: start,
end, end_idx: end,
content, content,
}) })
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -3,7 +3,8 @@ use mlua::prelude::*;
use mlua_codemp_patch as mlua; use mlua_codemp_patch as mlua;
use super::ext::a_sync::a_sync; use super::ext::a_sync::a_sync;
use super::ext::from_lua_serde;
super::ext::impl_lua_serde! { CodempTextChange CodempBufferUpdate }
impl LuaUserData for CodempBufferController { impl LuaUserData for CodempBufferController {
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) { 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 mlua_codemp_patch as mlua;
use super::ext::a_sync::a_sync; use super::ext::a_sync::a_sync;
use super::ext::from_lua_serde;
super::ext::impl_lua_serde! { CodempConfig CodempUser }
impl LuaUserData for CodempClient { 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) { fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| {
Ok(format!("{:?}", 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( methods.add_method(
"refresh", "refresh",
|_, this, ()| a_sync! { this => this.refresh().await? }, |_, this, ()| a_sync! { this => this.refresh().await? },
); );
methods.add_method( methods.add_method(
"join_workspace", "attach_workspace",
|_, this, (ws,): (String,)| a_sync! { this => this.join_workspace(ws).await? }, |_, this, (ws,): (String,)| a_sync! { this => this.attach_workspace(ws).await? },
); );
methods.add_method( methods.add_method(
@ -41,8 +43,14 @@ impl LuaUserData for CodempClient {
a_sync! { this => this.invite_to_workspace(ws, user).await? } a_sync! { this => this.invite_to_workspace(ws, user).await? }
); );
methods.add_method("list_workspaces", |_, this, (owned,invited):(Option<bool>,Option<bool>)| methods.add_method(
a_sync! { this => this.list_workspaces(owned.unwrap_or(true), invited.unwrap_or(true)).await? } "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,)| { 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 mlua_codemp_patch as mlua;
use super::ext::a_sync::a_sync; use super::ext::a_sync::a_sync;
use super::ext::from_lua_serde;
super::ext::impl_lua_serde! { CodempCursor CodempSelection }
impl LuaUserData for CodempCursorController { impl LuaUserData for CodempCursorController {
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) { 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! { callback_args! {
Str: String, Str: String,
VecStr: Vec<String>, VecStr: Vec<String>,
VecUser: Vec<CodempUser>,
Client: CodempClient, Client: CodempClient,
CursorController: CodempCursorController, CursorController: CodempCursorController,
BufferController: CodempBufferController, BufferController: CodempBufferController,

View file

@ -5,7 +5,7 @@ pub mod log;
pub(crate) use a_sync::tokio; pub(crate) use a_sync::tokio;
pub(crate) use callback::callback; pub(crate) use callback::callback;
macro_rules! from_lua_serde { macro_rules! impl_lua_serde {
($($t:ty)*) => { ($($t:ty)*) => {
$( $(
impl FromLua for $t { impl FromLua for $t {
@ -13,8 +13,14 @@ macro_rules! from_lua_serde {
lua.from_value(value) 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 mlua_codemp_patch as mlua;
use super::ext::a_sync::a_sync; use super::ext::a_sync::a_sync;
use super::ext::from_lua_serde;
super::ext::impl_lua_serde! { CodempEvent }
impl LuaUserData for CodempWorkspace { impl LuaUserData for CodempWorkspace {
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) { fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
@ -11,26 +12,26 @@ impl LuaUserData for CodempWorkspace {
Ok(format!("{:?}", this)) Ok(format!("{:?}", this))
}); });
methods.add_method( methods.add_method(
"create", "create_buffer",
|_, this, (name,): (String,)| a_sync! { this => this.create(&name).await? }, |_, this, (name,): (String,)| a_sync! { this => this.create_buffer(&name).await? },
); );
methods.add_method( methods.add_method(
"attach", "attach_buffer",
|_, this, (name,): (String,)| a_sync! { this => this.attach(&name).await? }, |_, this, (name,): (String,)| a_sync! { this => this.attach_buffer(&name).await? },
); );
methods.add_method("detach", |_, this, (name,): (String,)| { methods.add_method("detach_buffer", |_, this, (name,): (String,)| {
Ok(this.detach(&name)) Ok(this.detach_buffer(&name))
}); });
methods.add_method( methods.add_method(
"delete", "delete_buffer",
|_, this, (name,): (String,)| a_sync! { this => this.delete(&name).await? }, |_, this, (name,): (String,)| a_sync! { this => this.delete_buffer(&name).await? },
); );
methods.add_method("get_buffer", |_, this, (name,): (String,)| { methods.add_method("get_buffer", |_, this, (name,): (String,)| {
Ok(this.buffer_by_name(&name)) Ok(this.get_buffer(&name))
}); });
methods.add_method( methods.add_method(
@ -42,13 +43,19 @@ impl LuaUserData for CodempWorkspace {
|_, this, ()| a_sync! { this => this.fetch_users().await? }, |_, this, ()| a_sync! { this => this.fetch_users().await? },
); );
methods.add_method( methods.add_method("search_buffers", |_, this, (filter,): (Option<String>,)| {
"filetree", Ok(this.search_buffers(filter.as_deref()))
|_, this, (filter, strict): (Option<String>, Option<bool>)| { });
Ok(this.filetree(filter.as_deref(), strict.unwrap_or(false)))
},
);
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("user_list", |_, this, ()| Ok(this.user_list()));
methods.add_method("recv", |_, this, ()| a_sync! { this => this.recv().await? }); 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())); 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

@ -5,26 +5,26 @@
//! ```no_run //! ```no_run
//! # async { //! # async {
//! use codemp::api::controller::{AsyncReceiver, AsyncSender}; // needed for send/recv trait methods //! use codemp::api::controller::{AsyncReceiver, AsyncSender}; // needed for send/recv trait methods
//! //!
//! // connect first, api.code.mp is managed by hexed.technology //! // connect first, api.code.mp is managed by hexed.technology
//! let client = codemp::Client::connect(codemp::api::Config::new( //! let client = codemp::Client::connect(codemp::api::Config::new(
//! "mail@example.net", "dont-use-this-password" //! "mail@example.net", "dont-use-this-password"
//! )).await?; //! )).await?;
//! //!
//! // create and join a workspace //! // create and join a workspace
//! client.create_workspace("some-workspace").await?; //! 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 //! // create a new buffer in this workspace and attach to it
//! workspace.create("/my/file.txt").await?; //! workspace.create_buffer("/my/file.txt").await?;
//! let buffer = workspace.attach("/my/file.txt").await?; //! let buffer = workspace.attach_buffer("/my/file.txt").await?;
//! //!
//! // write `hello!` at the beginning of this buffer //! // write `hello!` at the beginning of this buffer
//! buffer.send(codemp::api::TextChange { //! buffer.send(codemp::api::TextChange {
//! start: 0, end: 0, //! start_idx: 0, end_idx: 0,
//! content: "hello!".to_string(), //! content: "hello!".to_string(),
//! })?; //! })?;
//! //!
//! // wait for cursor movements //! // wait for cursor movements
//! loop { //! loop {
//! let event = workspace.cursor().recv().await?; //! let event = workspace.cursor().recv().await?;
@ -42,26 +42,26 @@
//! //!
//! ```js //! ```js
//! import * as codemp from 'codemp'; //! import * as codemp from 'codemp';
//! //!
//! // connect first, api.code.mp is managed by hexed.technology //! // connect first, api.code.mp is managed by hexed.technology
//! let client = await codemp.connect({ //! let client = await codemp.connect({
//! username: "mail@example.net", password: "dont-use-this-password" //! username: "mail@example.net", password: "dont-use-this-password"
//! }); //! });
//! //!
//! // create and join a workspace //! // create and join a workspace
//! await client.create_workspace("some-workspace"); //! await client.createWorkspace("some-workspace");
//! let workspace = await client.join_workspace("some-workspace"); //! let workspace = await client.attachWorkspace("some-workspace");
//! //!
//! // create a new buffer in this workspace and attach to it //! // create a new buffer in this workspace and attach to it
//! await workspace.create("/my/file.txt"); //! await workspace.createBuffer("/my/file.txt");
//! let buffer = await workspace.attach("/my/file.txt"); //! let buffer = await workspace.attachBuffer("/my/file.txt");
//! //!
//! // write `hello!` at the beginning of this buffer //! // write `hello!` at the beginning of this buffer
//! await buffer.send({ //! await buffer.send({
//! start: 0, end: 0, //! start_idx: 0, end_idx: 0,
//! content: "hello!", //! content: "hello!",
//! }); //! });
//! //!
//! // wait for cursor movements //! // wait for cursor movements
//! while (true) { //! while (true) {
//! let event = await workspace.cursor().recv(); //! let event = await workspace.cursor().recv();
@ -78,30 +78,31 @@
//! //!
//! ```py //! ```py
//! import codemp //! import codemp
//! //!
//! # connect first, api.code.mp is managed by hexed.technology //! # connect first, api.code.mp is managed by hexed.technology
//! config = codemp.get_default_config() //! client = codemp.connect(
//! config.username = "mail@example.net" //! codemp.Config('mail@example.net', 'dont-use-this-password')
//! config.password = "dont-use-this-password" //! ).wait()
//! client = codemp.connect(config).wait() //!
//!
//! # create and join a workspace //! # create and join a workspace
//! client.create_workspace("some-workspace").wait() //! 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 //! # create a new buffer in this workspace and attach to it
//! workspace.create("/my/file.txt").wait() //! 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 //! # write `hello!` at the beginning of this buffer
//! buffer.send( //! buffer.send(codemp.TextChange(
//! 0, 0, "hello!" //! start_idx=0, end_idx=0,
//! ).wait() //! content="hello!"
//! //! )).wait()
//!
//! # wait for cursor movements //! # wait for cursor movements
//! while true: //! while true:
//! event = workspace.cursor().recv().wait() //! event = workspace.cursor().recv().wait()
//! print(f"user {event.user} moved on buffer {event.buffer}") //! print(f"user {event.user} moved on buffer {event.buffer}")
//!
//! ``` //! ```
//! //!
//! ## Lua //! ## Lua
@ -124,26 +125,26 @@
//! //!
//! ```lua //! ```lua
//! CODEMP = require('codemp') //! CODEMP = require('codemp')
//! //!
//! -- connect first, api.code.mp is managed by hexed.technology //! -- connect first, api.code.mp is managed by hexed.technology
//! local client = CODEMP.connect({ //! local client = CODEMP.connect({
//! username = "mail@example.net", password = "dont-use-this-password" //! username = "mail@example.net", password = "dont-use-this-password"
//! }):await() //! }):await()
//! //!
//! -- create and join a workspace //! -- create and join a workspace
//! client:create_workspace("my-workspace"):await() //! 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 //! -- create a new buffer in this workspace and attach to it
//! workspace:create_buffer("/my/file.txt"):await() //! workspace:create_buffer("/my/file.txt"):await()
//! local buffer = workspace:attach_buffer("/my/file.txt"):await() //! local buffer = workspace:attach_buffer("/my/file.txt"):await()
//! //!
//! -- write `hello!` at the beginning of this buffer //! -- write `hello!` at the beginning of this buffer
//! buffer:send({ //! buffer:send({
//! start = 0, finish = 0, //! start_idx = 0, end_idx = 0,
//! content = "hello!" //! content = "hello!"
//! }):await() //! }):await()
//! //!
//! -- wait for cursor movements //! -- wait for cursor movements
//! while true do //! while true do
//! local event = workspace.cursor:recv():await() //! local event = workspace.cursor:recv():await()
@ -162,29 +163,29 @@
//! //!
//! ```java //! ```java
//! import mp.code.*; //! import mp.code.*;
//! //!
//! // connect first, api.code.mp is managed by hexed.technology //! // connect first, api.code.mp is managed by hexed.technology
//! Client client = Client.connect( //! Client client = Client.connect(
//! new data.Config("mail@example.net", "dont-use-this-password") //! new data.Config("mail@example.net", "dont-use-this-password")
//! ); //! );
//! //!
//! // create and join a workspace //! // create and join a workspace
//! client.createWorkspace("some-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 //! // create a new buffer in this workspace and attach to it
//! workspace.createBuffer("/my/file.txt"); //! 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 //! // write `hello!` at the beginning of this buffer
//! buffer.send(new data.TextChange( //! buffer.send(new data.TextChange(
//! 0, 0, "hello!", //! 0, 0, "hello!",
//! java.util.OptionalLong.empty() // optional, used for error detection //! java.util.OptionalLong.empty() // optional, used for error detection
//! )); //! ));
//! //!
//! // wait for cursor movements //! // wait for cursor movements
//! while (true) { //! 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); //! 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::a_sync_allow_threads;
use super::Client; use super::Client;
use crate::api::User;
use crate::workspace::Workspace; use crate::workspace::Workspace;
use pyo3::prelude::*; use pyo3::prelude::*;
@ -14,11 +15,11 @@ impl Client {
// super::tokio().block_on(Client::connect(host, username, password)) // super::tokio().block_on(Client::connect(host, username, password))
// } // }
#[pyo3(name = "join_workspace")] #[pyo3(name = "attach_workspace")]
fn pyjoin_workspace(&self, py: Python<'_>, workspace: String) -> PyResult<super::Promise> { fn pyattach_workspace(&self, py: Python<'_>, workspace: String) -> PyResult<super::Promise> {
tracing::info!("attempting to join the workspace {}", workspace); tracing::info!("attempting to join the workspace {}", workspace);
let this = self.clone(); 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(); // let this = self.clone();
// Ok(super::Promise(Some(tokio().spawn(async move { // Ok(super::Promise(Some(tokio().spawn(async move {
// Ok(this // Ok(this
@ -54,16 +55,18 @@ impl Client {
a_sync_allow_threads!(py, this.invite_to_workspace(workspace, user).await) a_sync_allow_threads!(py, this.invite_to_workspace(workspace, user).await)
} }
#[pyo3(name = "list_workspaces")] #[pyo3(name = "fetch_owned_workspaces")]
fn pylist_workspaces( fn pyfetch_owned_workspaces(&self, py: Python<'_>) -> PyResult<super::Promise> {
&self, tracing::info!("attempting to fetch owned workspaces");
py: Python<'_>,
owned: bool,
invited: bool,
) -> PyResult<super::Promise> {
tracing::info!("attempting to list workspaces");
let this = self.clone(); 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")] #[pyo3(name = "leave_workspace")]
@ -82,14 +85,9 @@ impl Client {
self.active_workspaces() self.active_workspaces()
} }
#[pyo3(name = "user_id")] #[pyo3(name = "current_user")]
fn pyuser_id(&self) -> String { fn pycurrent_user(&self) -> User {
self.user().id.to_string() self.current_user().clone()
}
#[pyo3(name = "user_name")]
fn pyuser_name(&self) -> String {
self.user().name.clone()
} }
#[pyo3(name = "refresh")] #[pyo3(name = "refresh")]

View file

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

View file

@ -3,15 +3,15 @@ pub mod controllers;
pub mod workspace; pub mod workspace;
use crate::{ use crate::{
api::{Config, Cursor, TextChange}, api::{BufferUpdate, Config, Cursor, Selection, TextChange, User},
buffer::Controller as BufferController, buffer::Controller as BufferController,
cursor::Controller as CursorController, cursor::Controller as CursorController,
Client, Workspace, Client, Workspace,
}; };
use pyo3::prelude::*;
use pyo3::{ use pyo3::{
exceptions::{PyConnectionError, PyRuntimeError, PySystemError}, exceptions::{PyConnectionError, PyRuntimeError, PySystemError},
prelude::*,
types::PyDict, types::PyDict,
}; };
@ -153,13 +153,37 @@ fn init() -> PyResult<Driver> {
Ok(Driver(Some(rt_stop_tx))) Ok(Driver(Some(rt_stop_tx)))
} }
#[pyfunction] #[pymethods]
fn get_default_config() -> crate::api::Config { impl User {
let mut conf = crate::api::Config::new("".to_string(), "".to_string()); #[getter]
conf.host = Some(conf.host().to_string()); fn get_id(&self) -> pyo3::PyResult<String> {
conf.port = Some(conf.port()); Ok(self.id.to_string())
conf.tls = Some(false); }
conf
#[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] #[pymethods]
@ -176,7 +200,7 @@ impl Config {
let port = kwgs.get_item("port")?.and_then(|e| e.extract().ok()); let port = kwgs.get_item("port")?.and_then(|e| e.extract().ok());
let tls = kwgs.get_item("tls")?.and_then(|e| e.extract().ok()); let tls = kwgs.get_item("tls")?.and_then(|e| e.extract().ok());
Ok(Config { Ok(Self {
username, username,
password, password,
host, host,
@ -184,9 +208,119 @@ impl Config {
tls, tls,
}) })
} else { } 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] #[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] #[pymodule]
fn codemp(m: &Bound<'_, PyModule>) -> PyResult<()> { fn codemp(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(version, m)?)?; m.add_function(wrap_pyfunction!(version, m)?)?;
m.add_function(wrap_pyfunction!(init, 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!(connect, m)?)?;
m.add_function(wrap_pyfunction!(set_logger, m)?)?; m.add_function(wrap_pyfunction!(set_logger, m)?)?;
m.add_class::<Driver>()?; m.add_class::<Driver>()?;
m.add_class::<BufferUpdate>()?;
m.add_class::<TextChange>()?; m.add_class::<TextChange>()?;
m.add_class::<BufferController>()?; m.add_class::<BufferController>()?;
m.add_class::<Cursor>()?; m.add_class::<Cursor>()?;
m.add_class::<Selection>()?;
m.add_class::<CursorController>()?; m.add_class::<CursorController>()?;
m.add_class::<User>()?;
m.add_class::<Workspace>()?; m.add_class::<Workspace>()?;
m.add_class::<Client>()?; m.add_class::<Client>()?;
m.add_class::<Config>()?; m.add_class::<Config>()?;

View file

@ -1,4 +1,5 @@
use crate::api::controller::AsyncReceiver; use crate::api::controller::AsyncReceiver;
use crate::api::User;
use crate::buffer::Controller as BufferController; use crate::buffer::Controller as BufferController;
use crate::cursor::Controller as CursorController; use crate::cursor::Controller as CursorController;
use crate::workspace::Workspace; use crate::workspace::Workspace;
@ -11,21 +12,21 @@ use super::Promise;
#[pymethods] #[pymethods]
impl Workspace { impl Workspace {
// join a workspace // join a workspace
#[pyo3(name = "create")] #[pyo3(name = "create_buffer")]
fn pycreate(&self, py: Python, path: String) -> PyResult<Promise> { fn pycreate_buffer(&self, py: Python, path: String) -> PyResult<Promise> {
let this = self.clone(); 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")] #[pyo3(name = "attach_buffer")]
fn pyattach(&self, py: Python, path: String) -> PyResult<Promise> { fn pyattach_buffer(&self, py: Python, path: String) -> PyResult<Promise> {
let this = self.clone(); 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")] #[pyo3(name = "detach_buffer")]
fn pydetach(&self, path: String) -> bool { fn pydetach_buffer(&self, path: String) -> bool {
self.detach(path.as_str()) self.detach_buffer(path.as_str())
} }
#[pyo3(name = "fetch_buffers")] #[pyo3(name = "fetch_buffers")]
@ -40,17 +41,17 @@ impl Workspace {
a_sync_allow_threads!(py, this.fetch_users().await) a_sync_allow_threads!(py, this.fetch_users().await)
} }
#[pyo3(name = "list_buffer_users")] #[pyo3(name = "fetch_buffer_users")]
fn pylist_buffer_users(&self, py: Python, path: String) -> PyResult<Promise> { fn pyfetch_buffer_users(&self, py: Python, path: String) -> PyResult<Promise> {
// crate::Result<Vec<crate::api::User>> // crate::Result<Vec<crate::api::User>>
let this = self.clone(); 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")] #[pyo3(name = "delete_buffer")]
fn pydelete(&self, py: Python, path: String) -> PyResult<Promise> { fn pydelete_buffer(&self, py: Python, path: String) -> PyResult<Promise> {
let this = self.clone(); 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")] #[pyo3(name = "id")]
@ -63,24 +64,24 @@ impl Workspace {
self.cursor() self.cursor()
} }
#[pyo3(name = "buffer_by_name")] #[pyo3(name = "get_buffer")]
fn pybuffer_by_name(&self, path: String) -> Option<BufferController> { fn pyget_buffer(&self, path: String) -> Option<BufferController> {
self.buffer_by_name(path.as_str()) self.get_buffer(path.as_str())
} }
#[pyo3(name = "buffer_list")] #[pyo3(name = "active_buffers")]
fn pybuffer_list(&self) -> Vec<String> { fn pyactive_buffers(&self) -> Vec<String> {
self.buffer_list() self.active_buffers()
} }
#[pyo3(name = "filetree")] #[pyo3(name = "search_buffers")]
#[pyo3(signature = (filter=None, strict=false))] #[pyo3(signature = (filter=None))]
fn pyfiletree(&self, filter: Option<&str>, strict: bool) -> Vec<String> { fn pysearch_buffers(&self, filter: Option<&str>) -> Vec<String> {
self.filetree(filter, strict) self.search_buffers(filter)
} }
#[pyo3(name = "user_list")] #[pyo3(name = "user_list")]
fn pyuser_list(&self) -> Vec<String> { fn pyuser_list(&self) -> Vec<User> {
self.user_list() 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 //! 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 //! ```no_run
//! # async { //! # async {
//! # let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap(); //! # let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap();
//! client.create_workspace("my-workspace").await.expect("failed to create workspace!"); //! 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 { //! # async {
//! # let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap(); //! # let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap();
//! # client.create_workspace("").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 //! use codemp::api::controller::{AsyncSender, AsyncReceiver}; // needed to access trait methods
//! let cursor = workspace.cursor(); //! let cursor = workspace.cursor();
//! let event = cursor.recv().await.expect("disconnected while waiting for event!"); //! let event = cursor.recv().await.expect("disconnected while waiting for event!");
@ -65,14 +65,14 @@
//! # async { //! # async {
//! # let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap(); //! # let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap();
//! # client.create_workspace("").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}; //! # 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 //! buffer.content(); // force-sync
//! if let Some(mut update) = buffer.try_recv().await.unwrap() { //! if let Some(mut update) = buffer.try_recv().await.unwrap() {
//! println!( //! println!(
//! "content: {}, span: {}-{}", //! "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); //! buffer.ack(update.version);
//! } // if None, no changes are currently available //! } // if None, no changes are currently available

View file

@ -2,7 +2,7 @@
//! All-in-one renamed imports with `use codemp::prelude::*`. //! All-in-one renamed imports with `use codemp::prelude::*`.
pub use crate::api::{ 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, BufferUpdate as CodempBufferUpdate, Config as CodempConfig, Controller as CodempController,
Cursor as CodempCursor, Event as CodempEvent, Selection as CodempSelection, Cursor as CodempCursor, Event as CodempEvent, Selection as CodempSelection,
TextChange as CodempTextChange, User as CodempUser, TextChange as CodempTextChange, User as CodempUser,

View file

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