diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Cargo.lock | 798 | ||||
-rw-r--r-- | Cargo.toml | 5 | ||||
-rw-r--r-- | README.md | 80 | ||||
-rw-r--r-- | helix-core/.gitignore | 2 | ||||
-rw-r--r-- | helix-core/Cargo.toml | 11 | ||||
-rw-r--r-- | helix-core/src/lib.rs | 5 | ||||
-rw-r--r-- | helix-core/src/position.rs | 27 | ||||
-rw-r--r-- | helix-core/src/range.rs | 9 | ||||
-rw-r--r-- | helix-term/.gitignore | 1 | ||||
-rw-r--r-- | helix-term/Cargo.toml | 19 | ||||
-rw-r--r-- | helix-term/README.md | 7 | ||||
-rw-r--r-- | helix-term/src/line.rs | 111 | ||||
-rw-r--r-- | helix-term/src/main.rs | 227 |
14 files changed, 1303 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..eb5a316c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..3d182e52 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,798 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" + +[[package]] +name = "arc-swap" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b585a98a234c46fc563103e9278c9391fde1f4e6850334da895d27edb9580f62" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +dependencies = [ + "nodrop", +] + +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +dependencies = [ + "byteorder", +] + +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "blake2b_simd" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +dependencies = [ + "arrayref", + "arrayvec 0.5.1", + "constant_time_eq", +] + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "cassowary" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" + +[[package]] +name = "cfg-if" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "dirs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" +dependencies = [ + "cfg-if", + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +dependencies = [ + "cfg-if", + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "filedescriptor" +version = "0.7.1" +source = "git+https://github.com/wez/wezterm#58686f925f0f4a0942452e8feb0ababd48ec936c" +dependencies = [ + "anyhow", + "libc", + "thiserror", + "winapi", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "helix-core" +version = "0.1.0" + +[[package]] +name = "helix-term" +version = "0.1.0" +dependencies = [ + "anyhow", + "termwiz", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lexical-core" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86d66d380c9c5a685aaac7a11818bdfa1f733198dfd9ec09c70b762cd12ad6f" +dependencies = [ + "arrayvec 0.4.12", + "bitflags", + "cfg-if", + "rustc_version", + "ryu", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" + +[[package]] +name = "memmem" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15" + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "nom" +version = "5.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b471253da97532da4b61552249c521e01e736071f71c1a4f7ebbfbf0a06aad6" +dependencies = [ + "lexical-core", + "memchr", + "version_check", +] + +[[package]] +name = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "num-integer" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +dependencies = [ + "autocfg", +] + +[[package]] +name = "ordered-float" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" +dependencies = [ + "num-traits", +] + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53f5ffe53a6b28e37c9c1ce74893477864d64f74778a93a4beb43c8fa167f639" +dependencies = [ + "unicode-xid 0.2.0", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + +[[package]] +name = "quote" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" +dependencies = [ + "proc-macro2 1.0.13", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "redox_users" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" +dependencies = [ + "getrandom", + "redox_syscall", + "rust-argon2", +] + +[[package]] +name = "regex" +version = "1.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" + +[[package]] +name = "rust-argon2" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" +dependencies = [ + "base64 0.11.0", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" +dependencies = [ + "proc-macro2 1.0.13", + "quote 1.0.6", + "syn 1.0.22", +] + +[[package]] +name = "signal-hook" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ff2db2112d6c761e12522c65f7768548bd6e8cd23d2a9dae162520626629bd6" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" +dependencies = [ + "arc-swap", + "libc", +] + +[[package]] +name = "siphasher" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7" + +[[package]] +name = "smallvec" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" +dependencies = [ + "maybe-uninit", +] + +[[package]] +name = "static_assertions" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3" + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", +] + +[[package]] +name = "syn" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1425de3c33b0941002740a420b1a906a350b88d08b82b2c8a01035a3f9447bac" +dependencies = [ + "proc-macro2 1.0.13", + "quote 1.0.6", + "unicode-xid 0.2.0", +] + +[[package]] +name = "terminfo" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12064715207074ac562f450722884f981268a916ce1eb21c5bda2c806c8fecfc" +dependencies = [ + "dirs", + "fnv", + "nom", + "phf", + "phf_codegen", +] + +[[package]] +name = "termios" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0fcee7b24a25675de40d5bb4de6e41b0df07bc9856295e7e2b3a3600c400c2" +dependencies = [ + "libc", +] + +[[package]] +name = "termwiz" +version = "0.9.0" +source = "git+https://github.com/wez/wezterm#58686f925f0f4a0942452e8feb0ababd48ec936c" +dependencies = [ + "anyhow", + "base64 0.10.1", + "bitflags", + "cassowary", + "filedescriptor", + "fnv", + "lazy_static", + "libc", + "log", + "memmem", + "num", + "num-derive", + "num-traits", + "ordered-float", + "regex", + "semver", + "serde", + "signal-hook", + "smallvec", + "terminfo", + "termios", + "unicode-segmentation", + "unicode-width", + "vtparse", + "winapi", + "xi-unicode", +] + +[[package]] +name = "thiserror" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5976891d6950b4f68477850b5b9e5aa64d955961466f9e174363f573e54e8ca7" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab81dbd1cd69cd2ce22ecfbdd3bdb73334ba25350649408cc6c085f46d89573d" +dependencies = [ + "proc-macro2 1.0.13", + "quote 1.0.6", + "syn 1.0.22", +] + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" + +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + +[[package]] +name = "utf8parse" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" + +[[package]] +name = "version_check" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" + +[[package]] +name = "vtparse" +version = "0.2.2" +source = "git+https://github.com/wez/wezterm#58686f925f0f4a0942452e8feb0ababd48ec936c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "xi-unicode" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7395cdb9d0a6219fa0ea77d08c946adf9c1984c72fcd443ace30365f3daadef7" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..d84aef1d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,5 @@ +[workspace] +members = [ + "helix-core", + "helix-term", +] diff --git a/README.md b/README.md new file mode 100644 index 00000000..70eca234 --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +- server-client architecture via gRPC, UI separate from core +- multi cursor based editing and slicing +- WASM based plugins (builtin LSP & fuzzy file finder) +- piece table-based tree structure for changes + + +Structure similar to codemirror: + +text (ropes) +- column utils, stuff like tab aware (row, col) -> char pos translation +- word/grapheme/code point utils and iterators +state +- transactions + - changes + - annotations (time changed etc) + - state effects + - additional editor state as facets +- snapshots as an async view into current state +- selections { anchor (nonmoving), head (moving) from/to } -> SelectionSet with a primary + - cursor is just a single range selection +- markers + track a position inside text that synchronizes with edits +{ doc, selection, update(), splice, changes(), facets, tabSize, identUnit, lineSeparator, changeFilter/transactionFilter to modify stuff before } +view (actual UI) +- renders via termwiz +- viewport(Lines) -> what's actually visible +- extend the view via Decorations (inline styling) or Components (UI) + - mark / wieget / line / replace decoration +commands (transform state) +- movement +- selection extension +- deletion +- indentation +keymap (maps keys to commands) +history (undo tree via immutable ropes) +- undoes transactions +- invert changes (generates a revert) +(collab mode) +gutter (line numbers, diagnostic marker, etc) -> ties into UI components +rangeset/span -> mappable over changes (can be a marker primitive?) +syntax (treesitter) +- indentation strategies +fold +selections (select mode/multiselect) +matchbrackets +closebrackets +special-chars (shows dots etc for specials) +panel (for UI: file pickers, search dialogs, etc) +tooltip (for UI) +search (regex? pcre) +lint (async linters) +lsp +highlight (?) +stream-syntax +autocomplete +comment (gc, etc for auto commenting) +snippets + +terminal mode? + +plugins can contain more commands/ui abstractions to use elsewhere + +languageData as presets for each language (syntax, indent, comment, etc) + +TODO: determine rust vs script portions + +vim stuff: +motions/operators/text objects +full visual mode +macros +jump lists +marks +yank/paste +conceal for markdown markers, etc + + +--- + +codemirror uses offsets exclusively with Line being computed when necessary +(with start/end extents) diff --git a/helix-core/.gitignore b/helix-core/.gitignore new file mode 100644 index 00000000..96ef6c0b --- /dev/null +++ b/helix-core/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml new file mode 100644 index 00000000..446e8e42 --- /dev/null +++ b/helix-core/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "helix-core" +version = "0.1.0" +authors = ["Blaž Hrastnik <blaz@mxxn.io>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ropey = "1.1.0" +# slab = "0.4.2" diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs new file mode 100644 index 00000000..71a66030 --- /dev/null +++ b/helix-core/src/lib.rs @@ -0,0 +1,5 @@ +mod position; +mod range; + +use position::Position; +use range::Range; diff --git a/helix-core/src/position.rs b/helix-core/src/position.rs new file mode 100644 index 00000000..8c82b83b --- /dev/null +++ b/helix-core/src/position.rs @@ -0,0 +1,27 @@ +/// Represents a single point in a text buffer. Zero indexed. +#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Position { + pub row: usize, + pub col: usize, +} + +impl Position { + pub fn new(row: usize, col: usize) -> Self { + Self { row, col } + } + + pub fn is_zero(self) -> bool { + self.row == 0 && self.col == 0 + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_ordering() { + // (0, 5) is less than (1, 0 w v f) + assert!(Position::new(0, 5) < Position::new(1, 0)); + } +} diff --git a/helix-core/src/range.rs b/helix-core/src/range.rs new file mode 100644 index 00000000..46411664 --- /dev/null +++ b/helix-core/src/range.rs @@ -0,0 +1,9 @@ +use crate::Position; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct Range { + pub start: Position, + pub end: Position, +} + +// range traversal iters diff --git a/helix-term/.gitignore b/helix-term/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/helix-term/.gitignore @@ -0,0 +1 @@ +/target diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml new file mode 100644 index 00000000..f6528034 --- /dev/null +++ b/helix-term/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "helix-term" +version = "0.1.0" +authors = ["Blaž Hrastnik <blaz@mxxn.io>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[[bin]] +name = "hx" +path = "src/main.rs" + +# [[bin]] +# name = "line" +# path = "src/line.rs" + +[dependencies] +termwiz = { git = "https://github.com/wez/wezterm", features = ["widgets"] } +anyhow = "1.0.31" diff --git a/helix-term/README.md b/helix-term/README.md new file mode 100644 index 00000000..abefa6fd --- /dev/null +++ b/helix-term/README.md @@ -0,0 +1,7 @@ + +window -> buffer -> text +\-> contains "view", a viewport into the buffer + +view +\-> selections etc +-> cursor diff --git a/helix-term/src/line.rs b/helix-term/src/line.rs new file mode 100644 index 00000000..90fb5e6f --- /dev/null +++ b/helix-term/src/line.rs @@ -0,0 +1,111 @@ +use termwiz::cell::AttributeChange; +use termwiz::color::{AnsiColor, ColorAttribute, RgbColor}; +use termwiz::lineedit::*; + +#[derive(Default)] +struct Host { + history: BasicHistory, +} + +impl LineEditorHost for Host { + // Render the prompt with a darkslateblue background color if + // the terminal supports true color, otherwise render it with + // a navy blue ansi color. + fn render_prompt(&self, prompt: &str) -> Vec<OutputElement> { + vec![ + OutputElement::Attribute(AttributeChange::Background( + ColorAttribute::TrueColorWithPaletteFallback( + RgbColor::from_named("darkslateblue").unwrap(), + AnsiColor::Navy.into(), + ), + )), + OutputElement::Text(prompt.to_owned()), + ] + } + + fn history(&mut self) -> &mut dyn History { + &mut self.history + } + + /// Demo of the completion API for words starting with "h" or "he" + fn complete(&self, line: &str, cursor_position: usize) -> Vec<CompletionCandidate> { + let mut candidates = vec![]; + if let Some((range, word)) = word_at_cursor(line, cursor_position) { + let words = &["hello", "help", "he-man"]; + + for w in words { + if w.starts_with(word) { + candidates.push(CompletionCandidate { + range: range.clone(), + text: w.to_string(), + }); + } + } + } + candidates + } +} + +/// This is a conceptually simple function that computes the bounds +/// of the whitespace delimited word at the specified cursor position +/// in the supplied line string. +/// It returns the range and the corresponding slice out of the line. +/// This function is sufficient for example purposes; in a real application +/// the equivalent function would need to be aware of quoting and other +/// application specific context. +fn word_at_cursor(line: &str, cursor_position: usize) -> Option<(std::ops::Range<usize>, &str)> { + let char_indices: Vec<(usize, char)> = line.char_indices().collect(); + if char_indices.is_empty() { + return None; + } + let char_position = char_indices + .iter() + .position(|(idx, _)| *idx == cursor_position) + .unwrap_or(char_indices.len()); + + // Look back until we find whitespace + let mut start_position = char_position; + while start_position > 0 + && start_position <= char_indices.len() + && !char_indices[start_position - 1].1.is_whitespace() + { + start_position -= 1; + } + + // Look forwards until we find whitespace + let mut end_position = char_position; + while end_position < char_indices.len() && !char_indices[end_position].1.is_whitespace() { + end_position += 1; + } + + if end_position > start_position { + let range = char_indices[start_position].0 + ..char_indices + .get(end_position) + .map(|c| c.0 + 1) + .unwrap_or(line.len()); + Some((range.clone(), &line[range])) + } else { + None + } +} + +fn main() -> anyhow::Result<()> { + println!("Type `exit` to quit this example, or start a word with `h` and press Tab."); + let mut terminal = line_editor_terminal()?; + let mut editor = LineEditor::new(&mut terminal); + + let mut host = Host::default(); + loop { + if let Some(line) = editor.read_line(&mut host)? { + println!("read line: {:?}", line); + if line == "exit" { + break; + } + + host.history().add(&line); + } + } + + Ok(()) +} diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs new file mode 100644 index 00000000..e13309eb --- /dev/null +++ b/helix-term/src/main.rs @@ -0,0 +1,227 @@ +//! This example shows how to make a basic widget that accumulates +//! text input and renders it to the screen +#![allow(unused)] +use anyhow::Error; +use termwiz::caps::Capabilities; +use termwiz::cell::AttributeChange; +use termwiz::color::{AnsiColor, ColorAttribute, RgbColor}; +use termwiz::input::*; +use termwiz::surface::Change; +use termwiz::terminal::buffered::BufferedTerminal; +use termwiz::terminal::{new_terminal, Terminal}; +use termwiz::widgets::*; + +/// This is a widget for our application +struct MainScreen {} + +impl MainScreen { + pub fn new() -> Self { + Self {} + } +} + +impl Widget for MainScreen { + fn process_event(&mut self, event: &WidgetEvent, _args: &mut UpdateArgs) -> bool { + true // handled it all + } + + /// Draw ourselves into the surface provided by RenderArgs + fn render(&mut self, args: &mut RenderArgs) { + // args.surface.add_change(Change::ClearScreen( + // ColorAttribute::TrueColorWithPaletteFallback( + // RgbColor::new(0x31, 0x1B, 0x92), + // AnsiColor::Black.into(), + // ), + // )); + // args.surface + // .add_change(Change::Attribute(AttributeChange::Foreground( + // ColorAttribute::TrueColorWithPaletteFallback( + // RgbColor::new(0xB3, 0x88, 0xFF), + // AnsiColor::Purple.into(), + // ), + // ))); + } + + fn get_size_constraints(&self) -> layout::Constraints { + let mut constraints = layout::Constraints::default(); + constraints.child_orientation = layout::ChildOrientation::Vertical; + constraints + } +} + +struct Buffer<'a> { + /// Holds the input text that we wish the widget to display + text: &'a mut String, +} + +impl<'a> Buffer<'a> { + /// Initialize the widget with the input text + pub fn new(text: &'a mut String) -> Self { + Self { text } + } +} + +impl<'a> Widget for Buffer<'a> { + fn process_event(&mut self, event: &WidgetEvent, _args: &mut UpdateArgs) -> bool { + match event { + WidgetEvent::Input(InputEvent::Key(KeyEvent { + key: KeyCode::Char(c), + .. + })) => self.text.push(*c), + WidgetEvent::Input(InputEvent::Key(KeyEvent { + key: KeyCode::Enter, + .. + })) => { + self.text.push_str("\r\n"); + } + WidgetEvent::Input(InputEvent::Paste(s)) => { + self.text.push_str(&s); + } + _ => {} + } + + true // handled it all + } + + /// Draw ourselves into the surface provided by RenderArgs + fn render(&mut self, args: &mut RenderArgs) { + args.surface + .add_change(Change::ClearScreen(ColorAttribute::Default)); + + // args.surface + // .add_change(Change::Attribute(AttributeChange::Foreground( + // ColorAttribute::TrueColorWithPaletteFallback( + // RgbColor::new(0x11, 0x00, 0xFF), + // AnsiColor::Purple.into(), + // ), + // ))); + let dims = args.surface.dimensions(); + args.surface + .add_change(format!("🤷 surface size is {:?}\r\n", dims)); + args.surface.add_change(self.text.clone()); + + // Place the cursor at the end of the text. + // A more advanced text editing widget would manage the + // cursor position differently. + *args.cursor = CursorShapeAndPosition { + coords: args.surface.cursor_position().into(), + shape: termwiz::surface::CursorShape::SteadyBar, + ..Default::default() + }; + } + + fn get_size_constraints(&self) -> layout::Constraints { + let mut c = layout::Constraints::default(); + c.set_valign(layout::VerticalAlignment::Top); + c + } +} + +struct StatusLine {} + +impl StatusLine { + pub fn new() -> Self { + StatusLine {} + } +} +impl Widget for StatusLine { + fn process_event(&mut self, event: &WidgetEvent, _args: &mut UpdateArgs) -> bool { + true + } + + fn render(&mut self, args: &mut RenderArgs) { + args.surface.add_change(Change::ClearScreen( + ColorAttribute::TrueColorWithPaletteFallback( + RgbColor::new(0xFF, 0xFF, 0xFF), + AnsiColor::Black.into(), + ), + )); + args.surface + .add_change(Change::Attribute(AttributeChange::Foreground( + ColorAttribute::TrueColorWithPaletteFallback( + RgbColor::new(0x00, 0x00, 0x00), + AnsiColor::Black.into(), + ), + ))); + + args.surface.add_change(" helix"); + } + + fn get_size_constraints(&self) -> layout::Constraints { + *layout::Constraints::default() + .set_fixed_height(1) + .set_valign(layout::VerticalAlignment::Bottom) + } +} + +fn main() -> Result<(), Error> { + // Start with an empty string; typing into the app will + // update this string. + let mut typed_text = String::new(); + + { + // Create a terminal and put it into full screen raw mode + let caps = Capabilities::new_from_env()?; + let mut buf = BufferedTerminal::new(new_terminal(caps)?)?; + buf.terminal().enter_alternate_screen()?; + buf.terminal().set_raw_mode()?; + + // Set up the UI + let mut ui = Ui::new(); + + let root_id = ui.set_root(MainScreen::new()); + let buffer_id = ui.add_child(root_id, Buffer::new(&mut typed_text)); + // let root_id = ui.set_root(Buffer::new(&mut typed_text)); + ui.add_child(root_id, StatusLine::new()); + ui.set_focus(buffer_id); + + loop { + ui.process_event_queue()?; + + // After updating and processing all of the widgets, compose them + // and render them to the screen. + if ui.render_to_screen(&mut buf)? { + // We have more events to process immediately; don't block waiting + // for input below, but jump to the top of the loop to re-run the + // updates. + continue; + } + // Compute an optimized delta to apply to the terminal and display it + buf.flush()?; + + // Wait for user input + match buf.terminal().poll_input(None) { + Ok(Some(InputEvent::Resized { rows, cols })) => { + // FIXME: this is working around a bug where we don't realize + // that we should redraw everything on resize in BufferedTerminal. + buf.add_change(Change::ClearScreen(Default::default())); + buf.resize(cols, rows); + } + Ok(Some(input)) => match input { + InputEvent::Key(KeyEvent { + key: KeyCode::Escape, + .. + }) => { + // Quit the app when escape is pressed + break; + } + input @ _ => { + // Feed input into the Ui + ui.queue_event(WidgetEvent::Input(input)); + } + }, + Ok(None) => {} + Err(e) => { + print!("{:?}\r\n", e); + break; + } + } + } + } + + // After we've stopped the full screen raw terminal, + // print out the final edited value of the input text. + println!("The text you entered: {}", typed_text); + + Ok(()) +} |