aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock798
-rw-r--r--Cargo.toml5
-rw-r--r--README.md80
-rw-r--r--helix-core/.gitignore2
-rw-r--r--helix-core/Cargo.toml11
-rw-r--r--helix-core/src/lib.rs5
-rw-r--r--helix-core/src/position.rs27
-rw-r--r--helix-core/src/range.rs9
-rw-r--r--helix-term/.gitignore1
-rw-r--r--helix-term/Cargo.toml19
-rw-r--r--helix-term/README.md7
-rw-r--r--helix-term/src/line.rs111
-rw-r--r--helix-term/src/main.rs227
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(())
+}