├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── metadata └── screenshot.gif └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.69" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" 10 | 11 | [[package]] 12 | name = "arrayvec" 13 | version = "0.7.2" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" 16 | 17 | [[package]] 18 | name = "associative-cache" 19 | version = "1.0.1" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "46016233fc1bb55c23b856fe556b7db6ccd05119a0a392e04f0b3b7c79058f16" 22 | 23 | [[package]] 24 | name = "atk" 25 | version = "0.16.0" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "39991bc421ddf72f70159011b323ff49b0f783cc676a7287c59453da2e2531cf" 28 | dependencies = [ 29 | "atk-sys", 30 | "bitflags", 31 | "glib", 32 | "libc", 33 | ] 34 | 35 | [[package]] 36 | name = "atk-sys" 37 | version = "0.16.0" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "11ad703eb64dc058024f0e57ccfa069e15a413b98dbd50a1a950e743b7f11148" 40 | dependencies = [ 41 | "glib-sys", 42 | "gobject-sys", 43 | "libc", 44 | "system-deps", 45 | ] 46 | 47 | [[package]] 48 | name = "autocfg" 49 | version = "1.1.0" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 52 | 53 | [[package]] 54 | name = "bitflags" 55 | version = "1.3.2" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 58 | 59 | [[package]] 60 | name = "block" 61 | version = "0.1.6" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" 64 | 65 | [[package]] 66 | name = "bumpalo" 67 | version = "3.12.0" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" 70 | 71 | [[package]] 72 | name = "bytemuck" 73 | version = "1.13.1" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" 76 | dependencies = [ 77 | "bytemuck_derive", 78 | ] 79 | 80 | [[package]] 81 | name = "bytemuck_derive" 82 | version = "1.4.0" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "1aca418a974d83d40a0c1f0c5cba6ff4bc28d8df099109ca459a2118d40b6322" 85 | dependencies = [ 86 | "proc-macro2", 87 | "quote", 88 | "syn", 89 | ] 90 | 91 | [[package]] 92 | name = "cairo-rs" 93 | version = "0.16.7" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "f3125b15ec28b84c238f6f476c6034016a5f6cc0221cb514ca46c532139fc97d" 96 | dependencies = [ 97 | "bitflags", 98 | "cairo-sys-rs", 99 | "glib", 100 | "libc", 101 | "once_cell", 102 | "thiserror", 103 | ] 104 | 105 | [[package]] 106 | name = "cairo-sys-rs" 107 | version = "0.16.3" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "7c48f4af05fabdcfa9658178e1326efa061853f040ce7d72e33af6885196f421" 110 | dependencies = [ 111 | "glib-sys", 112 | "libc", 113 | "system-deps", 114 | ] 115 | 116 | [[package]] 117 | name = "cfg-expr" 118 | version = "0.11.0" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "b0357a6402b295ca3a86bc148e84df46c02e41f41fef186bda662557ef6328aa" 121 | dependencies = [ 122 | "smallvec", 123 | ] 124 | 125 | [[package]] 126 | name = "cfg-if" 127 | version = "1.0.0" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 130 | 131 | [[package]] 132 | name = "cocoa" 133 | version = "0.24.1" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" 136 | dependencies = [ 137 | "bitflags", 138 | "block", 139 | "cocoa-foundation", 140 | "core-foundation", 141 | "core-graphics", 142 | "foreign-types", 143 | "libc", 144 | "objc", 145 | ] 146 | 147 | [[package]] 148 | name = "cocoa-foundation" 149 | version = "0.1.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" 152 | dependencies = [ 153 | "bitflags", 154 | "block", 155 | "core-foundation", 156 | "core-graphics-types", 157 | "foreign-types", 158 | "libc", 159 | "objc", 160 | ] 161 | 162 | [[package]] 163 | name = "console_error_panic_hook" 164 | version = "0.1.7" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" 167 | dependencies = [ 168 | "cfg-if", 169 | "wasm-bindgen", 170 | ] 171 | 172 | [[package]] 173 | name = "core-foundation" 174 | version = "0.9.3" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" 177 | dependencies = [ 178 | "core-foundation-sys", 179 | "libc", 180 | ] 181 | 182 | [[package]] 183 | name = "core-foundation-sys" 184 | version = "0.8.3" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 187 | 188 | [[package]] 189 | name = "core-graphics" 190 | version = "0.22.3" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" 193 | dependencies = [ 194 | "bitflags", 195 | "core-foundation", 196 | "core-graphics-types", 197 | "foreign-types", 198 | "libc", 199 | ] 200 | 201 | [[package]] 202 | name = "core-graphics-types" 203 | version = "0.1.1" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" 206 | dependencies = [ 207 | "bitflags", 208 | "core-foundation", 209 | "foreign-types", 210 | "libc", 211 | ] 212 | 213 | [[package]] 214 | name = "core-text" 215 | version = "19.2.0" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" 218 | dependencies = [ 219 | "core-foundation", 220 | "core-graphics", 221 | "foreign-types", 222 | "libc", 223 | ] 224 | 225 | [[package]] 226 | name = "displaydoc" 227 | version = "0.2.3" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" 230 | dependencies = [ 231 | "proc-macro2", 232 | "quote", 233 | "syn", 234 | ] 235 | 236 | [[package]] 237 | name = "druid" 238 | version = "0.8.3" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "5ece41814b410c87e6379441caa7316539500b2e387b8d691f2ba5c0f4aff631" 241 | dependencies = [ 242 | "console_error_panic_hook", 243 | "druid-derive", 244 | "druid-shell", 245 | "fluent-bundle", 246 | "fluent-langneg", 247 | "fluent-syntax", 248 | "fnv", 249 | "instant", 250 | "tracing", 251 | "tracing-subscriber", 252 | "tracing-wasm", 253 | "unic-langid", 254 | "unicode-segmentation", 255 | "xi-unicode", 256 | ] 257 | 258 | [[package]] 259 | name = "druid-derive" 260 | version = "0.5.0" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "f1234fc14b0c07e3d4ff2ae8862eb2c24c87e1f3d6eeef0ec6b9d564fe13cef2" 263 | dependencies = [ 264 | "proc-macro2", 265 | "quote", 266 | "syn", 267 | ] 268 | 269 | [[package]] 270 | name = "druid-shell" 271 | version = "0.8.3" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "7682d9c8fbf934504c30970775bfcfba7858a600f2f6e56bed331989958350fc" 274 | dependencies = [ 275 | "anyhow", 276 | "bitflags", 277 | "block", 278 | "cairo-rs", 279 | "cfg-if", 280 | "cocoa", 281 | "core-graphics", 282 | "foreign-types", 283 | "gdk-sys", 284 | "glib-sys", 285 | "gtk", 286 | "gtk-sys", 287 | "instant", 288 | "js-sys", 289 | "keyboard-types", 290 | "objc", 291 | "once_cell", 292 | "piet-common", 293 | "scopeguard", 294 | "time", 295 | "tracing", 296 | "wasm-bindgen", 297 | "web-sys", 298 | "winapi", 299 | "wio", 300 | ] 301 | 302 | [[package]] 303 | name = "dwrote" 304 | version = "0.11.0" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" 307 | dependencies = [ 308 | "lazy_static", 309 | "libc", 310 | "winapi", 311 | "wio", 312 | ] 313 | 314 | [[package]] 315 | name = "field-offset" 316 | version = "0.3.5" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535" 319 | dependencies = [ 320 | "memoffset", 321 | "rustc_version", 322 | ] 323 | 324 | [[package]] 325 | name = "filedescriptor" 326 | version = "0.7.3" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "e70cb4dda2f343f3b7a98a6536559d04a700136cada190822e5d6a99e4184c06" 329 | dependencies = [ 330 | "anyhow", 331 | "libc", 332 | "winapi", 333 | ] 334 | 335 | [[package]] 336 | name = "fluent-bundle" 337 | version = "0.15.2" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "e242c601dec9711505f6d5bbff5bedd4b61b2469f2e8bb8e57ee7c9747a87ffd" 340 | dependencies = [ 341 | "fluent-langneg", 342 | "fluent-syntax", 343 | "intl-memoizer", 344 | "intl_pluralrules", 345 | "rustc-hash", 346 | "self_cell", 347 | "smallvec", 348 | "unic-langid", 349 | ] 350 | 351 | [[package]] 352 | name = "fluent-langneg" 353 | version = "0.13.0" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" 356 | dependencies = [ 357 | "unic-langid", 358 | ] 359 | 360 | [[package]] 361 | name = "fluent-syntax" 362 | version = "0.11.0" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "c0abed97648395c902868fee9026de96483933faa54ea3b40d652f7dfe61ca78" 365 | dependencies = [ 366 | "thiserror", 367 | ] 368 | 369 | [[package]] 370 | name = "fnv" 371 | version = "1.0.7" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 374 | 375 | [[package]] 376 | name = "foreign-types" 377 | version = "0.3.2" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 380 | dependencies = [ 381 | "foreign-types-shared", 382 | ] 383 | 384 | [[package]] 385 | name = "foreign-types-shared" 386 | version = "0.1.1" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 389 | 390 | [[package]] 391 | name = "futures-channel" 392 | version = "0.3.26" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" 395 | dependencies = [ 396 | "futures-core", 397 | ] 398 | 399 | [[package]] 400 | name = "futures-core" 401 | version = "0.3.26" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" 404 | 405 | [[package]] 406 | name = "futures-executor" 407 | version = "0.3.26" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" 410 | dependencies = [ 411 | "futures-core", 412 | "futures-task", 413 | "futures-util", 414 | ] 415 | 416 | [[package]] 417 | name = "futures-io" 418 | version = "0.3.26" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" 421 | 422 | [[package]] 423 | name = "futures-macro" 424 | version = "0.3.26" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" 427 | dependencies = [ 428 | "proc-macro2", 429 | "quote", 430 | "syn", 431 | ] 432 | 433 | [[package]] 434 | name = "futures-task" 435 | version = "0.3.26" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" 438 | 439 | [[package]] 440 | name = "futures-util" 441 | version = "0.3.26" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" 444 | dependencies = [ 445 | "futures-core", 446 | "futures-macro", 447 | "futures-task", 448 | "pin-project-lite", 449 | "pin-utils", 450 | "slab", 451 | ] 452 | 453 | [[package]] 454 | name = "gdk" 455 | version = "0.16.2" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "aa9cb33da481c6c040404a11f8212d193889e9b435db2c14fd86987f630d3ce1" 458 | dependencies = [ 459 | "bitflags", 460 | "cairo-rs", 461 | "gdk-pixbuf", 462 | "gdk-sys", 463 | "gio", 464 | "glib", 465 | "libc", 466 | "pango", 467 | ] 468 | 469 | [[package]] 470 | name = "gdk-pixbuf" 471 | version = "0.16.7" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "c3578c60dee9d029ad86593ed88cb40f35c1b83360e12498d055022385dd9a05" 474 | dependencies = [ 475 | "bitflags", 476 | "gdk-pixbuf-sys", 477 | "gio", 478 | "glib", 479 | "libc", 480 | ] 481 | 482 | [[package]] 483 | name = "gdk-pixbuf-sys" 484 | version = "0.16.3" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "3092cf797a5f1210479ea38070d9ae8a5b8e9f8f1be9f32f4643c529c7d70016" 487 | dependencies = [ 488 | "gio-sys", 489 | "glib-sys", 490 | "gobject-sys", 491 | "libc", 492 | "system-deps", 493 | ] 494 | 495 | [[package]] 496 | name = "gdk-sys" 497 | version = "0.16.0" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "d76354f97a913e55b984759a997b693aa7dc71068c9e98bcce51aa167a0a5c5a" 500 | dependencies = [ 501 | "cairo-sys-rs", 502 | "gdk-pixbuf-sys", 503 | "gio-sys", 504 | "glib-sys", 505 | "gobject-sys", 506 | "libc", 507 | "pango-sys", 508 | "pkg-config", 509 | "system-deps", 510 | ] 511 | 512 | [[package]] 513 | name = "gio" 514 | version = "0.16.7" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "2a1c84b4534a290a29160ef5c6eff2a9c95833111472e824fc5cb78b513dd092" 517 | dependencies = [ 518 | "bitflags", 519 | "futures-channel", 520 | "futures-core", 521 | "futures-io", 522 | "futures-util", 523 | "gio-sys", 524 | "glib", 525 | "libc", 526 | "once_cell", 527 | "pin-project-lite", 528 | "smallvec", 529 | "thiserror", 530 | ] 531 | 532 | [[package]] 533 | name = "gio-sys" 534 | version = "0.16.3" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "e9b693b8e39d042a95547fc258a7b07349b1f0b48f4b2fa3108ba3c51c0b5229" 537 | dependencies = [ 538 | "glib-sys", 539 | "gobject-sys", 540 | "libc", 541 | "system-deps", 542 | "winapi", 543 | ] 544 | 545 | [[package]] 546 | name = "glib" 547 | version = "0.16.7" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "ddd4df61a866ed7259d6189b8bcb1464989a77f1d85d25d002279bbe9dd38b2f" 550 | dependencies = [ 551 | "bitflags", 552 | "futures-channel", 553 | "futures-core", 554 | "futures-executor", 555 | "futures-task", 556 | "futures-util", 557 | "gio-sys", 558 | "glib-macros", 559 | "glib-sys", 560 | "gobject-sys", 561 | "libc", 562 | "once_cell", 563 | "smallvec", 564 | "thiserror", 565 | ] 566 | 567 | [[package]] 568 | name = "glib-macros" 569 | version = "0.16.3" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "e084807350b01348b6d9dbabb724d1a0bb987f47a2c85de200e98e12e30733bf" 572 | dependencies = [ 573 | "anyhow", 574 | "heck", 575 | "proc-macro-crate", 576 | "proc-macro-error", 577 | "proc-macro2", 578 | "quote", 579 | "syn", 580 | ] 581 | 582 | [[package]] 583 | name = "glib-sys" 584 | version = "0.16.3" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "c61a4f46316d06bfa33a7ac22df6f0524c8be58e3db2d9ca99ccb1f357b62a65" 587 | dependencies = [ 588 | "libc", 589 | "system-deps", 590 | ] 591 | 592 | [[package]] 593 | name = "gobject-sys" 594 | version = "0.16.3" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "3520bb9c07ae2a12c7f2fbb24d4efc11231c8146a86956413fb1a79bb760a0f1" 597 | dependencies = [ 598 | "glib-sys", 599 | "libc", 600 | "system-deps", 601 | ] 602 | 603 | [[package]] 604 | name = "gtk" 605 | version = "0.16.2" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "e4d3507d43908c866c805f74c9dd593c0ce7ba5c38e576e41846639cdcd4bee6" 608 | dependencies = [ 609 | "atk", 610 | "bitflags", 611 | "cairo-rs", 612 | "field-offset", 613 | "futures-channel", 614 | "gdk", 615 | "gdk-pixbuf", 616 | "gio", 617 | "glib", 618 | "gtk-sys", 619 | "gtk3-macros", 620 | "libc", 621 | "once_cell", 622 | "pango", 623 | "pkg-config", 624 | ] 625 | 626 | [[package]] 627 | name = "gtk-sys" 628 | version = "0.16.0" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "89b5f8946685d5fe44497007786600c2f368ff6b1e61a16251c89f72a97520a3" 631 | dependencies = [ 632 | "atk-sys", 633 | "cairo-sys-rs", 634 | "gdk-pixbuf-sys", 635 | "gdk-sys", 636 | "gio-sys", 637 | "glib-sys", 638 | "gobject-sys", 639 | "libc", 640 | "pango-sys", 641 | "system-deps", 642 | ] 643 | 644 | [[package]] 645 | name = "gtk3-macros" 646 | version = "0.16.0" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "8cfd6557b1018b773e43c8de9d0d13581d6b36190d0501916cbec4731db5ccff" 649 | dependencies = [ 650 | "anyhow", 651 | "proc-macro-crate", 652 | "proc-macro-error", 653 | "proc-macro2", 654 | "quote", 655 | "syn", 656 | ] 657 | 658 | [[package]] 659 | name = "hashbrown" 660 | version = "0.12.3" 661 | source = "registry+https://github.com/rust-lang/crates.io-index" 662 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 663 | 664 | [[package]] 665 | name = "heck" 666 | version = "0.4.1" 667 | source = "registry+https://github.com/rust-lang/crates.io-index" 668 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 669 | 670 | [[package]] 671 | name = "helix-ui" 672 | version = "0.1.0" 673 | dependencies = [ 674 | "bytemuck", 675 | "druid", 676 | "once_cell", 677 | "portable-pty", 678 | "vte", 679 | ] 680 | 681 | [[package]] 682 | name = "indexmap" 683 | version = "1.9.2" 684 | source = "registry+https://github.com/rust-lang/crates.io-index" 685 | checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" 686 | dependencies = [ 687 | "autocfg", 688 | "hashbrown", 689 | ] 690 | 691 | [[package]] 692 | name = "instant" 693 | version = "0.1.12" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 696 | dependencies = [ 697 | "cfg-if", 698 | "js-sys", 699 | "wasm-bindgen", 700 | "web-sys", 701 | ] 702 | 703 | [[package]] 704 | name = "intl-memoizer" 705 | version = "0.5.1" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "c310433e4a310918d6ed9243542a6b83ec1183df95dff8f23f87bb88a264a66f" 708 | dependencies = [ 709 | "type-map", 710 | "unic-langid", 711 | ] 712 | 713 | [[package]] 714 | name = "intl_pluralrules" 715 | version = "7.0.2" 716 | source = "registry+https://github.com/rust-lang/crates.io-index" 717 | checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972" 718 | dependencies = [ 719 | "unic-langid", 720 | ] 721 | 722 | [[package]] 723 | name = "ioctl-rs" 724 | version = "0.1.6" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "f7970510895cee30b3e9128319f2cefd4bde883a39f38baa279567ba3a7eb97d" 727 | dependencies = [ 728 | "libc", 729 | ] 730 | 731 | [[package]] 732 | name = "js-sys" 733 | version = "0.3.61" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" 736 | dependencies = [ 737 | "wasm-bindgen", 738 | ] 739 | 740 | [[package]] 741 | name = "keyboard-types" 742 | version = "0.6.2" 743 | source = "registry+https://github.com/rust-lang/crates.io-index" 744 | checksum = "0b7668b7cff6a51fe61cdde64cd27c8a220786f399501b57ebe36f7d8112fd68" 745 | dependencies = [ 746 | "bitflags", 747 | ] 748 | 749 | [[package]] 750 | name = "kurbo" 751 | version = "0.9.1" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "db8c31eaef73f18e0d938785e01ab471ec73e3f90c3389e84335ade689ba953b" 754 | dependencies = [ 755 | "arrayvec", 756 | ] 757 | 758 | [[package]] 759 | name = "lazy_static" 760 | version = "1.4.0" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 763 | 764 | [[package]] 765 | name = "libc" 766 | version = "0.2.139" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" 769 | 770 | [[package]] 771 | name = "log" 772 | version = "0.4.17" 773 | source = "registry+https://github.com/rust-lang/crates.io-index" 774 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 775 | dependencies = [ 776 | "cfg-if", 777 | ] 778 | 779 | [[package]] 780 | name = "malloc_buf" 781 | version = "0.0.6" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" 784 | dependencies = [ 785 | "libc", 786 | ] 787 | 788 | [[package]] 789 | name = "matches" 790 | version = "0.1.10" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" 793 | 794 | [[package]] 795 | name = "memchr" 796 | version = "2.5.0" 797 | source = "registry+https://github.com/rust-lang/crates.io-index" 798 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 799 | 800 | [[package]] 801 | name = "memoffset" 802 | version = "0.8.0" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" 805 | dependencies = [ 806 | "autocfg", 807 | ] 808 | 809 | [[package]] 810 | name = "nu-ansi-term" 811 | version = "0.46.0" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 814 | dependencies = [ 815 | "overload", 816 | "winapi", 817 | ] 818 | 819 | [[package]] 820 | name = "objc" 821 | version = "0.2.7" 822 | source = "registry+https://github.com/rust-lang/crates.io-index" 823 | checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" 824 | dependencies = [ 825 | "malloc_buf", 826 | ] 827 | 828 | [[package]] 829 | name = "once_cell" 830 | version = "1.17.1" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" 833 | 834 | [[package]] 835 | name = "overload" 836 | version = "0.1.1" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 839 | 840 | [[package]] 841 | name = "pango" 842 | version = "0.16.5" 843 | source = "registry+https://github.com/rust-lang/crates.io-index" 844 | checksum = "cdff66b271861037b89d028656184059e03b0b6ccb36003820be19f7200b1e94" 845 | dependencies = [ 846 | "bitflags", 847 | "gio", 848 | "glib", 849 | "libc", 850 | "once_cell", 851 | "pango-sys", 852 | ] 853 | 854 | [[package]] 855 | name = "pango-sys" 856 | version = "0.16.3" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "9e134909a9a293e04d2cc31928aa95679c5e4df954d0b85483159bd20d8f047f" 859 | dependencies = [ 860 | "glib-sys", 861 | "gobject-sys", 862 | "libc", 863 | "system-deps", 864 | ] 865 | 866 | [[package]] 867 | name = "pangocairo" 868 | version = "0.16.3" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "16ad2ec87789371b551fd2367c10aa37060412ffd3e60abd99491b21b93a3f9b" 871 | dependencies = [ 872 | "bitflags", 873 | "cairo-rs", 874 | "glib", 875 | "libc", 876 | "pango", 877 | "pangocairo-sys", 878 | ] 879 | 880 | [[package]] 881 | name = "pangocairo-sys" 882 | version = "0.16.3" 883 | source = "registry+https://github.com/rust-lang/crates.io-index" 884 | checksum = "848d2df9b7f1a8c7a19d994de443bcbe5d4382610ccb8e64247f932be74fcf76" 885 | dependencies = [ 886 | "cairo-sys-rs", 887 | "glib-sys", 888 | "libc", 889 | "pango-sys", 890 | "system-deps", 891 | ] 892 | 893 | [[package]] 894 | name = "piet" 895 | version = "0.6.2" 896 | source = "registry+https://github.com/rust-lang/crates.io-index" 897 | checksum = "e381186490a3e2017a506d62b759ea8eaf4be14666b13ed53973e8ae193451b1" 898 | dependencies = [ 899 | "kurbo", 900 | "unic-bidi", 901 | ] 902 | 903 | [[package]] 904 | name = "piet-cairo" 905 | version = "0.6.2" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "12dc0b38ac300c79deb9bfc8c7f91a08f2b080338648f7202981094b22321bb9" 908 | dependencies = [ 909 | "cairo-rs", 910 | "pango", 911 | "pangocairo", 912 | "piet", 913 | "unicode-segmentation", 914 | "xi-unicode", 915 | ] 916 | 917 | [[package]] 918 | name = "piet-common" 919 | version = "0.6.2" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "9dd8497cc0bcfecb1e14e027428c5e3eaf9af6e14761176e1212006d8bdba387" 922 | dependencies = [ 923 | "cairo-rs", 924 | "cairo-sys-rs", 925 | "cfg-if", 926 | "core-graphics", 927 | "piet", 928 | "piet-cairo", 929 | "piet-coregraphics", 930 | "piet-direct2d", 931 | "piet-web", 932 | "wasm-bindgen", 933 | "web-sys", 934 | ] 935 | 936 | [[package]] 937 | name = "piet-coregraphics" 938 | version = "0.6.2" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "a819b41d2ddb1d8abf3e45e49422f866cba281b4abb5e2fb948bba06e2c3d3f7" 941 | dependencies = [ 942 | "associative-cache", 943 | "core-foundation", 944 | "core-foundation-sys", 945 | "core-graphics", 946 | "core-text", 947 | "foreign-types", 948 | "piet", 949 | ] 950 | 951 | [[package]] 952 | name = "piet-direct2d" 953 | version = "0.6.2" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "dd00e91df4f987be40eb13042afe6ee9e54468466bdb7486390b40d4fef0993e" 956 | dependencies = [ 957 | "associative-cache", 958 | "dwrote", 959 | "piet", 960 | "utf16_lit", 961 | "winapi", 962 | "wio", 963 | ] 964 | 965 | [[package]] 966 | name = "piet-web" 967 | version = "0.6.2" 968 | source = "registry+https://github.com/rust-lang/crates.io-index" 969 | checksum = "3a560232a94e535979923d49062d1c6d5407b3804bcd0d0b4cb9e25a9b41db1e" 970 | dependencies = [ 971 | "js-sys", 972 | "piet", 973 | "unicode-segmentation", 974 | "wasm-bindgen", 975 | "web-sys", 976 | "xi-unicode", 977 | ] 978 | 979 | [[package]] 980 | name = "pin-project-lite" 981 | version = "0.2.9" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 984 | 985 | [[package]] 986 | name = "pin-utils" 987 | version = "0.1.0" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 990 | 991 | [[package]] 992 | name = "pkg-config" 993 | version = "0.3.26" 994 | source = "registry+https://github.com/rust-lang/crates.io-index" 995 | checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" 996 | 997 | [[package]] 998 | name = "portable-pty" 999 | version = "0.4.0" 1000 | source = "registry+https://github.com/rust-lang/crates.io-index" 1001 | checksum = "924309c952a87a0897575a1bb65bdf3d572af120fbb57dfedec639fb9934b417" 1002 | dependencies = [ 1003 | "anyhow", 1004 | "bitflags", 1005 | "filedescriptor", 1006 | "lazy_static", 1007 | "libc", 1008 | "log", 1009 | "serial", 1010 | "shared_library", 1011 | "shell-words", 1012 | "winapi", 1013 | ] 1014 | 1015 | [[package]] 1016 | name = "proc-macro-crate" 1017 | version = "1.3.1" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" 1020 | dependencies = [ 1021 | "once_cell", 1022 | "toml_edit", 1023 | ] 1024 | 1025 | [[package]] 1026 | name = "proc-macro-error" 1027 | version = "1.0.4" 1028 | source = "registry+https://github.com/rust-lang/crates.io-index" 1029 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 1030 | dependencies = [ 1031 | "proc-macro-error-attr", 1032 | "proc-macro2", 1033 | "quote", 1034 | "syn", 1035 | "version_check", 1036 | ] 1037 | 1038 | [[package]] 1039 | name = "proc-macro-error-attr" 1040 | version = "1.0.4" 1041 | source = "registry+https://github.com/rust-lang/crates.io-index" 1042 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1043 | dependencies = [ 1044 | "proc-macro2", 1045 | "quote", 1046 | "version_check", 1047 | ] 1048 | 1049 | [[package]] 1050 | name = "proc-macro2" 1051 | version = "1.0.51" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" 1054 | dependencies = [ 1055 | "unicode-ident", 1056 | ] 1057 | 1058 | [[package]] 1059 | name = "quote" 1060 | version = "1.0.23" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" 1063 | dependencies = [ 1064 | "proc-macro2", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "rustc-hash" 1069 | version = "1.1.0" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1072 | 1073 | [[package]] 1074 | name = "rustc_version" 1075 | version = "0.4.0" 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" 1077 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1078 | dependencies = [ 1079 | "semver", 1080 | ] 1081 | 1082 | [[package]] 1083 | name = "scopeguard" 1084 | version = "1.1.0" 1085 | source = "registry+https://github.com/rust-lang/crates.io-index" 1086 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1087 | 1088 | [[package]] 1089 | name = "self_cell" 1090 | version = "0.10.2" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af" 1093 | 1094 | [[package]] 1095 | name = "semver" 1096 | version = "1.0.16" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" 1099 | 1100 | [[package]] 1101 | name = "serde" 1102 | version = "1.0.152" 1103 | source = "registry+https://github.com/rust-lang/crates.io-index" 1104 | checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" 1105 | 1106 | [[package]] 1107 | name = "serial" 1108 | version = "0.4.0" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "a1237a96570fc377c13baa1b88c7589ab66edced652e43ffb17088f003db3e86" 1111 | dependencies = [ 1112 | "serial-core", 1113 | "serial-unix", 1114 | "serial-windows", 1115 | ] 1116 | 1117 | [[package]] 1118 | name = "serial-core" 1119 | version = "0.4.0" 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" 1121 | checksum = "3f46209b345401737ae2125fe5b19a77acce90cd53e1658cda928e4fe9a64581" 1122 | dependencies = [ 1123 | "libc", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "serial-unix" 1128 | version = "0.4.0" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "f03fbca4c9d866e24a459cbca71283f545a37f8e3e002ad8c70593871453cab7" 1131 | dependencies = [ 1132 | "ioctl-rs", 1133 | "libc", 1134 | "serial-core", 1135 | "termios", 1136 | ] 1137 | 1138 | [[package]] 1139 | name = "serial-windows" 1140 | version = "0.4.0" 1141 | source = "registry+https://github.com/rust-lang/crates.io-index" 1142 | checksum = "15c6d3b776267a75d31bbdfd5d36c0ca051251caafc285827052bc53bcdc8162" 1143 | dependencies = [ 1144 | "libc", 1145 | "serial-core", 1146 | ] 1147 | 1148 | [[package]] 1149 | name = "sharded-slab" 1150 | version = "0.1.4" 1151 | source = "registry+https://github.com/rust-lang/crates.io-index" 1152 | checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" 1153 | dependencies = [ 1154 | "lazy_static", 1155 | ] 1156 | 1157 | [[package]] 1158 | name = "shared_library" 1159 | version = "0.1.9" 1160 | source = "registry+https://github.com/rust-lang/crates.io-index" 1161 | checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" 1162 | dependencies = [ 1163 | "lazy_static", 1164 | "libc", 1165 | ] 1166 | 1167 | [[package]] 1168 | name = "shell-words" 1169 | version = "1.1.0" 1170 | source = "registry+https://github.com/rust-lang/crates.io-index" 1171 | checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" 1172 | 1173 | [[package]] 1174 | name = "slab" 1175 | version = "0.4.8" 1176 | source = "registry+https://github.com/rust-lang/crates.io-index" 1177 | checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" 1178 | dependencies = [ 1179 | "autocfg", 1180 | ] 1181 | 1182 | [[package]] 1183 | name = "smallvec" 1184 | version = "1.10.0" 1185 | source = "registry+https://github.com/rust-lang/crates.io-index" 1186 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" 1187 | 1188 | [[package]] 1189 | name = "syn" 1190 | version = "1.0.109" 1191 | source = "registry+https://github.com/rust-lang/crates.io-index" 1192 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1193 | dependencies = [ 1194 | "proc-macro2", 1195 | "quote", 1196 | "unicode-ident", 1197 | ] 1198 | 1199 | [[package]] 1200 | name = "system-deps" 1201 | version = "6.0.3" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | checksum = "2955b1fe31e1fa2fbd1976b71cc69a606d7d4da16f6de3333d0c92d51419aeff" 1204 | dependencies = [ 1205 | "cfg-expr", 1206 | "heck", 1207 | "pkg-config", 1208 | "toml", 1209 | "version-compare", 1210 | ] 1211 | 1212 | [[package]] 1213 | name = "termios" 1214 | version = "0.2.2" 1215 | source = "registry+https://github.com/rust-lang/crates.io-index" 1216 | checksum = "d5d9cf598a6d7ce700a4e6a9199da127e6819a61e64b68609683cc9a01b5683a" 1217 | dependencies = [ 1218 | "libc", 1219 | ] 1220 | 1221 | [[package]] 1222 | name = "thiserror" 1223 | version = "1.0.38" 1224 | source = "registry+https://github.com/rust-lang/crates.io-index" 1225 | checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" 1226 | dependencies = [ 1227 | "thiserror-impl", 1228 | ] 1229 | 1230 | [[package]] 1231 | name = "thiserror-impl" 1232 | version = "1.0.38" 1233 | source = "registry+https://github.com/rust-lang/crates.io-index" 1234 | checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" 1235 | dependencies = [ 1236 | "proc-macro2", 1237 | "quote", 1238 | "syn", 1239 | ] 1240 | 1241 | [[package]] 1242 | name = "thread_local" 1243 | version = "1.1.7" 1244 | source = "registry+https://github.com/rust-lang/crates.io-index" 1245 | checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" 1246 | dependencies = [ 1247 | "cfg-if", 1248 | "once_cell", 1249 | ] 1250 | 1251 | [[package]] 1252 | name = "time" 1253 | version = "0.3.20" 1254 | source = "registry+https://github.com/rust-lang/crates.io-index" 1255 | checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" 1256 | dependencies = [ 1257 | "serde", 1258 | "time-core", 1259 | ] 1260 | 1261 | [[package]] 1262 | name = "time-core" 1263 | version = "0.1.0" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" 1266 | 1267 | [[package]] 1268 | name = "tinystr" 1269 | version = "0.7.1" 1270 | source = "registry+https://github.com/rust-lang/crates.io-index" 1271 | checksum = "7ac3f5b6856e931e15e07b478e98c8045239829a65f9156d4fa7e7788197a5ef" 1272 | dependencies = [ 1273 | "displaydoc", 1274 | ] 1275 | 1276 | [[package]] 1277 | name = "toml" 1278 | version = "0.5.11" 1279 | source = "registry+https://github.com/rust-lang/crates.io-index" 1280 | checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" 1281 | dependencies = [ 1282 | "serde", 1283 | ] 1284 | 1285 | [[package]] 1286 | name = "toml_datetime" 1287 | version = "0.6.1" 1288 | source = "registry+https://github.com/rust-lang/crates.io-index" 1289 | checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" 1290 | 1291 | [[package]] 1292 | name = "toml_edit" 1293 | version = "0.19.4" 1294 | source = "registry+https://github.com/rust-lang/crates.io-index" 1295 | checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825" 1296 | dependencies = [ 1297 | "indexmap", 1298 | "toml_datetime", 1299 | "winnow", 1300 | ] 1301 | 1302 | [[package]] 1303 | name = "tracing" 1304 | version = "0.1.37" 1305 | source = "registry+https://github.com/rust-lang/crates.io-index" 1306 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 1307 | dependencies = [ 1308 | "cfg-if", 1309 | "pin-project-lite", 1310 | "tracing-attributes", 1311 | "tracing-core", 1312 | ] 1313 | 1314 | [[package]] 1315 | name = "tracing-attributes" 1316 | version = "0.1.23" 1317 | source = "registry+https://github.com/rust-lang/crates.io-index" 1318 | checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" 1319 | dependencies = [ 1320 | "proc-macro2", 1321 | "quote", 1322 | "syn", 1323 | ] 1324 | 1325 | [[package]] 1326 | name = "tracing-core" 1327 | version = "0.1.30" 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" 1329 | checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" 1330 | dependencies = [ 1331 | "once_cell", 1332 | ] 1333 | 1334 | [[package]] 1335 | name = "tracing-subscriber" 1336 | version = "0.3.16" 1337 | source = "registry+https://github.com/rust-lang/crates.io-index" 1338 | checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" 1339 | dependencies = [ 1340 | "nu-ansi-term", 1341 | "sharded-slab", 1342 | "thread_local", 1343 | "tracing-core", 1344 | ] 1345 | 1346 | [[package]] 1347 | name = "tracing-wasm" 1348 | version = "0.2.1" 1349 | source = "registry+https://github.com/rust-lang/crates.io-index" 1350 | checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" 1351 | dependencies = [ 1352 | "tracing", 1353 | "tracing-subscriber", 1354 | "wasm-bindgen", 1355 | ] 1356 | 1357 | [[package]] 1358 | name = "type-map" 1359 | version = "0.4.0" 1360 | source = "registry+https://github.com/rust-lang/crates.io-index" 1361 | checksum = "b6d3364c5e96cb2ad1603037ab253ddd34d7fb72a58bdddf4b7350760fc69a46" 1362 | dependencies = [ 1363 | "rustc-hash", 1364 | ] 1365 | 1366 | [[package]] 1367 | name = "unic-bidi" 1368 | version = "0.9.0" 1369 | source = "registry+https://github.com/rust-lang/crates.io-index" 1370 | checksum = "1356b759fb6a82050666f11dce4b6fe3571781f1449f3ef78074e408d468ec09" 1371 | dependencies = [ 1372 | "matches", 1373 | "unic-ucd-bidi", 1374 | ] 1375 | 1376 | [[package]] 1377 | name = "unic-char-property" 1378 | version = "0.9.0" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" 1381 | dependencies = [ 1382 | "unic-char-range", 1383 | ] 1384 | 1385 | [[package]] 1386 | name = "unic-char-range" 1387 | version = "0.9.0" 1388 | source = "registry+https://github.com/rust-lang/crates.io-index" 1389 | checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" 1390 | 1391 | [[package]] 1392 | name = "unic-common" 1393 | version = "0.9.0" 1394 | source = "registry+https://github.com/rust-lang/crates.io-index" 1395 | checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" 1396 | 1397 | [[package]] 1398 | name = "unic-langid" 1399 | version = "0.9.1" 1400 | source = "registry+https://github.com/rust-lang/crates.io-index" 1401 | checksum = "398f9ad7239db44fd0f80fe068d12ff22d78354080332a5077dc6f52f14dcf2f" 1402 | dependencies = [ 1403 | "unic-langid-impl", 1404 | ] 1405 | 1406 | [[package]] 1407 | name = "unic-langid-impl" 1408 | version = "0.9.1" 1409 | source = "registry+https://github.com/rust-lang/crates.io-index" 1410 | checksum = "e35bfd2f2b8796545b55d7d3fd3e89a0613f68a0d1c8bc28cb7ff96b411a35ff" 1411 | dependencies = [ 1412 | "tinystr", 1413 | ] 1414 | 1415 | [[package]] 1416 | name = "unic-ucd-bidi" 1417 | version = "0.9.0" 1418 | source = "registry+https://github.com/rust-lang/crates.io-index" 1419 | checksum = "d1d568b51222484e1f8209ce48caa6b430bf352962b877d592c29ab31fb53d8c" 1420 | dependencies = [ 1421 | "unic-char-property", 1422 | "unic-char-range", 1423 | "unic-ucd-version", 1424 | ] 1425 | 1426 | [[package]] 1427 | name = "unic-ucd-version" 1428 | version = "0.9.0" 1429 | source = "registry+https://github.com/rust-lang/crates.io-index" 1430 | checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" 1431 | dependencies = [ 1432 | "unic-common", 1433 | ] 1434 | 1435 | [[package]] 1436 | name = "unicode-ident" 1437 | version = "1.0.7" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "775c11906edafc97bc378816b94585fbd9a054eabaf86fdd0ced94af449efab7" 1440 | 1441 | [[package]] 1442 | name = "unicode-segmentation" 1443 | version = "1.10.1" 1444 | source = "registry+https://github.com/rust-lang/crates.io-index" 1445 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" 1446 | 1447 | [[package]] 1448 | name = "utf16_lit" 1449 | version = "2.0.2" 1450 | source = "registry+https://github.com/rust-lang/crates.io-index" 1451 | checksum = "14706d2a800ee8ff38c1d3edb873cd616971ea59eb7c0d046bb44ef59b06a1ae" 1452 | 1453 | [[package]] 1454 | name = "utf8parse" 1455 | version = "0.2.0" 1456 | source = "registry+https://github.com/rust-lang/crates.io-index" 1457 | checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" 1458 | 1459 | [[package]] 1460 | name = "version-compare" 1461 | version = "0.1.1" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" 1464 | 1465 | [[package]] 1466 | name = "version_check" 1467 | version = "0.9.4" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1470 | 1471 | [[package]] 1472 | name = "vte" 1473 | version = "0.11.0" 1474 | source = "registry+https://github.com/rust-lang/crates.io-index" 1475 | checksum = "1aae21c12ad2ec2d168c236f369c38ff332bc1134f7246350dca641437365045" 1476 | dependencies = [ 1477 | "arrayvec", 1478 | "utf8parse", 1479 | "vte_generate_state_changes", 1480 | ] 1481 | 1482 | [[package]] 1483 | name = "vte_generate_state_changes" 1484 | version = "0.1.1" 1485 | source = "registry+https://github.com/rust-lang/crates.io-index" 1486 | checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" 1487 | dependencies = [ 1488 | "proc-macro2", 1489 | "quote", 1490 | ] 1491 | 1492 | [[package]] 1493 | name = "wasm-bindgen" 1494 | version = "0.2.84" 1495 | source = "registry+https://github.com/rust-lang/crates.io-index" 1496 | checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" 1497 | dependencies = [ 1498 | "cfg-if", 1499 | "wasm-bindgen-macro", 1500 | ] 1501 | 1502 | [[package]] 1503 | name = "wasm-bindgen-backend" 1504 | version = "0.2.84" 1505 | source = "registry+https://github.com/rust-lang/crates.io-index" 1506 | checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" 1507 | dependencies = [ 1508 | "bumpalo", 1509 | "log", 1510 | "once_cell", 1511 | "proc-macro2", 1512 | "quote", 1513 | "syn", 1514 | "wasm-bindgen-shared", 1515 | ] 1516 | 1517 | [[package]] 1518 | name = "wasm-bindgen-macro" 1519 | version = "0.2.84" 1520 | source = "registry+https://github.com/rust-lang/crates.io-index" 1521 | checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" 1522 | dependencies = [ 1523 | "quote", 1524 | "wasm-bindgen-macro-support", 1525 | ] 1526 | 1527 | [[package]] 1528 | name = "wasm-bindgen-macro-support" 1529 | version = "0.2.84" 1530 | source = "registry+https://github.com/rust-lang/crates.io-index" 1531 | checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" 1532 | dependencies = [ 1533 | "proc-macro2", 1534 | "quote", 1535 | "syn", 1536 | "wasm-bindgen-backend", 1537 | "wasm-bindgen-shared", 1538 | ] 1539 | 1540 | [[package]] 1541 | name = "wasm-bindgen-shared" 1542 | version = "0.2.84" 1543 | source = "registry+https://github.com/rust-lang/crates.io-index" 1544 | checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" 1545 | 1546 | [[package]] 1547 | name = "web-sys" 1548 | version = "0.3.61" 1549 | source = "registry+https://github.com/rust-lang/crates.io-index" 1550 | checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" 1551 | dependencies = [ 1552 | "js-sys", 1553 | "wasm-bindgen", 1554 | ] 1555 | 1556 | [[package]] 1557 | name = "winapi" 1558 | version = "0.3.9" 1559 | source = "registry+https://github.com/rust-lang/crates.io-index" 1560 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1561 | dependencies = [ 1562 | "winapi-i686-pc-windows-gnu", 1563 | "winapi-x86_64-pc-windows-gnu", 1564 | ] 1565 | 1566 | [[package]] 1567 | name = "winapi-i686-pc-windows-gnu" 1568 | version = "0.4.0" 1569 | source = "registry+https://github.com/rust-lang/crates.io-index" 1570 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1571 | 1572 | [[package]] 1573 | name = "winapi-x86_64-pc-windows-gnu" 1574 | version = "0.4.0" 1575 | source = "registry+https://github.com/rust-lang/crates.io-index" 1576 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1577 | 1578 | [[package]] 1579 | name = "winnow" 1580 | version = "0.3.4" 1581 | source = "registry+https://github.com/rust-lang/crates.io-index" 1582 | checksum = "c95fb4ff192527911dd18eb138ac30908e7165b8944e528b6af93aa4c842d345" 1583 | dependencies = [ 1584 | "memchr", 1585 | ] 1586 | 1587 | [[package]] 1588 | name = "wio" 1589 | version = "0.2.2" 1590 | source = "registry+https://github.com/rust-lang/crates.io-index" 1591 | checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" 1592 | dependencies = [ 1593 | "winapi", 1594 | ] 1595 | 1596 | [[package]] 1597 | name = "xi-unicode" 1598 | version = "0.3.0" 1599 | source = "registry+https://github.com/rust-lang/crates.io-index" 1600 | checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" 1601 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | description = "Helix UI client" 3 | name = "helix-ui" 4 | version = "0.1.0" 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | druid = "0.8.3" 11 | portable-pty = "0.4.0" 12 | bytemuck = { version = "1.4", features = [ "derive" ] } 13 | vte = "0.11.0" 14 | once_cell = "1.17.1" 15 | 16 | [package.metadata.bundle] 17 | copyright = "Copyright (c) Huy Tran 2023. All rights reserved." 18 | icon = [] 19 | identifier = "com.rhelix.ui" 20 | name = "Rhelix" 21 | version = "0.0.1" 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Helix UI (POC) 2 | 3 | A GUI client for the [Helix editor](https://github.com/helix-editor/helix). It works by capturing and re-render the stdout of the TTY when Helix is running. 4 | 5 | Screenshot: _Helix-UI editing its own source code_ :P 6 | 7 | ![](./metadata/screenshot.gif) 8 | 9 | Some UI features can be implemented on top of it, for example, the rounded corner cursor and the editing mode badge. 10 | 11 | This is by no mean a good approach to implement UI, but it works. The right way to do this should be interacting with the actual rendering protocol. 12 | 13 | **Note:** To run this program, make sure you have helix installed at **/usr/local/bin/hx**, if the location on your machine is different, change it before compile. 14 | 15 | --- 16 | 17 | This piece of POC is [UNLICENSED](https://unlicense.org/), please feel free to do whatever you want with it. 18 | -------------------------------------------------------------------------------- /metadata/screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huytd/helix-ui/749297993b79ba55a09d12114cb730637ef723fc/metadata/screenshot.gif -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{fmt::Display, thread}; 2 | 3 | use druid::{ 4 | piet::{PietText, Text, TextAttribute, TextLayoutBuilder}, 5 | widget::Painter, 6 | AppDelegate, AppLauncher, Application, Color, Data, ExtEventSink, FontDescriptor, FontFamily, 7 | Handled, Rect, RenderContext, Selector, Target, TextLayout, Widget, WindowDesc, 8 | }; 9 | 10 | use once_cell::sync::OnceCell; 11 | use portable_pty::{native_pty_system, CommandBuilder, PtyPair, PtySize}; 12 | use vte::{Params, Parser, Perform}; 13 | 14 | #[derive(Clone, Copy, Debug, Data, PartialEq, Eq)] 15 | struct Cell { 16 | content: char, 17 | bg: Option, 18 | fg: Option, 19 | // TODO: inverse 20 | } 21 | 22 | impl Cell { 23 | pub fn new() -> Self { 24 | Self { 25 | content: ' ', 26 | bg: None, 27 | fg: None, 28 | } 29 | } 30 | 31 | pub fn set_content(&mut self, c: &char) { 32 | self.content = c.to_owned(); 33 | } 34 | 35 | pub fn set_bg(&mut self, color: Option<(u16, u16, u16)>) { 36 | if let Some(color) = color { 37 | let r = color.0 as f64 / 255.0; 38 | let g = color.1 as f64 / 255.0; 39 | let b = color.2 as f64 / 255.0; 40 | self.bg = Some(Color::rgb(r, g, b)); 41 | } else { 42 | self.bg = None; 43 | } 44 | } 45 | 46 | pub fn set_fg(&mut self, color: Option<(u16, u16, u16)>) { 47 | if let Some(color) = color { 48 | let r = color.0 as f64 / 255.0; 49 | let g = color.1 as f64 / 255.0; 50 | let b = color.2 as f64 / 255.0; 51 | self.fg = Some(Color::rgb(r, g, b)); 52 | } else { 53 | self.fg = None; 54 | } 55 | } 56 | } 57 | 58 | struct HelixUIState { 59 | grid: Vec>, 60 | cursor: (usize, usize), 61 | } 62 | 63 | const UPDATE_UI: Selector = Selector::new("helix-ui.update-screen"); 64 | const DESTROY_UI: Selector = Selector::new("helix-ui.destroy"); 65 | 66 | pub const NEWLINE_CHAR: char = 10 as char; 67 | pub const SPACE_CHAR: char = 32 as char; 68 | pub const TAB_CHAR: char = 9 as char; 69 | pub const BACK_CHAR: char = 8 as char; 70 | pub const ESC_CHAR: char = 27 as char; 71 | pub const CR_CHAR: char = 13 as char; 72 | pub const BELL_CHAR: char = 7 as char; 73 | 74 | struct ANSIParser { 75 | row: usize, 76 | col: usize, 77 | grid: Vec>, 78 | current_fg: Option<(u16, u16, u16)>, 79 | current_bg: Option<(u16, u16, u16)>, 80 | } 81 | 82 | impl ANSIParser { 83 | pub fn new() -> Self { 84 | Self { 85 | row: 0, 86 | col: 0, 87 | grid: vec![vec![Cell::new(); 81]; 25], 88 | current_fg: None, 89 | current_bg: None, 90 | } 91 | } 92 | } 93 | 94 | impl Perform for ANSIParser { 95 | fn print(&mut self, c: char) { 96 | self.grid[self.row][self.col].set_content(&c); 97 | self.grid[self.row][self.col].set_bg(self.current_bg); 98 | self.grid[self.row][self.col].set_fg(self.current_fg); 99 | self.col += 1; 100 | } 101 | 102 | fn execute(&mut self, _byte: u8) {} 103 | 104 | fn hook(&mut self, _params: &Params, _intermediates: &[u8], _ignore: bool, _c: char) {} 105 | 106 | fn put(&mut self, _byte: u8) {} 107 | 108 | fn unhook(&mut self) {} 109 | 110 | fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {} 111 | 112 | fn csi_dispatch(&mut self, params: &Params, _intermediates: &[u8], _ignore: bool, c: char) { 113 | // CSI sequences https://www.xfree86.org/current/ctlseqs.html 114 | // This list is better https://wezfurlong.org/wezterm/escape-sequences.html 115 | match c { 116 | // TODO: Handle [CSI Ps; m] for colors 117 | // [CSI Ps; Ps H] sequences to control the cursor 118 | 'm' => { 119 | let pm = params.iter().flatten().collect::>(); 120 | // println!("CSI :: {:?}", pm); 121 | 122 | let header = pm.iter().take(2).collect::>(); 123 | // [38; 2; R; G; B] = Foreground RGB 124 | // [48; 2; R; G; B] = Background RGB 125 | // [7] = Inverse On 126 | // [27] = Inverse Off 127 | // [39] = Foreground Default 128 | // [49] = Background Default 129 | // [0] = Reset 130 | match header[..] { 131 | [38, 2] => { 132 | self.current_fg = Some((*pm[2], *pm[3], *pm[4])); 133 | } 134 | [48, 2] => { 135 | self.current_bg = Some((*pm[2], *pm[3], *pm[4])); 136 | } 137 | [39] => { 138 | self.current_fg = None; 139 | } 140 | [49] => { 141 | self.current_bg = None; 142 | } 143 | [0] => { 144 | self.current_fg = None; 145 | self.current_bg = None; 146 | } 147 | _ => {} 148 | } 149 | } 150 | 'H' => { 151 | // cursor moving 152 | let mut p = params.iter(); 153 | let row = p.next().unwrap().first().unwrap(); 154 | let col = p.next().unwrap().first().unwrap(); 155 | self.row = row.saturating_sub(1).into(); 156 | self.col = col.saturating_sub(1).into(); 157 | } 158 | _ => {} 159 | } 160 | } 161 | 162 | fn esc_dispatch(&mut self, _intermediates: &[u8], _ignore: bool, _byte: u8) {} 163 | } 164 | 165 | #[derive(Debug, Clone, PartialEq, Eq, Data)] 166 | struct AppState { 167 | #[data(eq)] 168 | grid: Vec>, 169 | cursor_pos: (usize, usize), 170 | } 171 | 172 | fn ui() -> impl Widget { 173 | Painter::new(|ctx, data: &AppState, env| { 174 | let bg_color = data.grid[0][0].bg.unwrap_or(Color::TRANSPARENT); 175 | let screen_size = ctx.size(); 176 | let screen_rect = Rect::new(0., 0., screen_size.width, screen_size.height); 177 | let screen_bg_brush = ctx.solid_brush(bg_color); 178 | ctx.fill(screen_rect, &screen_bg_brush); 179 | 180 | // Calculate a single cell's size 181 | let mut letter_layout = TextLayout::::from_text("H"); 182 | letter_layout.set_font(FontDescriptor::new(FontFamily::MONOSPACE).with_size(12.0)); 183 | letter_layout.rebuild_if_needed(ctx.text(), env); 184 | let cell_size = letter_layout.size(); 185 | let cell_width = cell_size.width; 186 | let cell_height = cell_size.height; 187 | 188 | // Get current editing mode 189 | let mode: String = data.grid[22][1..4] 190 | .into_iter() 191 | .map(|cell| cell.content) 192 | .collect(); 193 | let should_draw_mode = ["NOR", "INS", "SEL"].contains(&&mode.as_str()); 194 | 195 | // Draw text content 196 | for row in 0..=24 { 197 | let text_ctx: &mut PietText = ctx.text(); 198 | let line_text = data.grid[row] 199 | .iter() 200 | .map(|cell| cell.content) 201 | .collect::(); 202 | let chars = line_text.chars().collect::>(); 203 | let mut byte_offset = 0; 204 | let mut layout_builder = text_ctx 205 | .new_text_layout(line_text) 206 | .font(FontFamily::MONOSPACE, 12.0) 207 | .text_color(Color::WHITE); 208 | 209 | for (col, cell) in data.grid[row].iter().enumerate() { 210 | if row < 22 || !should_draw_mode { 211 | let cell_rect = Rect::new( 212 | cell_width * col as f64, 213 | cell_height * row as f64, 214 | cell_width * col as f64 + cell_width, 215 | cell_height * row as f64 + cell_height, 216 | ); 217 | let cell_brush = ctx.solid_brush(cell.bg.unwrap_or(Color::TRANSPARENT)); 218 | ctx.fill(cell_rect, &cell_brush); 219 | } 220 | 221 | // Draw 222 | let text_color = cell.fg.unwrap_or(Color::WHITE); 223 | let ch = chars[col]; 224 | let ch_len = ch.len_utf8(); 225 | layout_builder = layout_builder.range_attribute( 226 | byte_offset..byte_offset + ch_len, 227 | TextAttribute::TextColor(text_color), 228 | ); 229 | byte_offset += ch_len; 230 | } 231 | 232 | let text_layout = layout_builder.build().unwrap(); 233 | ctx.draw_text(&text_layout, (0., cell_height * row as f64)); 234 | } 235 | 236 | // Draw mode badge 237 | let mut mode_text_layout = TextLayout::::from_text(mode.to_owned()); 238 | mode_text_layout.set_font(FontDescriptor::new(FontFamily::MONOSPACE).with_size(12.0)); 239 | mode_text_layout.set_text_color(Color::BLACK); 240 | mode_text_layout.rebuild_if_needed(ctx.text(), env); 241 | let mode_rect = Rect::new( 242 | cell_width * 1. - 2.5, 243 | cell_height * 22., 244 | cell_width * 1. + 3. * cell_width + 5.0, 245 | cell_height * 22. + cell_height, 246 | ) 247 | .to_rounded_rect(2.0); 248 | match mode.as_str() { 249 | "NOR" => { 250 | let normal_mode_brush = ctx.solid_brush(Color::rgb(0.68, 0.75, 0.75)); 251 | ctx.fill(mode_rect, &normal_mode_brush); 252 | mode_text_layout.draw(ctx, (cell_width * 1. + 2.5, cell_height * 22.)); 253 | } 254 | "INS" => { 255 | let insert_mode_brush = ctx.solid_brush(Color::rgb(0.28, 0.80, 0.54)); 256 | ctx.fill(mode_rect, &insert_mode_brush); 257 | mode_text_layout.draw(ctx, (cell_width * 1. + 2.5, cell_height * 22.)); 258 | } 259 | "SEL" => { 260 | let select_mode_brush = ctx.solid_brush(Color::rgb(0.71, 0.45, 0.71)); 261 | ctx.fill(mode_rect, &select_mode_brush); 262 | mode_text_layout.draw(ctx, (cell_width * 1. + 2.5, cell_height * 22.)); 263 | } 264 | _ => {} 265 | } 266 | 267 | // Draw cursor 268 | let (cursor_row, cursor_col) = data.cursor_pos; 269 | if cursor_row <= 24 && cursor_col <= 80 { 270 | let grid_rect = Rect::new( 271 | cell_width * cursor_col as f64, 272 | cell_height * cursor_row as f64, 273 | cell_width * cursor_col as f64 + cell_width, 274 | cell_height * cursor_row as f64 + cell_height, 275 | ) 276 | .to_rounded_rect(2.0); 277 | // Text under cursor 278 | let mut cursor_text_layout = 279 | TextLayout::::from_text(data.grid[cursor_row][cursor_col].content); 280 | cursor_text_layout.set_font(FontDescriptor::new(FontFamily::MONOSPACE).with_size(12.0)); 281 | cursor_text_layout.set_text_color(Color::BLACK); 282 | cursor_text_layout.rebuild_if_needed(ctx.text(), env); 283 | if mode.eq("INS") { 284 | let cursor_brush = ctx.solid_brush(Color::rgb(1.0, 0.87, 0.01)); 285 | ctx.stroke(grid_rect, &cursor_brush, 1.0); 286 | } else { 287 | let cursor_brush = ctx.solid_brush(Color::rgb(1.0, 0.87, 0.01)); 288 | ctx.fill(grid_rect, &cursor_brush); 289 | cursor_text_layout.draw( 290 | ctx, 291 | ( 292 | cell_width * cursor_col as f64, 293 | cell_height * cursor_row as f64, 294 | ), 295 | ); 296 | } 297 | } 298 | }) 299 | } 300 | 301 | struct Delegate; 302 | 303 | impl AppDelegate for Delegate { 304 | fn command( 305 | &mut self, 306 | _ctx: &mut druid::DelegateCtx, 307 | _target: Target, 308 | cmd: &druid::Command, 309 | data: &mut AppState, 310 | _env: &druid::Env, 311 | ) -> druid::Handled { 312 | if let Some(ui_state) = cmd.get(UPDATE_UI) { 313 | data.grid = ui_state.grid.to_vec(); 314 | data.cursor_pos = ui_state.cursor; 315 | return Handled::Yes; 316 | } 317 | if cmd.is(DESTROY_UI) { 318 | Application::global().quit(); 319 | return Handled::Yes; 320 | } 321 | druid::Handled::No 322 | } 323 | 324 | fn event( 325 | &mut self, 326 | _ctx: &mut druid::DelegateCtx, 327 | _window_id: druid::WindowId, 328 | event: druid::Event, 329 | _data: &mut AppState, 330 | _env: &druid::Env, 331 | ) -> Option { 332 | let original_event = event.clone(); 333 | match event { 334 | druid::Event::KeyDown(key_event) => { 335 | let modifiers = key_event.mods; 336 | let c = match key_event.key { 337 | druid::keyboard_types::Key::Escape => 27 as u8, 338 | druid::keyboard_types::Key::Backspace => 8 as u8, 339 | druid::keyboard_types::Key::Tab => 9 as u8, 340 | druid::keyboard_types::Key::Enter => 13 as u8, 341 | _ => { 342 | let chs = key_event.key.to_string().chars().next().unwrap(); 343 | if chs.is_lowercase() && chs.is_alphabetic() && modifiers.ctrl() { 344 | match chs { 345 | 'a' => 0x01 as u8, 346 | 'b' => 0x02 as u8, 347 | 'c' => 0x03 as u8, 348 | 'd' => 0x04 as u8, 349 | 'e' => 0x05 as u8, 350 | 'f' => 0x06 as u8, 351 | 'g' => 0x07 as u8, 352 | 'h' => 0x08 as u8, 353 | 'i' => 0x09 as u8, 354 | 'j' => 0x10 as u8, 355 | 'k' => 0x11 as u8, 356 | 'l' => 0x12 as u8, 357 | 'm' => 0x13 as u8, 358 | 'n' => 0x14 as u8, 359 | 'o' => 0x15 as u8, 360 | 'p' => 0x16 as u8, 361 | 'q' => 0x17 as u8, 362 | 'r' => 0x18 as u8, 363 | 's' => 0x19 as u8, 364 | 't' => 0x1a as u8, 365 | 'u' => 0x21 as u8, 366 | 'v' => 0x22 as u8, 367 | 'w' => 0x23 as u8, 368 | 'x' => 0x24 as u8, 369 | 'y' => 0x25 as u8, 370 | 'z' => 0x26 as u8, 371 | _ => chs as u8, 372 | } 373 | } else { 374 | key_event.key.legacy_charcode() as u8 375 | } 376 | } 377 | }; 378 | if c != 0 { 379 | if let Some(pair) = unsafe { PTY_WRITER.get_mut() } { 380 | _ = pair.0.master.write(&[c as u8]); 381 | } 382 | } 383 | } 384 | _ => {} 385 | } 386 | Some(original_event) 387 | } 388 | } 389 | 390 | static UI_EVENT_SINK: OnceCell = OnceCell::new(); 391 | 392 | struct PtyWriter(PtyPair); 393 | unsafe impl Send for PtyWriter {} 394 | unsafe impl Sync for PtyWriter {} 395 | 396 | static mut PTY_WRITER: OnceCell = OnceCell::new(); 397 | 398 | fn main() { 399 | let win = WindowDesc::new(ui()) 400 | .title("helix-ui") 401 | .window_size((600., 380.)); 402 | let app = AppLauncher::with_window(win); 403 | let event_sink = app.get_external_handle(); 404 | _ = UI_EVENT_SINK.set(event_sink); 405 | 406 | let pty_system = native_pty_system(); 407 | let pair = pty_system 408 | .openpty(PtySize { 409 | rows: 24, 410 | cols: 80, 411 | pixel_width: 0, 412 | pixel_height: 0, 413 | }) 414 | .unwrap(); 415 | let cmd = CommandBuilder::new("/usr/local/bin/hx"); 416 | _ = pair.slave.spawn_command(cmd).unwrap(); 417 | let mut reader = pair.master.try_clone_reader().unwrap(); 418 | _ = unsafe { PTY_WRITER.set(PtyWriter(pair)) }; 419 | 420 | thread::spawn(move || { 421 | let mut buf = [0u8; 128]; 422 | let mut parser = Parser::new(); 423 | let mut ansi = ANSIParser::new(); 424 | while let Ok(len) = reader.read(&mut buf) { 425 | if len == 0 { 426 | break; 427 | } 428 | for b in &buf[0..len] { 429 | parser.advance(&mut ansi, *b); 430 | } 431 | buf = [0u8; 128]; 432 | if let Some(sink) = UI_EVENT_SINK.get() { 433 | _ = sink.submit_command( 434 | UPDATE_UI, 435 | HelixUIState { 436 | grid: ansi.grid.to_vec(), 437 | cursor: (ansi.row, ansi.col), 438 | }, 439 | Target::Auto, 440 | ); 441 | } 442 | } 443 | // Helix exit 444 | if let Some(sink) = UI_EVENT_SINK.get() { 445 | _ = sink.submit_command(DESTROY_UI, (), Target::Auto); 446 | } 447 | }); 448 | 449 | _ = app.delegate(Delegate).launch(AppState { 450 | grid: vec![vec![Cell::new(); 81]; 25], 451 | cursor_pos: (0, 0), 452 | }); 453 | } 454 | --------------------------------------------------------------------------------