WIP: Apply patches #6

Draft
Trivernis wants to merge 88 commits from old into main

@ -1,41 +0,0 @@
name: Github Pages
on:
push:
branches:
- master
tags:
- '*'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup mdBook
uses: peaceiris/actions-mdbook@v1
with:
mdbook-version: 'latest'
# mdbook-version: '0.4.8'
- run: mdbook build book
- name: Set output directory
run: |
OUTDIR=$(basename ${{ github.ref }})
echo "OUTDIR=$OUTDIR" >> $GITHUB_ENV
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./book/book
destination_dir: ./${{ env.OUTDIR }}
- name: Deploy stable
uses: peaceiris/actions-gh-pages@v3
if: startswith(github.ref, 'refs/tags/')
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./book/book

@ -116,8 +116,10 @@ jobs:
- name: Install ${{ matrix.rust }} toolchain
uses: dtolnay/rust-toolchain@master
with:
profile: minimal
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
override: true
# Install a pre-release version of Cross
# TODO: We need to pre-install Cross because we need cross-rs/cross#591 to
@ -137,8 +139,12 @@ jobs:
echo "target flag is: ${{ env.TARGET_FLAGS }}"
- name: Run cargo test
uses: actions-rs/cargo@v1
if: "!matrix.skip_tests"
run: ${{ env.CARGO }} test --release --locked --target ${{ matrix.target }} --workspace
with:
use-cross: ${{ matrix.cross }}
command: test
args: --release --locked --target ${{ matrix.target }} --workspace
- name: Set profile.release.strip = true
shell: bash

8
.idea/.gitignore vendored

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="CPP_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/helix.iml" filepath="$PROJECT_DIR$/.idea/helix.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

375
Cargo.lock generated

@ -84,20 +84,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bstr"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
dependencies = [
"lazy_static",
"memchr",
"regex-automata",
]
[[package]]
name = "bstr"
version = "1.0.1"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd"
checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b"
dependencies = [
"memchr",
"once_cell",
@ -250,15 +239,6 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossterm"
version = "0.25.0"
@ -287,9 +267,9 @@ dependencies = [
[[package]]
name = "cxx"
version = "1.0.82"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453"
checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579"
dependencies = [
"cc",
"cxxbridge-flags",
@ -299,9 +279,9 @@ dependencies = [
[[package]]
name = "cxx-build"
version = "1.0.82"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0"
checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70"
dependencies = [
"cc",
"codespan-reporting",
@ -314,15 +294,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
version = "1.0.82"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71"
checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c"
[[package]]
name = "cxxbridge-macro"
version = "1.0.82"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470"
checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5"
dependencies = [
"proc-macro2",
"quote",
@ -339,7 +319,7 @@ dependencies = [
"hashbrown 0.12.3",
"lock_api",
"once_cell",
"parking_lot_core 0.9.4",
"parking_lot_core 0.9.6",
]
[[package]]
@ -448,9 +428,9 @@ dependencies = [
[[package]]
name = "filetime"
version = "0.2.18"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3"
checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9"
dependencies = [
"cfg-if",
"libc",
@ -545,7 +525,7 @@ version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9e5fd7bc63ad527d64584f8d01f99b89c051f5fbb8144b58ae5f812775065cf"
dependencies = [
"bstr 1.0.1",
"bstr",
"btoi",
"git-date",
"itoa",
@ -555,11 +535,11 @@ dependencies = [
[[package]]
name = "git-attributes"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8013dfce47c1e29236d732308933e2c77af5355ec5105755d26faf7764d3f7b"
checksum = "b2c9687a890892650e8574e123b4b633d277b99953cb877dc02aba852a0139fa"
dependencies = [
"bstr 1.0.1",
"bstr",
"compact_str",
"git-features",
"git-glob",
@ -589,20 +569,20 @@ dependencies = [
[[package]]
name = "git-command"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "215145cc1686a45bc6f9872b153a0d3f3c40a1b94173a928325e1b53dfa5e2af"
checksum = "5a19fe1efc0b4969b2b2a14621f6cf6a007cf6cbabcf344e078271b65d1f7cef"
dependencies = [
"bstr 1.0.1",
"bstr",
]
[[package]]
name = "git-config"
version = "0.15.0"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9da662fd64ac69772158dcf04777da6266f0f36bc9a310b3eb2d805bb696315"
checksum = "500cc0517781f9f573c4dc26feb3ae0cdc28ae7160a81ef104590943984f6a8e"
dependencies = [
"bstr 1.0.1",
"bstr",
"git-config-value",
"git-features",
"git-glob",
@ -624,7 +604,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "989a90c1c630513a153c685b4249b96fdf938afc75bf7ef2ae1ccbd3d799f5db"
dependencies = [
"bitflags",
"bstr 1.0.1",
"bstr",
"git-path",
"libc",
"thiserror",
@ -636,7 +616,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97cd6bbe001afd6356b35ef13f2a6b0f0abc0133d1b2ecaec1033bdd769616d6"
dependencies = [
"bstr 1.0.1",
"bstr",
"git-command",
"git-config-value",
"git-path",
@ -648,11 +628,11 @@ dependencies = [
[[package]]
name = "git-date"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "412c9b89026505bd24d5f8acafa578de6eea3b271ece307a73b8e646e671302a"
checksum = "3777ed3a92334193bc5032d468dee2ddb7d1101263e58e0d2edcc308c06948b5"
dependencies = [
"bstr 1.0.1",
"bstr",
"itoa",
"thiserror",
"time",
@ -672,11 +652,11 @@ dependencies = [
[[package]]
name = "git-discover"
version = "0.12.0"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e9e26e0bc434643228cd418185bd28ca5c7cf831bde1da434807391c27ac40e"
checksum = "a2738a9941f1411cff31e6ea4399a6c7304cc3ea34fb8c1c6f1aef1f667d46cc"
dependencies = [
"bstr 1.0.1",
"bstr",
"git-hash",
"git-path",
"git-ref",
@ -686,9 +666,9 @@ dependencies = [
[[package]]
name = "git-features"
version = "0.26.0"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ff74064fa007c5beefa89a64bb72834f32b3c497750a56c79c6802bbdb311f9"
checksum = "0019327672cb759f851d1b18fdcc36bb797dc62b925cb93c8c881b54735eb2c2"
dependencies = [
"crc32fast",
"flate2",
@ -703,12 +683,12 @@ dependencies = [
[[package]]
name = "git-glob"
version = "0.5.1"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3908404c9b76ac7b3f636a104142378d3eaa78623cbc6eb7c7f0651979d48e8a"
checksum = "aa73cf9c9c1a66e28de1cf250fc1ebe323e7c7c59768c1a2331e3b3308e783a3"
dependencies = [
"bitflags",
"bstr 1.0.1",
"bstr",
]
[[package]]
@ -728,18 +708,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c52b625ad8cc360a0b7f426266f21fb07bd49b8f4ccf1b3ca7bc89424db1dec4"
dependencies = [
"git-hash",
"hashbrown 0.13.1",
"hashbrown 0.13.2",
]
[[package]]
name = "git-index"
version = "0.12.1"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "485da97dd4f69c7d9a8dc238cd6f4a726387ffc34573489e8e0d2bee266e3454"
checksum = "b82fd3d70ed6fbceb7573f145fbf79371e4d0c8dbdf7ad46f3a03328239ddda7"
dependencies = [
"atoi",
"bitflags",
"bstr 1.0.1",
"bstr",
"filetime",
"git-bitmap",
"git-features",
@ -755,9 +735,9 @@ dependencies = [
[[package]]
name = "git-lock"
version = "3.0.0"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89e4f05b8a68c3a5dd83a6651c76be384e910fe283072184fdab9d77f87ccec2"
checksum = "e7cf6a3c9d1a9932bb9bcb7e0044e2e429f9d94711969a7d2a09e34ae21f6437"
dependencies = [
"fastrand",
"git-tempfile",
@ -766,11 +746,11 @@ dependencies = [
[[package]]
name = "git-mailmap"
version = "0.9.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0316b4346f3e162ade368209efb8a609b587793c74aa3b8de0ec01a4f3580120"
checksum = "1957f2f550e345f70cb0615d390fb0446d41eeb5bc87824b7bae31efd8cfc2da"
dependencies = [
"bstr 1.0.1",
"bstr",
"git-actor",
"quick-error",
]
@ -781,7 +761,7 @@ version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f8563e2d6f524d7053f3106714f99ecdc3adbba2cb7108c09d71a02579f2e19"
dependencies = [
"bstr 1.0.1",
"bstr",
"btoi",
"git-actor",
"git-features",
@ -796,9 +776,9 @@ dependencies = [
[[package]]
name = "git-odb"
version = "0.40.0"
version = "0.40.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "616115a0e3daff6e08842758d24547b37a6eb6d0e2eedd95a740c3aaa2750333"
checksum = "b43514e1d1062613352a10f96d48e69967f4c420776596e1af9a6f368df2eea2"
dependencies = [
"arc-swap",
"git-features",
@ -814,9 +794,9 @@ dependencies = [
[[package]]
name = "git-pack"
version = "0.30.0"
version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cd16b88f4b66041f41ca510c28bd81c4ee7363c5a544b3d62b4170432965871"
checksum = "9e124d13e4e4b53ca7544e9786f30dafe2e76b4a75ba62b2156ee0656b356c71"
dependencies = [
"bytesize",
"clru",
@ -842,15 +822,15 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e40e68481a06da243d3f4dfd86a4be39c24eefb535017a862e845140dcdb878a"
dependencies = [
"bstr 1.0.1",
"bstr",
"thiserror",
]
[[package]]
name = "git-prompt"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3612a486e507dd431ef0f7108eeaafc8fd1ed7bd0f205a88554f6f91fe5dccbf"
checksum = "ad3f84ec28896f6a4b3f3174a1125117ac91788b1c64d96f25eabcd8d01cc7e3"
dependencies = [
"git-command",
"git-config-value",
@ -865,16 +845,16 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd11f4e7f251ab297545faa4c5a4517f4985a43b9c16bf96fa49107f58e837f"
dependencies = [
"bstr 1.0.1",
"bstr",
"btoi",
"quick-error",
]
[[package]]
name = "git-ref"
version = "0.23.0"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6767925a6fc4af5c5a81e348d1d851c1b3ab2b512bd7f562ac11be37c14468"
checksum = "2a2c29bab109acaf626d49a54f1f85ab7f0911268fbf62c2b39680ef4ef19069"
dependencies = [
"git-actor",
"git-features",
@ -891,11 +871,11 @@ dependencies = [
[[package]]
name = "git-refspec"
version = "0.7.0"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddf310ed5f2829ac0af96e7d4aebd4ae4b89f0718a7ae3666d09b02b2c5a1dfd"
checksum = "419fba469ca7dca4746de8b2be6a21990b276f3974acaa94314f39d4c2bbfc0a"
dependencies = [
"bstr 1.0.1",
"bstr",
"git-hash",
"git-revision",
"git-validate",
@ -905,9 +885,9 @@ dependencies = [
[[package]]
name = "git-repository"
version = "0.32.0"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "993277960cb7e2d3991a11c1ec6951c1d142de052c26a18d2db64304e52d3741"
checksum = "1a958d3fa83660d15c6535765477a8895156bdd6a922dbd0fc445afa42f4b534"
dependencies = [
"git-actor",
"git-attributes",
@ -948,11 +928,11 @@ dependencies = [
[[package]]
name = "git-revision"
version = "0.10.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f9a6bd28c9d1676bb96f428cd09614ae18a0087d7cea1cebfd177e25f99b2af"
checksum = "bfc3f7c901777f8318f059dbdf73dbda05acdb36c631fe12465bd955e230a205"
dependencies = [
"bstr 1.0.1",
"bstr",
"git-date",
"git-hash",
"git-hashtable",
@ -962,9 +942,9 @@ dependencies = [
[[package]]
name = "git-sec"
version = "0.6.0"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1802e8252fa223b0ad89a393aed461132174ced1e6842a41f56dc92a3fc14f"
checksum = "6696a816445a51f76995d579a3122f98247377cc45cd681764f740f3a2666004"
dependencies = [
"bitflags",
"dirs",
@ -975,9 +955,9 @@ dependencies = [
[[package]]
name = "git-tempfile"
version = "3.0.0"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6bb4dee86c8cae5a078cfaac3b004ef99c31548ed86218f23a7ff9b4b74f3be"
checksum = "2d851911a2b043dc1ab6cd5432ce7a3ee3a2fd614ed87428cec1b15f5abb7e0c"
dependencies = [
"dashmap",
"libc",
@ -1001,11 +981,11 @@ dependencies = [
[[package]]
name = "git-url"
version = "0.13.0"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85af407ed0dbb8d8da2a7241827d2fd5681186d9dab3570fc8dd8d6152ec48f"
checksum = "cc9a3df0498c511cf34739eab2692352939b54075c2fc96e8f688d402f3f1250"
dependencies = [
"bstr 1.0.1",
"bstr",
"git-features",
"git-path",
"home",
@ -1019,17 +999,17 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0431cf9352c596dc7c8ec9066ee551ce54e63c86c3c767e5baf763f6019ff3c2"
dependencies = [
"bstr 1.0.1",
"bstr",
"thiserror",
]
[[package]]
name = "git-worktree"
version = "0.12.0"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3bc63878f134e08ed52dba5d82422798c01a3f2e48c38ae9a2f7ff9194f362"
checksum = "0c28b292694c98bba8225c39d4e86605843882ba7117ca98491841761e710547"
dependencies = [
"bstr 1.0.1",
"bstr",
"git-attributes",
"git-features",
"git-glob",
@ -1043,12 +1023,12 @@ dependencies = [
[[package]]
name = "globset"
version = "0.4.9"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc"
dependencies = [
"aho-corasick",
"bstr 0.2.17",
"bstr",
"fnv",
"log",
"regex",
@ -1056,21 +1036,21 @@ dependencies = [
[[package]]
name = "grep-matcher"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d27563c33062cd33003b166ade2bb4fd82db1fd6a86db764dfdad132d46c1cc"
checksum = "3902ca28f26945fe35cad349d776f163981d777fee382ccd6ef451126f51b319"
dependencies = [
"memchr",
]
[[package]]
name = "grep-regex"
version = "0.1.10"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1345f8d33c89f2d5b081f2f2a41175adef9fd0bed2fea6a26c96c2deb027e58e"
checksum = "997598b41d53a37a2e3fc5300d5c11d825368c054420a9c65125b8fe1078463f"
dependencies = [
"aho-corasick",
"bstr 0.2.17",
"bstr",
"grep-matcher",
"log",
"regex",
@ -1080,11 +1060,11 @@ dependencies = [
[[package]]
name = "grep-searcher"
version = "0.1.10"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48852bd08f9b4eb3040ecb6d2f4ade224afe880a9a0909c5563cc59fa67932cc"
checksum = "5601c4b9f480f0c9ebb40b1f6cbf447b8a50c5369223937a6c5214368c58779f"
dependencies = [
"bstr 0.2.17",
"bstr",
"bytecount",
"encoding_rs",
"encoding_rs_io",
@ -1104,9 +1084,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.13.1"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [
"ahash 0.8.2",
]
@ -1121,7 +1101,7 @@ dependencies = [
"chrono",
"encoding_rs",
"etcetera",
"hashbrown 0.13.1",
"hashbrown 0.13.2",
"helix-loader",
"imara-diff",
"log",
@ -1288,9 +1268,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.1.19"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
@ -1352,11 +1332,10 @@ dependencies = [
[[package]]
name = "ignore"
version = "0.4.18"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d"
checksum = "a05705bc64e0b66a806c3740bd6578ea66051b157ec42dc219c785cbf185aef3"
dependencies = [
"crossbeam-utils",
"globset",
"lazy_static",
"log",
@ -1405,9 +1384,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.4"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "js-sys"
@ -1426,9 +1405,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.137"
version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "libloading"
@ -1442,9 +1421,9 @@ dependencies = [
[[package]]
name = "link-cplusplus"
version = "1.0.7"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369"
checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
dependencies = [
"cc",
]
@ -1537,9 +1516,9 @@ dependencies = [
[[package]]
name = "nom"
version = "7.1.1"
version = "7.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c"
dependencies = [
"memchr",
"minimal-lexical",
@ -1566,9 +1545,9 @@ dependencies = [
[[package]]
name = "num_cpus"
version = "1.14.0"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [
"hermit-abi",
"libc",
@ -1607,7 +1586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core 0.9.4",
"parking_lot_core 0.9.6",
]
[[package]]
@ -1626,9 +1605,9 @@ dependencies = [
[[package]]
name = "parking_lot_core"
version = "0.9.4"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf"
dependencies = [
"cfg-if",
"libc",
@ -1657,9 +1636,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "proc-macro2"
version = "1.0.47"
version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
dependencies = [
"unicode-ident",
]
@ -1704,9 +1683,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.21"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
@ -1793,15 +1772,15 @@ dependencies = [
[[package]]
name = "rustversion"
version = "1.0.9"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8"
checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70"
[[package]]
name = "ryu"
version = "1.0.11"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "same-file"
@ -1820,9 +1799,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "scratch"
version = "1.0.2"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
[[package]]
name = "serde"
@ -1857,9 +1836,9 @@ dependencies = [
[[package]]
name = "serde_repr"
version = "0.1.9"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca"
checksum = "9a5ec9fa74a20ebbe5d9ac23dac1fc96ba0ecfe9f50f2843b52e537b10fbcb4e"
dependencies = [
"proc-macro2",
"quote",
@ -1979,15 +1958,15 @@ checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0"
[[package]]
name = "str_indices"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d9199fa80c817e074620be84374a520062ebac833f358d74b37060ce4a0f2c0"
checksum = "5f026164926842ec52deb1938fae44f83dfdb82d0a5b0270c5bd5935ab74d6dd"
[[package]]
name = "syn"
version = "1.0.104"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce"
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
@ -2141,9 +2120,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
version = "1.8.0"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
dependencies = [
"proc-macro2",
"quote",
@ -2209,9 +2188,9 @@ checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7"
[[package]]
name = "unicode-ident"
version = "1.0.5"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "unicode-linebreak"
@ -2377,17 +2356,17 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.40.0"
version = "0.43.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e30acc718a52fb130fec72b1cb5f55ffeeec9253e1b785e94db222178a6acaa1"
checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244"
dependencies = [
"windows_aarch64_gnullvm 0.40.0",
"windows_aarch64_msvc 0.40.0",
"windows_i686_gnu 0.40.0",
"windows_i686_msvc 0.40.0",
"windows_x86_64_gnu 0.40.0",
"windows_x86_64_gnullvm 0.40.0",
"windows_x86_64_msvc 0.40.0",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
@ -2396,98 +2375,56 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm 0.42.0",
"windows_aarch64_msvc 0.42.0",
"windows_i686_gnu 0.42.0",
"windows_i686_msvc 0.42.0",
"windows_x86_64_gnu 0.42.0",
"windows_x86_64_gnullvm 0.42.0",
"windows_x86_64_msvc 0.42.0",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.40.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3caa4a1a16561b714323ca6b0817403738583033a6a92e04c5d10d4ba37ca10"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
version = "0.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "328973c62dfcc50fb1aaa8e7100676e0b642fe56bac6bafff3327902db843ab4"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
[[package]]
name = "windows_i686_gnu"
version = "0.40.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa5b09fad70f0df85dea2ac2a525537e415e2bf63ee31cf9b8e263645ee9f3c1"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_i686_gnu"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
[[package]]
name = "windows_i686_msvc"
version = "0.40.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a1ad4031c1a98491fa195d8d43d7489cb749f135f2e5c4eed58da094bd0d876"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_msvc"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_x86_64_gnu"
version = "0.40.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520ff37edd72da8064b49d2281182898e17f0688ae9f4070bca27e4b5c162ac7"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046e5b82215102c44fd75f488f1b9158973d02aa34d06ed85c23d6f5520a2853"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_msvc"
version = "0.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0c9c6df55dd1bfa76e131cef44bdd8ec9c819ef3611f04dfe453fd5bfeda28"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "xtask"

@ -1,20 +1,6 @@
<div align="center">
<h1>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="logo_dark.svg">
<source media="(prefers-color-scheme: light)" srcset="logo_light.svg">
<img alt="Helix" height="128" src="logo_light.svg">
</picture>
</h1>
# Helix
[![Build status](https://github.com/helix-editor/helix/actions/workflows/build.yml/badge.svg)](https://github.com/helix-editor/helix/actions)
[![GitHub Release](https://img.shields.io/github/v/release/helix-editor/helix)](https://github.com/helix-editor/helix/releases/latest)
[![Documentation](https://shields.io/badge/-documentation-452859)](https://docs.helix-editor.com/)
[![GitHub contributors](https://img.shields.io/github/contributors/helix-editor/helix)](https://github.com/helix-editor/helix/graphs/contributors)
[![Matrix Space](https://img.shields.io/matrix/helix-community:matrix.org)](https://matrix.to/#/#helix-community:matrix.org)
</div>
![Screenshot](./screenshot.png)
@ -139,7 +125,3 @@ Contributing guidelines can be found [here](./docs/CONTRIBUTING.md).
Your question might already be answered on the [FAQ](https://github.com/helix-editor/helix/wiki/FAQ).
Discuss the project on the community [Matrix Space](https://matrix.to/#/#helix-community:matrix.org) (make sure to join `#helix-editor:matrix.org` if you're on a client that doesn't support Matrix Spaces yet).
# Credits
Thanks to [@JakeHL](https://github.com/JakeHL) for designing the logo!

@ -52,6 +52,7 @@ on unix operating systems.
| `auto-save` | Enable automatic saving on focus moving away from Helix. Requires [focus event support](https://github.com/helix-editor/helix/wiki/Terminal-Support) from your terminal. | `false` |
| `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant. | `400` |
| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
| `completion-trigger-chars` | The chars that trigger completion (additional to all word chars) | `['.', ':']` |
| `auto-info` | Whether to display infoboxes | `true` |
| `true-color` | Set to `true` to override automatic detection of terminal truecolor support in the event of a false negative. | `false` |
| `rulers` | List of column positions at which to display the rulers. Can be overridden by language specific `rulers` in `languages.toml` file. | `[]` |
@ -172,6 +173,8 @@ auto-pairs = false # defaults to `true`
The default pairs are <code>(){}[]''""``</code>, but these can be customized by
setting `auto-pairs` to a TOML table:
Example
```toml
[editor.auto-pairs]
'(' = ')'
@ -237,22 +240,85 @@ tab = "→"
newline = "⏎"
tabpad = "·" # Tabs will look like "→···" (depending on tab width)
```
<<<<<<< HEAD
### `[editor.explorer]` Section
Sets explorer side width and style.
| Key | Description | Default |
| --- | ----------- | ------- |
| `column-width` | explorer side width | 30 |
| `style` | explorer item style, tree or list | tree |
| `position` | explorer widget position, embed or overlay | overlay |
||||||| 43027d91
=======
### `[editor.indent-guides]` Section
Options for rendering vertical indent guides.
<<<<<<< HEAD
| Key | Description | Default |
| --- | --- | --- |
| `render` | Whether to render indent guides. | `true` |
| `character` | Literal character to use for rendering the indent guide | `│` |
| `rainbow` | Whether or not the indent guides shall have changing colors. | `false` |
| `skip-levels` | Number of indent levels to skip | `0` |
||||||| merged common ancestors
<<<<<<<<< Temporary merge branch 1
| Key | Description | Default |
| --- | --- | --- |
| `render` | Whether to render indent guides. | `false` |
| `character` | Literal character to use for rendering the indent guide | `│` |
| `rainbow` | Whether or not the indent guides shall have changing colors. | `false` |
||||||||| 60aa7d36
| Key | Description | Default |
| --- | --- | --- |
| `render` | Whether to render indent guides. | `false` |
| `character` | Literal character to use for rendering the indent guide | `│` |
=========
| Key | Description | Default |
| --- | --- | --- |
| `render` | Whether to render indent guides. | `false` |
| `character` | Literal character to use for rendering the indent guide | `│` |
| `skip-levels` | Number of indent levels to skip | `0` |
>>>>>>>>> Temporary merge branch 2
=======
| Key | Description | Default |
| --- | --- | --- |
| `render` | Whether to render indent guides. | `false` |
| `character` | Literal character to use for rendering the indent guide | `│` |
| `rainbow` | Whether or not the indent guides shall have changing colors. It can be `none`, `dim` or `normal`| `none` |
| `skip-levels` | Number of indent levels to skip | `0` |
>>>>>>> colored-indent-guides
Example:
```toml
[editor.indent-guides]
render = true
character = "╎"
<<<<<<< HEAD
rainbow = true
||||||| merged common ancestors
rainbow = true
||||||||| 60aa7d36
character = "╎"
=========
character = "╎" # Some characters that work well: "▏", "┆", "┊", "⸽"
=======
rainbow = "normal"
character = "╎" # Some characters that work well: "▏", "┆", "┊", "⸽"
>>>>>>> colored-indent-guides
skip-levels = 1
```
### `[editor.explorer]` Section
Sets explorer side width and style.
| Key | Description | Default |
| --- | ----------- | ------- |
| `column-width` | explorer side width | 30 |
| `style` | explorer item style, tree or list | tree |
| `position` | explorer widget position, embed or overlay | overlay |
>>>>>>> 0e04c4c93caadb704c11a72bcf626b1f10ff2d98

@ -73,3 +73,4 @@
| `:pipe` | Pipe each selection to the shell command. |
| `:pipe-to` | Pipe each selection to the shell command, ignoring output. |
| `:run-shell-command`, `:sh` | Run a shell command |
| `:lsp-restart` | Restarts the LSP server of the current buffer |

@ -287,6 +287,8 @@ This layer is a kludge of mappings, mostly pickers.
| `R` | Replace selections by clipboard contents | `replace_selections_with_clipboard` |
| `/` | Global search in workspace folder | `global_search` |
| `?` | Open command palette | `command_palette` |
| `e` | Open or focus explorer | `toggle_or_focus_explorer` |
| `E` | open explorer recursion | `open_explorer_recursion` |
> TIP: Global search displays results in a fuzzy picker, use `Space + '` to bring it back up after opening a file.
@ -437,3 +439,35 @@ Keys to use within prompt, Remapping currently not supported.
| `Tab` | Select next completion item |
| `BackTab` | Select previous completion item |
| `Enter` | Open selected |
# File explorer
Keys to use within explorer, Remapping currently not supported.
| Key | Description |
| ----- | ------------- |
| `Escape` | Back to editor |
| `Ctrl-c` | Close explorer |
| `Enter` | Open file or toggle dir selected |
| `b` | Back to current root's parent |
| `f` | Filter items |
| `z` | Fold currrent level |
| `k`, `Shift-Tab`, `Up` | select previous item |
| `j`, `Tab`, `Down` | select next item |
| `h` | Scroll left |
| `l` | Scroll right |
| `G` | Move to last item |
| `Ctrl-d` | Move down half page |
| `Ctrl-u` | Move up half page |
| `Shift-d` | Move down a page |
| `Shift-u` | Move up a page |
| `/` | Search item |
| `?` | Search item reverse |
| `n` | Repeat last search |
| `Shift-n` | Repeat last search reverse |
| `gg` | Move to first item |
| `ge` | Move to last item |
| `gc` | Make current dir as root dir |
| `mf` | Create new file under current item's parent |
| `md` | Create new dir under current item's parent |
| `rf` | Remove file selected |
| `rd` | Remove dir selected |

@ -107,6 +107,35 @@ Some styles might not be supported by your terminal emulator.
| `double_line` |
<<<<<<< HEAD
<<<<<<< HEAD
### Rainbow
The `rainbow` key is used for rainbow highlight for matching brackets.
The key is a list of styles.
```toml
rainbow = ["#ff0000", "#ffa500", "#fff000", { fg = "#00ff00", modifiers = ["bold"] }]
```
Colors from the palette and modifiers may be used.
||||||| 60aa7d36
=======
||||||| merged common ancestors
=======
### Rainbow
The `rainbow` key is used for rainbow highlight for matching brackets.
The key is a list of styles.
```toml
rainbow = ["#ff0000", "#ffa500", "#fff000", { fg = "#00ff00", modifiers = ["bold"] }]
```
Colors from the palette and modifiers may be used.
>>>>>>> colored-indent-guides
### Inheritance
Extend upon other themes by setting the `inherits` property to an existing theme.
@ -122,6 +151,22 @@ inherits = "boo_berry"
berry = "#2A2A4D"
```
<<<<<<< HEAD
>>>>>>> seperate_code_action
||||||| merged common ancestors
### Rainbow
The `rainbow` key is used for rainbow highlight for matching brackets.
The key is a list of styles.
```toml
rainbow = ["#ff0000", "#ffa500", "#fff000", { fg = "#00ff00", modifiers = ["bold"] }]
```
Colors from the palette and modifiers may be used.
=======
>>>>>>> colored-indent-guides
### Scopes
The following is a list of scopes available to use for styling.

@ -1 +0,0 @@
../runtime/themes

@ -18,34 +18,34 @@ integration = []
helix-loader = { version = "0.6", path = "../helix-loader" }
ropey = { version = "1.5.1", default-features = false, features = ["simd"] }
smallvec = "1.10"
smallvec = "1.10.0"
smartstring = "1.0.1"
unicode-segmentation = "1.10"
unicode-width = "0.1"
unicode-general-category = "0.6"
unicode-segmentation = "1.10.0"
unicode-width = "0.1.10"
unicode-general-category = "0.6.0"
# slab = "0.4.2"
slotmap = "1.0"
tree-sitter = "0.20"
once_cell = "1.17"
arc-swap = "1"
regex = "1"
bitflags = "1.3"
slotmap = "1.0.6"
tree-sitter = "0.20.9"
once_cell = "1.17.0"
arc-swap = "1.6.0"
regex = "1.7.1"
bitflags = "1.3.2"
ahash = "0.8.2"
hashbrown = { version = "0.13.1", features = ["raw"] }
hashbrown = { version = "0.13.2", features = ["raw"] }
log = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
toml = "0.5"
log = "0.4.17"
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.91"
toml = "0.5.10"
imara-diff = "0.1.0"
imara-diff = "0.1.5"
encoding_rs = "0.8"
encoding_rs = "0.8.31"
chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }
chrono = { version = "0.4.23", default-features = false, features = ["alloc", "std"] }
etcetera = "0.4"
etcetera = "0.4.0"
textwrap = "0.16.0"
[dev-dependencies]
quickcheck = { version = "1", default-features = false }
quickcheck = { version = "1.0.3", default-features = false }

@ -190,6 +190,8 @@ pub fn ensure_grapheme_boundary_next(slice: RopeSlice, char_idx: usize) -> usize
pub fn ensure_grapheme_boundary_prev(slice: RopeSlice, char_idx: usize) -> usize {
if char_idx == slice.len_chars() {
char_idx
} else if char_idx > slice.len_chars() {
slice.len_chars()
} else {
prev_grapheme_boundary(slice, char_idx + 1)
}

@ -394,10 +394,12 @@ impl ChangeSet {
}
if pos > old_pos {
panic!(
log::error!(
"Position {} is out of range for changeset len {}!",
pos, old_pos
)
pos,
old_pos
);
return old_pos;
}
new_pos
}

@ -1 +0,0 @@
../../../src/indent.rs

@ -13,13 +13,13 @@ homepage = "https://helix-editor.com"
[dependencies]
helix-core = { version = "0.6", path = "../helix-core" }
anyhow = "1.0"
log = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "net", "sync"] }
which = "4.2"
anyhow = "1.0.68"
log = "0.4.17"
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.91"
thiserror = "1.0.38"
tokio = { version = "1.24.1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "net", "sync"] }
which = "4.3.0"
[dev-dependencies]
fern = "0.6"
fern = "0.6.1"

@ -14,19 +14,19 @@ name = "hx-loader"
path = "src/main.rs"
[dependencies]
anyhow = "1"
serde = { version = "1.0", features = ["derive"] }
toml = "0.5"
etcetera = "0.4"
tree-sitter = "0.20"
once_cell = "1.17"
log = "0.4"
anyhow = "1.0.68"
serde = { version = "1.0.152", features = ["derive"] }
toml = "0.5.10"
etcetera = "0.4.0"
tree-sitter = "0.20.9"
once_cell = "1.17.0"
log = "0.4.17"
# TODO: these two should be on !wasm32 only
# cloning/compiling tree-sitter grammars
cc = { version = "1" }
threadpool = { version = "1.0" }
cc = "1.0.78"
threadpool = "1.8.1"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
libloading = "0.7"
libloading = "0.7.4"

@ -15,14 +15,14 @@ homepage = "https://helix-editor.com"
helix-core = { version = "0.6", path = "../helix-core" }
helix-loader = { version = "0.6", path = "../helix-loader" }
anyhow = "1.0"
futures-executor = "0.3"
futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
log = "0.4"
lsp-types = { version = "0.93", features = ["proposed"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
tokio = { version = "1.24", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
anyhow = "1.0.68"
futures-executor = "0.3.25"
futures-util = { version = "0.3.25", features = ["std", "async-await"], default-features = false }
log = "0.4.17"
lsp-types = { version = "0.93.2", features = ["proposed"] }
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.91"
thiserror = "1.0.38"
tokio = { version = "1.24.1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
tokio-stream = "0.1.11"
which = "4.2"
which = "4.3.0"

@ -39,6 +39,8 @@ pub enum Error {
Timeout,
#[error("server closed the stream")]
StreamClosed,
#[error("LPS not defined")]
LspNotDefined,
#[error("Unhandled")]
Unhandled,
#[error(transparent)]

@ -34,49 +34,49 @@ helix-dap = { version = "0.6", path = "../helix-dap" }
helix-vcs = { version = "0.6", path = "../helix-vcs" }
helix-loader = { version = "0.6", path = "../helix-loader" }
anyhow = "1"
once_cell = "1.17"
anyhow = "1.0.68"
once_cell = "1.17.0"
which = "4.2"
which = "4.3.0"
tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] }
tokio = { version = "1.24.1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] }
tui = { path = "../helix-tui", package = "helix-tui", default-features = false, features = ["crossterm"] }
crossterm = { version = "0.25", features = ["event-stream"] }
signal-hook = "0.3"
tokio-stream = "0.1"
futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
arc-swap = { version = "1.6.0" }
crossterm = { version = "0.25.0", features = ["event-stream"] }
signal-hook = "0.3.14"
tokio-stream = "0.1.11"
futures-util = { version = "0.3.25", features = ["std", "async-await"], default-features = false }
arc-swap = "1.6.0"
# Logging
fern = "0.6"
chrono = { version = "0.4", default-features = false, features = ["clock"] }
log = "0.4"
fern = "0.6.1"
chrono = { version = "0.4.23", default-features = false, features = ["clock"] }
log = "0.4.17"
# File picker
fuzzy-matcher = "0.3"
ignore = "0.4"
fuzzy-matcher = "0.3.7"
ignore = "0.4.19"
# markdown doc rendering
pulldown-cmark = { version = "0.9", default-features = false }
pulldown-cmark = { version = "0.9.2", default-features = false }
# file type detection
content_inspector = "0.2.4"
# config
toml = "0.5"
toml = "0.5.10"
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.91"
serde = { version = "1.0.152", features = ["derive"] }
# ripgrep for global search
grep-regex = "0.1.10"
grep-searcher = "0.1.10"
grep-regex = "0.1.11"
grep-searcher = "0.1.11"
[target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
signal-hook-tokio = { version = "0.3.1", features = ["futures-v0_3"] }
[build-dependencies]
helix-loader = { version = "0.6", path = "../helix-loader" }
[dev-dependencies]
smallvec = "1.10"
smallvec = "1.10.0"
indoc = "1.0.8"
tempfile = "3.3.0"

@ -21,11 +21,11 @@ use tui::backend::Backend;
use crate::{
args::Args,
commands::apply_workspace_edit,
compositor::{Compositor, Event},
compositor::{self, Compositor, Event},
config::Config,
job::Jobs,
keymap::Keymaps,
ui::{self, overlay::overlayed},
ui::{self, overlay::overlayed, Explorer},
};
use log::{debug, error, warn};
@ -180,7 +180,19 @@ impl Application {
let keys = Box::new(Map::new(Arc::clone(&config), |config: &Config| {
&config.keys
}));
let editor_view = Box::new(ui::EditorView::new(Keymaps::new(keys)));
let mut editor_view = Box::new(ui::EditorView::new(Keymaps::new(keys)));
if args.show_explorer {
let mut jobs = Jobs::new();
let mut context = compositor::Context {
editor: &mut editor,
scroll: None,
jobs: &mut jobs,
};
let mut explorer = Explorer::new(&mut context)?;
explorer.unfocus();
editor_view.explorer = Some(overlayed(explorer));
}
compositor.push(editor_view);
if args.load_tutor {

@ -17,6 +17,7 @@ pub struct Args {
pub log_file: Option<PathBuf>,
pub config_file: Option<PathBuf>,
pub files: Vec<(PathBuf, Position)>,
pub show_explorer: bool,
}
impl Args {
@ -32,6 +33,7 @@ impl Args {
"--version" => args.display_version = true,
"--help" => args.display_help = true,
"--tutor" => args.load_tutor = true,
"--show-explorer" => args.show_explorer = true,
"--vsplit" => match args.split {
Some(_) => anyhow::bail!("can only set a split once of a specific type"),
None => args.split = Some(Layout::Vertical),

@ -272,6 +272,7 @@ impl MappableCommand {
file_picker, "Open file picker",
file_picker_in_current_directory, "Open file picker at current working directory",
code_action, "Perform code action",
workspace_command_picker, "Open workspace command picker",
buffer_picker, "Open buffer picker",
jumplist_picker, "Open jumplist picker",
symbol_picker, "Open symbol picker",
@ -444,7 +445,10 @@ impl MappableCommand {
decrement, "Decrement item under cursor",
record_macro, "Record macro",
replay_macro, "Replay macro",
command_palette, "Open command palette",
command_palette, "Open command pallete",
toggle_or_focus_explorer, "toggle or focus explorer",
open_explorer_recursion, "open explorer recursion",
close_explorer, "close explorer",
);
}
@ -2300,6 +2304,43 @@ fn file_picker_in_current_directory(cx: &mut Context) {
cx.push_layer(Box::new(overlayed(picker)));
}
fn toggle_or_focus_explorer(cx: &mut Context) {
cx.callback = Some(Box::new(
|compositor: &mut Compositor, cx: &mut compositor::Context| {
if let Some(editor) = compositor.find::<ui::EditorView>() {
match editor.explorer.as_mut() {
Some(explore) => explore.content.focus(),
None => match ui::Explorer::new(cx) {
Ok(explore) => editor.explorer = Some(overlayed(explore)),
Err(err) => cx.editor.set_error(format!("{}", err)),
},
}
}
},
));
}
fn open_explorer_recursion(cx: &mut Context) {
cx.callback = Some(Box::new(
|compositor: &mut Compositor, cx: &mut compositor::Context| {
if let Some(editor) = compositor.find::<ui::EditorView>() {
match ui::Explorer::new_explorer_recursion() {
Ok(explore) => editor.explorer = Some(overlayed(explore)),
Err(err) => cx.editor.set_error(format!("{}", err)),
}
}
},
));
}
fn close_explorer(cx: &mut Context) {
cx.callback = Some(Box::new(|compositor: &mut Compositor, _| {
if let Some(editor) = compositor.find::<ui::EditorView>() {
editor.explorer.take();
}
}));
}
fn buffer_picker(cx: &mut Context) {
let current = view!(cx.editor).doc;
@ -2999,18 +3040,11 @@ pub mod insert {
super::completion(cx);
}
fn language_server_completion(cx: &mut Context, ch: char) {
let config = cx.editor.config();
if !config.auto_completion {
return;
}
fn is_server_trigger_char(doc: &Document, ch: char) -> bool {
use helix_lsp::lsp;
// if ch matches completion char, trigger completion
let doc = doc_mut!(cx.editor);
let language_server = match doc.language_server() {
Some(language_server) => language_server,
None => return,
let Some(language_server) = doc.language_server() else {
return false;
};
let capabilities = language_server.capabilities();
@ -3020,11 +3054,36 @@ pub mod insert {
..
}) = &capabilities.completion_provider
{
// TODO: what if trigger is multiple chars long
if triggers.iter().any(|trigger| trigger.contains(ch)) {
cx.editor.clear_idle_timer();
super::completion(cx);
triggers.iter().any(|t| t.contains(ch))
} else {
false
}
}
fn language_server_completion(cx: &mut Context, ch: char) {
use helix_core::chars::char_is_word;
let config = cx.editor.config();
if !config.auto_completion {
return;
}
let (view, doc) = current_ref!(cx.editor);
if char_is_word(ch) && doc.savepoint.is_none() {
let text = doc.text().slice(..);
let cursor = doc.selection(view.id).primary().cursor(text);
let mut chars = text.chars_at(cursor);
chars.reverse();
for _ in 0..config.completion_trigger_len {
if chars.next().map_or(true, |c| !char_is_word(c)) {
return;
}
}
cx.editor.reset_idle_timer();
} else if is_server_trigger_char(doc, ch) {
cx.editor.reset_idle_timer();
}
}
@ -4029,9 +4088,15 @@ pub fn completion(cx: &mut Context) {
let pos = pos_to_lsp_pos(doc.text(), cursor, offset_encoding);
let future = match language_server.completion(doc.identifier(), pos, None) {
Some(future) => future,
None => return,
let Some(future) = language_server.completion(doc.identifier(), pos, None) else {
return;
};
let future = async move {
match future.await {
Ok(v) => Ok(v),
Err(helix_lsp::Error::Timeout) => Ok(serde_json::Value::Null),
Err(e) => Err(e),
}
};
let trigger_offset = cursor;
@ -4044,29 +4109,54 @@ pub fn completion(cx: &mut Context) {
iter.reverse();
let offset = iter.take_while(|ch| chars::char_is_word(*ch)).count();
let start_offset = cursor.saturating_sub(offset);
let prefix = text.slice(start_offset..cursor).to_string();
doc.savepoint();
let trigger_version = doc.version();
cx.callback(
future,
move |editor, compositor, response: Option<lsp::CompletionResponse>| {
let doc = doc_mut!(editor);
let Some(savepoint) = doc.savepoint.take() else {
return;
};
if editor.mode != Mode::Insert {
// we're not in insert mode anymore
return;
}
if savepoint.0 != trigger_version {
doc.savepoint = Some(savepoint);
return;
}
let items = match response {
let mut items = match response {
Some(lsp::CompletionResponse::Array(items)) => items,
// TODO: do something with is_incomplete
Some(lsp::CompletionResponse::List(lsp::CompletionList {
is_incomplete: _is_incomplete,
items,
})) => items,
None => Vec::new(),
None => {
editor.set_status(
"The completion response is None. We will ask the server again",
);
editor.reset_idle_timer();
return;
}
};
if prefix.is_empty() {
items.retain(|item| match &item.filter_text {
Some(t) => t.starts_with(&prefix),
None => item.label.starts_with(&prefix),
})
}
if items.is_empty() {
// editor.set_error("No completion available");
return;
}
doc.savepoint = Some(savepoint);
let size = compositor.size();
let ui = compositor.find::<ui::EditorView>().unwrap();
ui.set_completion(

@ -590,7 +590,6 @@ pub fn code_action(cx: &mut Context) {
}
// Sort codeactions into a useful order. This behaviour is only partially described in the LSP spec.
// Many details are modeled after vscode because langauge servers are usually tested against it.
// VScode sorts the codeaction two times:
//
// First the codeactions that fix some diagnostics are moved to the front.
@ -624,7 +623,7 @@ pub fn code_action(cx: &mut Context) {
.reverse()
});
let mut picker = ui::Menu::new(actions, (), move |editor, code_action, event| {
let mut picker = ui::Menu::new(actions, true, (), move |editor, code_action, event| {
if event != PromptEvent::Validate {
return;
}
@ -654,7 +653,7 @@ pub fn code_action(cx: &mut Context) {
});
picker.move_down(); // pre-select the first item
let popup = Popup::new("code-action", picker).with_scrollbar(false);
let popup = Popup::new("code-action", picker);
compositor.replace_or_push("code-action", popup);
},
)
@ -667,6 +666,34 @@ impl ui::menu::Item for lsp::Command {
}
}
pub fn workspace_command_picker(cx: &mut Context) {
let (_, doc) = current!(cx.editor);
let language_server = language_server!(cx.editor, doc);
let execute_command_provider = match &language_server.capabilities().execute_command_provider {
Some(p) => p,
None => return,
};
let commands = execute_command_provider
.commands
.iter()
.map(|command| lsp::Command {
title: command.clone(),
command: command.clone(),
arguments: None,
})
.collect::<Vec<_>>();
cx.callback = Some(Box::new(
move |compositor: &mut Compositor, _cx: &mut compositor::Context| {
let picker = ui::Picker::new(commands, (), move |cx, command, _action| {
execute_lsp_command(cx.editor, command.clone());
});
compositor.push(Box::new(overlayed(picker)))
},
));
}
pub fn execute_lsp_command(editor: &mut Editor, cmd: lsp::Command) {
let doc = doc!(editor);
let language_server = language_server!(editor, doc);

@ -281,6 +281,31 @@ fn buffer_previous(
Ok(())
}
fn delete(
cx: &mut compositor::Context,
_args: &[Cow<str>],
event: PromptEvent,
) -> anyhow::Result<()> {
if event != PromptEvent::Validate {
return Ok(());
}
let doc = doc_mut!(cx.editor);
if doc.path().is_none() {
bail!("cannot delete a buffer with no associated file on the disk");
}
let future = doc.delete();
cx.jobs.add(Job::new(future));
cx.block_try_flush_writes()?;
let doc_id = view!(cx.editor).doc;
cx.editor.close_document(doc_id, true)?;
Ok(())
}
fn write_impl(
cx: &mut compositor::Context,
path: Option<&Cow<str>>,
@ -1924,6 +1949,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
fun: new_file,
completer: Some(completers::filename),
},
TypableCommand {
name: "delete",
aliases: &["remove", "rm", "del"],
doc: "Deletes the file associated with the current buffer",
fun: delete,
completer: None,
},
TypableCommand {
name: "format",
aliases: &["fmt"],
@ -2340,6 +2372,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
fun: run_shell_command,
completer: Some(completers::directory),
},
TypableCommand {
name: "lsp-restart",
aliases: &[],
doc: "Restarts the LSP server of the current buffer",
fun: lsp_restart,
completer: None,
},
];
pub static TYPABLE_COMMAND_MAP: Lazy<HashMap<&'static str, &'static TypableCommand>> =

@ -10,6 +10,8 @@ pub fn default() -> HashMap<Mode, Keymap> {
"j" | "down" => move_line_down,
"k" | "up" => move_line_up,
"l" | "right" => move_char_right,
"C-j" => half_page_down,
"C-k" => half_page_up,
"t" => find_till_char,
"f" => find_next_char,
@ -175,7 +177,7 @@ pub fn default() -> HashMap<Mode, Keymap> {
"C-u" => half_page_up,
"C-d" => half_page_down,
"C-w" => { "Window"
"C-v" => { "View"
"C-w" | "w" => rotate_view,
"C-s" | "s" => hsplit,
"C-v" | "v" => vsplit,
@ -238,7 +240,8 @@ pub fn default() -> HashMap<Mode, Keymap> {
"e" => dap_enable_exceptions,
"E" => dap_disable_exceptions,
},
"w" => { "Window"
"w" => workspace_command_picker,
"v" => { "View"
"C-w" | "w" => rotate_view,
"C-s" | "s" => hsplit,
"C-v" | "v" => vsplit,
@ -270,6 +273,8 @@ pub fn default() -> HashMap<Mode, Keymap> {
"r" => rename_symbol,
"h" => select_references_to_symbol_under_cursor,
"?" => command_palette,
"e" => toggle_or_focus_explorer,
"E" => close_explorer,
},
"z" => { "View"
"z" | "c" => align_view_center,

@ -73,6 +73,7 @@ FLAGS:
-V, --version Prints version information
--vsplit Splits all given files vertically into different windows
--hsplit Splits all given files horizontally into different windows
--show-explorer Opens the explorer on startup
",
env!("CARGO_PKG_NAME"),
VERSION_AND_GIT_HASH,

@ -104,7 +104,7 @@ impl Completion {
items.sort_by_key(|item| !item.preselect.unwrap_or(false));
// Then create the menu
let menu = Menu::new(items, (), move |editor: &mut Editor, item, event| {
let menu = Menu::new(items, true, (), move |editor: &mut Editor, item, event| {
fn item_to_transaction(
doc: &Document,
view_id: ViewId,
@ -462,6 +462,16 @@ impl Component for Completion {
height = rel_height.min(height);
}
Rect::new(x, y, width, height)
} else if popup_x > 30 {
let mut height = area.height.saturating_sub(popup_y);
let mut width = popup_x;
if let Some((rel_width, rel_height)) = markdown_doc.required_size((width, height)) {
width = rel_width.min(width);
height = rel_height.min(height);
}
let x = popup_x - width;
let y = popup_y;
Rect::new(x, y, width, height)
} else {
let half = area.height / 2;
let height = 15.min(half);

@ -4,7 +4,7 @@ use crate::{
job::{self, Callback},
key,
keymap::{KeymapResult, Keymaps},
ui::{Completion, ProgressSpinners},
ui::{overlay::Overlay, Completion, Explorer, ProgressSpinners},
};
use helix_core::{
@ -19,7 +19,7 @@ use helix_core::{
use helix_view::{
apply_transaction,
document::{Mode, SCRATCH_BUFFER_NAME},
editor::{CompleteAction, CursorShapeConfig},
editor::{CompleteAction, CursorShapeConfig, RainbowIndentOptions},
graphics::{Color, CursorKind, Modifier, Rect, Style},
input::{KeyEvent, MouseButton, MouseEvent, MouseEventKind},
keyboard::{KeyCode, KeyModifiers},
@ -39,6 +39,7 @@ pub struct EditorView {
last_insert: (commands::MappableCommand, Vec<InsertEvent>),
pub(crate) completion: Option<Completion>,
spinners: ProgressSpinners,
pub(crate) explorer: Option<Overlay<Explorer>>,
}
#[derive(Debug, Clone)]
@ -63,6 +64,7 @@ impl EditorView {
last_insert: (commands::MappableCommand::normal_mode, Vec::new()),
completion: None,
spinners: ProgressSpinners::default(),
explorer: None,
}
}
@ -462,6 +464,27 @@ impl EditorView {
let starting_indent =
(offset.col / tab_width) + config.indent_guides.skip_levels as usize;
let modifier = if config.indent_guides.rainbow == RainbowIndentOptions::Dim {
Modifier::DIM
} else {
Modifier::empty()
};
for i in starting_indent..(indent_level / tab_width) {
let style = if config.indent_guides.rainbow != RainbowIndentOptions::None {
indent_guide_style
.patch(theme.get_rainbow(i as usize))
.add_modifier(modifier)
} else {
indent_guide_style
};
surface.set_string(
viewport.x + (i as u16 * tab_width as u16) - offset.col as u16,
viewport.y + line,
&indent_guide_char,
style,
);
}
// Don't draw indent guides outside of view
let end_indent = min(
indent_level,
@ -934,7 +957,7 @@ impl EditorView {
}
(Mode::Insert, Mode::Normal) => {
// if exiting insert mode, remove completion
self.completion = None;
self.clear_completion(cxt.editor);
// TODO: Use an on_mode_change hook to remove signature help
cxt.jobs.callback(async {
@ -1072,9 +1095,6 @@ impl EditorView {
return;
}
// Immediately initialize a savepoint
doc_mut!(editor).savepoint();
editor.last_completion = None;
self.last_insert.1.push(InsertEvent::TriggerCompletion);
@ -1105,7 +1125,15 @@ impl EditorView {
return EventResult::Ignored(None);
}
crate::commands::insert::idle_completion(cx);
let mut cx = commands::Context {
register: None,
editor: cx.editor,
jobs: cx.jobs,
count: None,
callback: None,
on_next_key_callback: None,
};
crate::commands::insert::idle_completion(&mut cx);
EventResult::Consumed(None)
}
@ -1299,6 +1327,11 @@ impl Component for EditorView {
event: &Event,
context: &mut crate::compositor::Context,
) -> EventResult {
if let Some(explore) = self.explorer.as_mut() {
if let EventResult::Consumed(callback) = explore.handle_event(event, context) {
return EventResult::Consumed(callback);
}
}
let mut cx = commands::Context {
editor: context.editor,
count: None,
@ -1333,7 +1366,7 @@ impl Component for EditorView {
EventResult::Consumed(None)
}
Event::Key(mut key) => {
cx.editor.reset_idle_timer();
cx.editor.clear_idle_timer();
canonicalize_key(&mut key);
// clear status
@ -1385,7 +1418,8 @@ impl Component for EditorView {
if let Some(completion) = &mut self.completion {
completion.update(&mut cx);
if completion.is_empty() {
self.clear_completion(cx.editor);
self.completion = None;
doc_mut!(cx.editor).savepoint = None;
}
}
}
@ -1462,6 +1496,21 @@ impl Component for EditorView {
}
// if the terminal size suddenly changed, we need to trigger a resize
if self.explorer.is_some() && (config.explorer.is_embed()) {
editor_area = editor_area.clip_left(config.explorer.column_width as u16 + 2);
}
cx.editor.resize(editor_area); // -1 from bottom for commandline
if let Some(explore) = self.explorer.as_mut() {
if !explore.content.is_focus() && config.explorer.is_embed() {
let current_doc = view!(cx.editor).doc;
let current_doc = cx.editor.document(current_doc).unwrap();
if let Some(path) = current_doc.path() {
explore.content.set_selection(&path);
}
explore.content.render(area, surface, cx);
}
}
cx.editor.resize(editor_area);
if use_bufferline {
@ -1542,9 +1591,30 @@ impl Component for EditorView {
if let Some(completion) = self.completion.as_mut() {
completion.render(area, surface, cx);
}
if let Some(explore) = self.explorer.as_mut() {
if explore.content.is_focus() {
if config.explorer.is_embed() {
explore.content.render(area, surface, cx);
} else {
explore.render(area, surface, cx);
}
}
}
}
fn cursor(&self, _area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
if let Some(explore) = &self.explorer {
if explore.content.is_focus() {
if editor.config().explorer.is_overlay() {
return explore.cursor(_area, editor);
}
let cursor = explore.content.cursor(_area, editor);
if cursor.0.is_some() {
return cursor;
}
}
}
match editor.cursor() {
// All block cursors are drawn manually
(pos, CursorKind::Block) => (pos, CursorKind::Hidden),

@ -0,0 +1,914 @@
use super::{Prompt, Tree, TreeItem, TreeOp};
use crate::{
compositor::{Component, Compositor, Context, EventResult},
ctrl, key, shift, ui,
};
use anyhow::{bail, ensure, Result};
use helix_core::Position;
use helix_view::{
editor::Action,
graphics::{CursorKind, Modifier, Rect},
input::{Event, KeyEvent},
Editor,
};
use std::borrow::Cow;
use std::cmp::Ordering;
use std::path::{Path, PathBuf};
use tui::{
buffer::Buffer as Surface,
text::{Span, Spans},
widgets::{Block, Borders, Widget},
};
macro_rules! get_theme {
($theme: expr, $s1: expr, $s2: expr) => {
$theme.try_get($s1).unwrap_or_else(|| $theme.get($s2))
};
}
const ICONS: &'static [&'static str] =
&["", "", "", "", "", "ﰟ", "", "", "", "ﯤ", "", "ﬥ"];
const ICONS_EXT: &'static [&'static str] = &[
".rs", ".md", ".js", ".c", ".png", ".svg", ".css", ".html", ".lua", ".ts", ".py", ".json",
];
const ICONS_COLORS: &'static [helix_view::theme::Color] = &[
helix_view::theme::Color::Rgb(227, 134, 84),
helix_view::theme::Color::LightCyan,
helix_view::theme::Color::Yellow,
helix_view::theme::Color::Blue,
helix_view::theme::Color::Yellow,
helix_view::theme::Color::Yellow,
helix_view::theme::Color::Green,
helix_view::theme::Color::Blue,
helix_view::theme::Color::Red,
helix_view::theme::Color::Blue,
helix_view::theme::Color::Red,
];
#[derive(Debug, Clone, Copy, PartialEq)]
enum FileType {
File,
Dir,
Exe,
Placeholder,
Parent,
Root,
}
#[derive(Debug, Clone)]
struct FileInfo {
file_type: FileType,
expanded: bool,
path: PathBuf,
}
impl FileInfo {
fn new(path: PathBuf, file_type: FileType) -> Self {
Self {
path,
file_type,
expanded: false,
}
}
fn root(path: PathBuf) -> Self {
Self {
file_type: FileType::Root,
path,
expanded: true,
}
}
fn parent(path: &Path) -> Self {
let p = path.parent().unwrap_or_else(|| Path::new(""));
Self {
file_type: FileType::Parent,
path: p.to_path_buf(),
expanded: false,
}
}
fn get_text(&self) -> Cow<'static, str> {
match self.file_type {
FileType::Parent => "..".into(),
FileType::Placeholder => "---".into(),
FileType::Root => {
if let Some(path) = self.path.iter().last() {
format!("- {} -", path.to_string_lossy()).into()
} else {
Cow::from("/")
}
}
FileType::File | FileType::Exe | FileType::Dir => self
.path
.file_name()
.map_or("/".into(), |p| p.to_string_lossy().into_owned().into()),
}
}
}
impl TreeItem for FileInfo {
type Params = State;
fn text(&self, cx: &mut Context, selected: bool, state: &mut State) -> Spans {
let text = self.get_text();
let theme = &cx.editor.theme;
let style = match self.file_type {
FileType::Parent | FileType::Dir | FileType::Root => "ui.explorer.dir",
FileType::File | FileType::Exe | FileType::Placeholder => "ui.explorer.file",
};
let mut style = theme.try_get(style).unwrap_or_else(|| theme.get("ui.text"));
if selected {
let patch = match state.focus {
true => "ui.explorer.focus",
false => "ui.explorer.unfocus",
};
if let Some(patch) = theme.try_get(patch) {
style = style.patch(patch);
} else {
style = style.add_modifier(Modifier::REVERSED);
}
}
Spans::from(Span::styled(text, style))
}
fn is_child(&self, other: &Self) -> bool {
if let FileType::Parent = other.file_type {
return false;
}
if let FileType::Placeholder = self.file_type {
self.path == other.path
} else {
self.path.parent().map_or(false, |p| p == other.path)
}
}
fn cmp(&self, other: &Self) -> Ordering {
use FileType::*;
match (self.file_type, other.file_type) {
(Parent, _) => return Ordering::Less,
(_, Parent) => return Ordering::Greater,
(Root, _) => return Ordering::Less,
(_, Root) => return Ordering::Greater,
_ => {}
};
if self.path == other.path {
match (self.file_type, other.file_type) {
(_, Placeholder) => return Ordering::Less,
(Placeholder, _) => return Ordering::Greater,
_ => {}
};
}
if let (Some(p1), Some(p2)) = (self.path.parent(), other.path.parent()) {
if p1 == p2 {
match (self.file_type, other.file_type) {
(Dir, File | Exe) => return Ordering::Less,
(File | Exe, Dir) => return Ordering::Greater,
_ => {}
};
}
}
self.path.cmp(&other.path)
}
fn get_childs(&self) -> Result<Vec<Self>> {
match self.file_type {
FileType::Root | FileType::Dir => {}
_ => return Ok(vec![]),
};
let mut ret: Vec<_> = std::fs::read_dir(&self.path)?
.filter_map(|entry| entry.ok())
.filter_map(|entry| {
entry.metadata().ok().map(|meta| {
let is_exe = false;
let file_type = match (meta.is_dir(), is_exe) {
(true, _) => FileType::Dir,
(_, false) => FileType::File,
(_, true) => FileType::Exe,
};
Self {
file_type,
path: self.path.join(entry.file_name()),
expanded: false,
}
})
})
.collect();
if ret.is_empty() {
ret.push(Self {
path: self.path.clone(),
file_type: FileType::Placeholder,
expanded: false,
})
}
Ok(ret)
}
fn filter(&self, _cx: &mut Context, s: &str, _params: &mut Self::Params) -> bool {
if s.is_empty() {
false
} else {
self.get_text().contains(s)
}
}
fn icon(&self) -> Option<(&'static str, &'static helix_view::theme::Color)> {
return match self.file_type {
FileType::Dir => {
if self.expanded {
Some(("", &helix_view::theme::Color::Yellow))
} else {
Some(("", &helix_view::theme::Color::Yellow))
}
}
FileType::File => {
for (i, ext) in ICONS_EXT.iter().enumerate() {
if self.get_text().ends_with(ext) {
let color = ICONS_COLORS
.iter()
.nth(i)
.unwrap_or(&helix_view::theme::Color::Blue);
return ICONS.iter().nth(i).map(|c| (*c, color));
}
}
return Some(("", &helix_view::theme::Color::LightBlue));
}
_ => None,
};
}
}
#[derive(Clone, Copy, Debug)]
enum PromptAction {
Search(bool), // search next/search pre
Mkdir,
CreateFile,
RemoveDir,
RemoveFile,
Filter,
}
#[derive(Clone, Debug)]
struct State {
focus: bool,
current_root: PathBuf,
}
impl State {
fn new(focus: bool, current_root: PathBuf) -> Self {
Self {
focus,
current_root,
}
}
}
pub struct Explorer {
tree: Tree<FileInfo>,
state: State,
prompt: Option<(PromptAction, Prompt)>,
#[allow(clippy::type_complexity)]
on_next_key: Option<Box<dyn FnMut(&mut Context, &mut Self, &KeyEvent) -> EventResult>>,
#[allow(clippy::type_complexity)]
repeat_motion: Option<Box<dyn FnMut(&mut Self, PromptAction, &mut Context) + 'static>>,
}
impl Explorer {
pub fn new(cx: &mut Context) -> Result<Self> {
let current_root = std::env::current_dir().unwrap_or_else(|_| "./".into());
let items = Self::get_items(current_root.clone(), cx)?;
Ok(Self {
tree: Tree::build_tree(items)
.with_enter_fn(Self::toggle_current)
.with_folded_fn(Self::fold_current),
state: State::new(true, current_root),
repeat_motion: None,
prompt: None,
on_next_key: None,
})
}
pub fn set_selection(&mut self, path: &Path) {
let info = if path.is_file() {
FileInfo::new(path.into(), FileType::File)
} else {
FileInfo::new(path.into(), FileType::Dir)
};
self.tree.select(&info);
self.tree.save_view();
}
pub fn new_explorer_recursion() -> Result<Self> {
let current_root = std::env::current_dir().unwrap_or_else(|_| "./".into());
let parent = FileInfo::parent(&current_root);
let root = FileInfo::root(current_root.clone());
let mut tree = Tree::build_from_root(root, usize::MAX / 2)?
.with_enter_fn(Self::toggle_current)
.with_folded_fn(Self::fold_current);
tree.insert_current_level(parent);
Ok(Self {
tree,
state: State::new(true, current_root),
repeat_motion: None,
prompt: None,
on_next_key: None,
})
}
pub fn focus(&mut self) {
self.state.focus = true
}
pub fn unfocus(&mut self) {
self.state.focus = false;
}
pub fn is_focus(&self) -> bool {
self.state.focus
}
fn get_items(p: PathBuf, cx: &mut Context) -> Result<Vec<FileInfo>> {
let mut items = Vec::new();
let root = FileInfo::root(p);
let childs = root.get_childs()?;
if cx.editor.config().explorer.is_tree() {
items.push(root)
}
items.extend(childs);
Ok(items)
}
fn render_preview(&mut self, area: Rect, surface: &mut Surface, editor: &Editor) {
if area.height <= 2 || area.width < 60 {
return;
}
let item = self.tree.current().item();
if item.file_type == FileType::Placeholder {
return;
}
let head_area = render_block(
area.clip_bottom(area.height - 2),
surface,
Borders::BOTTOM,
None,
);
let path_str = format!("{}", item.path.display());
surface.set_stringn(
head_area.x,
head_area.y,
path_str,
head_area.width as usize,
get_theme!(editor.theme, "ui.explorer.dir", "ui.text"),
);
let body_area = area.clip_top(2);
let style = editor.theme.get("ui.text");
if let Ok(preview_content) = get_preview(&item.path, body_area.height as usize) {
preview_content
.into_iter()
.enumerate()
.for_each(|(row, line)| {
surface.set_stringn(
body_area.x,
body_area.y + row as u16,
line,
body_area.width as usize,
style,
);
})
}
}
fn new_search_prompt(&mut self, search_next: bool) {
self.tree.save_view();
self.prompt = Some((
PromptAction::Search(search_next),
Prompt::new("search: ".into(), None, ui::completers::none, |_, _, _| {}),
))
}
fn new_filter_prompt(&mut self) {
self.tree.save_view();
self.prompt = Some((
PromptAction::Filter,
Prompt::new("filter: ".into(), None, ui::completers::none, |_, _, _| {}),
))
}
fn new_mkdir_prompt(&mut self) {
self.prompt = Some((
PromptAction::Mkdir,
Prompt::new("mkdir: ".into(), None, ui::completers::none, |_, _, _| {}),
));
}
fn new_create_file_prompt(&mut self) {
self.prompt = Some((
PromptAction::CreateFile,
Prompt::new(
"create file: ".into(),
None,
ui::completers::none,
|_, _, _| {},
),
));
}
fn new_remove_file_prompt(&mut self, cx: &mut Context) {
let item = self.tree.current_item();
let check = || {
ensure!(item.file_type != FileType::Placeholder, "The path is empty");
ensure!(
item.file_type != FileType::Parent,
"can not remove parent dir"
);
ensure!(item.path.is_file(), "The path is not a file");
let doc = cx.editor.document_by_path(&item.path);
ensure!(doc.is_none(), "The file is opened");
Ok(())
};
if let Err(e) = check() {
cx.editor.set_error(format!("{e}"));
return;
}
let p = format!("remove file: {}, YES? ", item.path.display());
self.prompt = Some((
PromptAction::RemoveFile,
Prompt::new(p.into(), None, ui::completers::none, |_, _, _| {}),
));
}
fn new_remove_dir_prompt(&mut self, cx: &mut Context) {
let item = self.tree.current_item();
let check = || {
ensure!(item.file_type != FileType::Placeholder, "The path is empty");
ensure!(
item.file_type != FileType::Parent,
"can not remove parent dir"
);
ensure!(item.path.is_dir(), "The path is not a dir");
let doc = cx.editor.documents().find(|doc| {
doc.path()
.map(|p| p.starts_with(&item.path))
.unwrap_or(false)
});
ensure!(doc.is_none(), "There are files opened under the dir");
Ok(())
};
if let Err(e) = check() {
cx.editor.set_error(format!("{e}"));
return;
}
let p = format!("remove dir: {}, YES? ", item.path.display());
self.prompt = Some((
PromptAction::RemoveDir,
Prompt::new(p.into(), None, ui::completers::none, |_, _, _| {}),
));
}
fn fold_current(item: &mut FileInfo, _cx: &mut Context, _state: &mut State) {
if item.path.is_dir() && item.file_type != FileType::Root {
item.expanded = false;
}
}
fn toggle_current(
item: &mut FileInfo,
cx: &mut Context,
state: &mut State,
) -> TreeOp<FileInfo> {
if item.file_type == FileType::Placeholder {
return TreeOp::Noop;
}
if item.path == Path::new("") {
return TreeOp::Noop;
}
let meta = match std::fs::metadata(&item.path) {
Ok(meta) => meta,
Err(e) => {
cx.editor.set_error(format!("{e}"));
return TreeOp::Noop;
}
};
if meta.is_file() {
if let Err(e) = cx.editor.open(&item.path.clone(), Action::Replace) {
cx.editor.set_error(format!("{e}"));
}
state.focus = false;
return TreeOp::Noop;
}
if item.path.is_dir() {
item.expanded = true;
if cx.editor.config().explorer.is_list() || item.file_type == FileType::Parent {
match Self::get_items(item.path.clone(), cx) {
Ok(items) => {
state.current_root = item.path.clone();
return TreeOp::ReplaceTree(items);
}
Err(e) => cx.editor.set_error(format!("{e}")),
}
} else {
return TreeOp::GetChildsAndInsert;
}
}
cx.editor.set_error("unkonw file type");
TreeOp::Noop
}
fn render_float(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
let background = cx.editor.theme.get("ui.background");
let column_width = cx.editor.config().explorer.column_width as u16;
surface.clear_with(area, background);
let area = render_block(area, surface, Borders::ALL, None);
let mut preview_area = area.clip_left(column_width + 1);
if let Some((_, prompt)) = self.prompt.as_mut() {
let area = preview_area.clip_bottom(2);
let promp_area = render_block(
preview_area.clip_top(area.height),
surface,
Borders::TOP,
None,
);
prompt.render(promp_area, surface, cx);
preview_area = area;
}
self.render_preview(preview_area, surface, cx.editor);
let list_area = render_block(
area.clip_right(preview_area.width),
surface,
Borders::RIGHT,
None,
);
self.tree.render(list_area, surface, cx, &mut self.state);
}
fn render_embed(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
let config = &cx.editor.config().explorer;
let side_area = area
.with_width(area.width.min(config.column_width as u16 + 2))
.clip_bottom(1);
let background = cx.editor.theme.get("ui.statusline");
surface.clear_with(side_area, background);
let preview_area = area.clip_left(side_area.width).clip_bottom(2);
let prompt_area = area.clip_top(side_area.height);
let border_style = cx.editor.theme.get("ui.explorer.border");
let list_area = render_block(
side_area.clip_left(1),
surface,
Borders::RIGHT,
Some(border_style),
)
.clip_bottom(1);
self.tree.render(list_area, surface, cx, &mut self.state);
{
let statusline = if self.is_focus() {
cx.editor.theme.get("ui.statusline")
} else {
cx.editor.theme.get("ui.statusline.inactive")
};
let area = side_area.clip_top(list_area.height).clip_right(1);
surface.clear_with(area, statusline);
}
if self.is_focus() {
if preview_area.width < 30 || preview_area.height < 3 {
return;
}
let width = preview_area.width.min(90);
let mut y = self.tree.row().saturating_sub(1) as u16;
let height = (preview_area.height).min(25);
if (height + y) > preview_area.height {
y = preview_area.height - height;
}
let area = Rect::new(preview_area.x, y, width, height);
surface.clear_with(area, background);
let area = render_block(area, surface, Borders::all(), None);
self.render_preview(area, surface, cx.editor);
}
if let Some((_, prompt)) = self.prompt.as_mut() {
prompt.render_prompt(prompt_area, surface, cx)
}
}
fn handle_filter_event(&mut self, event: &KeyEvent, cx: &mut Context) -> EventResult {
let (action, mut prompt) = self.prompt.take().unwrap();
match event {
key!(Tab) | key!(Down) | ctrl!('j') => {
self.tree.clean_recycle();
return self
.tree
.handle_event(Event::Key(event.clone()), cx, &mut self.state);
}
key!(Enter) => {
self.tree.clean_recycle();
return self
.tree
.handle_event(Event::Key(event.clone()), cx, &mut self.state);
}
key!(Esc) | ctrl!('c') => self.tree.restore_recycle(),
_ => {
if let EventResult::Consumed(_) = prompt.handle_event(&Event::Key(*event), cx) {
self.tree.filter(prompt.line(), cx, &mut self.state);
}
self.prompt = Some((action, prompt));
}
};
EventResult::Consumed(None)
}
fn handle_search_event(&mut self, event: &KeyEvent, cx: &mut Context) -> EventResult {
let (action, mut prompt) = self.prompt.take().unwrap();
let search_next = match action {
PromptAction::Search(search_next) => search_next,
_ => return EventResult::Ignored(None),
};
match event {
key!(Tab) | key!(Down) | ctrl!('j') => {
return self
.tree
.handle_event(Event::Key(event.clone()), cx, &mut self.state)
}
key!(Enter) => {
let search_str = prompt.line().clone();
if !search_str.is_empty() {
self.repeat_motion = Some(Box::new(move |explorer, action, cx| {
if let PromptAction::Search(is_next) = action {
explorer.tree.save_view();
if is_next == search_next {
explorer
.tree
.search_next(cx, &search_str, &mut explorer.state);
} else {
explorer
.tree
.search_pre(cx, &search_str, &mut explorer.state);
}
}
}))
} else {
self.repeat_motion = None;
}
return self
.tree
.handle_event(Event::Key(event.clone()), cx, &mut self.state);
}
key!(Esc) | ctrl!('c') => self.tree.restore_view(),
_ => {
if let EventResult::Consumed(_) = prompt.handle_event(&Event::Key(*event), cx) {
if search_next {
self.tree.search_next(cx, prompt.line(), &mut self.state);
} else {
self.tree.search_pre(cx, prompt.line(), &mut self.state);
}
}
self.prompt = Some((action, prompt));
}
};
EventResult::Consumed(None)
}
fn handle_prompt_event(&mut self, event: &KeyEvent, cx: &mut Context) -> EventResult {
match &self.prompt {
Some((PromptAction::Search(_), _)) => return self.handle_search_event(event, cx),
Some((PromptAction::Filter, _)) => return self.handle_filter_event(event, cx),
_ => {}
};
let (action, mut prompt) = match self.prompt.take() {
Some((action, p)) => (action, p),
_ => return EventResult::Ignored(None),
};
let line = prompt.line();
match (action, event) {
(PromptAction::Mkdir, key!(Enter)) => {
if let Err(e) = self.new_path(line, true) {
cx.editor.set_error(format!("{e}"))
}
}
(PromptAction::CreateFile, key!(Enter)) => {
if let Err(e) = self.new_path(line, false) {
cx.editor.set_error(format!("{e}"))
}
}
(PromptAction::RemoveDir, key!(Enter)) => {
let item = self.tree.current_item();
if let Err(e) = std::fs::remove_dir_all(&item.path) {
cx.editor.set_error(format!("{e}"));
} else {
self.tree.fold_current_child();
self.tree.remove_current();
}
}
(PromptAction::RemoveFile, key!(Enter)) => {
if line == "YES" {
let item = self.tree.current_item();
if let Err(e) = std::fs::remove_file(&item.path) {
cx.editor.set_error(format!("{e}"));
} else {
self.tree.remove_current();
}
}
}
(_, key!(Esc) | ctrl!('c')) => {}
_ => {
prompt.handle_event(&Event::Key(*event), cx);
self.prompt = Some((action, prompt));
}
}
EventResult::Consumed(None)
}
fn new_path(&mut self, file_name: &str, is_dir: bool) -> Result<()> {
let current = self.tree.current_item();
let current_parent = if current.file_type == FileType::Placeholder {
&current.path
} else {
current
.path
.parent()
.ok_or_else(|| anyhow::anyhow!("can not get parent dir"))?
};
let p = helix_core::path::get_normalized_path(&current_parent.join(file_name));
match p.parent() {
Some(p) if p == current_parent => {}
_ => bail!("The file name is not illegal"),
};
let f = if is_dir {
std::fs::create_dir(&p)?;
FileInfo::new(p, FileType::Dir)
} else {
let mut fd = std::fs::OpenOptions::new();
fd.create_new(true).write(true).open(&p)?;
FileInfo::new(p, FileType::File)
};
if current.file_type == FileType::Placeholder {
self.tree.replace_current(f);
} else {
self.tree.insert_current_level(f);
}
Ok(())
}
}
impl Component for Explorer {
/// Process input events, return true if handled.
fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
let key_event = match event {
Event::Key(event) => *event,
Event::Resize(..) => return EventResult::Consumed(None),
_ => return EventResult::Ignored(None),
};
if !self.is_focus() {
return EventResult::Ignored(None);
}
if let Some(mut on_next_key) = self.on_next_key.take() {
return on_next_key(cx, self, &key_event);
}
if let EventResult::Consumed(c) = self.handle_prompt_event(&key_event, cx) {
return EventResult::Consumed(c);
}
let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _| {
if let Some(editor) = compositor.find::<ui::EditorView>() {
editor.explorer = None;
}
})));
match key_event {
key!(Esc) => self.unfocus(),
ctrl!('c') => return close_fn,
key!('n') => {
if let Some(mut repeat_motion) = self.repeat_motion.take() {
repeat_motion(self, PromptAction::Search(true), cx);
self.repeat_motion = Some(repeat_motion);
}
}
shift!('N') => {
if let Some(mut repeat_motion) = self.repeat_motion.take() {
repeat_motion(self, PromptAction::Search(false), cx);
self.repeat_motion = Some(repeat_motion);
}
}
key!('f') => self.new_filter_prompt(),
key!('/') => self.new_search_prompt(true),
key!('?') => self.new_search_prompt(false),
key!('m') => {
self.on_next_key = Some(Box::new(|_, explorer, event| {
match event {
key!('d') => explorer.new_mkdir_prompt(),
key!('f') => explorer.new_create_file_prompt(),
_ => return EventResult::Ignored(None),
};
EventResult::Consumed(None)
}));
}
key!('r') => {
self.on_next_key = Some(Box::new(|cx, explorer, event| {
match event {
key!('d') => explorer.new_remove_dir_prompt(cx),
key!('f') => explorer.new_remove_file_prompt(cx),
_ => return EventResult::Ignored(None),
};
EventResult::Consumed(None)
}));
}
_ => {
self.tree
.handle_event(Event::Key(key_event.clone()), cx, &mut self.state);
}
}
EventResult::Consumed(None)
}
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
if area.width < 10 || area.height < 5 {
cx.editor.set_error("explorer render area is too small");
return;
}
let config = &cx.editor.config().explorer;
if config.is_embed() {
self.render_embed(area, surface, cx);
} else {
self.render_float(area, surface, cx);
}
}
fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
let prompt = match self.prompt.as_ref() {
Some((_, prompt)) => prompt,
None => return (None, CursorKind::Hidden),
};
let config = &editor.config().explorer;
let (x, y) = if config.is_overlay() {
let colw = config.column_width as u16;
if area.width > colw {
(area.x + colw + 2, area.y + area.height - 2)
} else {
return (None, CursorKind::Hidden);
}
} else {
(area.x, area.y + area.height - 1)
};
prompt.cursor(Rect::new(x, y, area.width, 1), editor)
}
}
fn get_preview(p: impl AsRef<Path>, max_line: usize) -> Result<Vec<String>> {
let p = p.as_ref();
if p.is_dir() {
return Ok(p
.read_dir()?
.filter_map(|entry| entry.ok())
.take(max_line)
.map(|entry| {
if entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false) {
format!("{}/", entry.file_name().to_string_lossy())
} else {
format!("{}", entry.file_name().to_string_lossy())
}
})
.collect());
}
ensure!(p.is_file(), "path: {} is not file or dir", p.display());
use std::fs::OpenOptions;
use std::io::BufRead;
let mut fd = OpenOptions::new();
fd.read(true);
let fd = fd.open(p)?;
Ok(std::io::BufReader::new(fd)
.lines()
.take(max_line)
.filter_map(|line| line.ok())
.map(|line| line.replace('\t', " "))
.collect())
}
fn render_block(
area: Rect,
surface: &mut Surface,
borders: Borders,
border_style: Option<helix_view::theme::Style>,
) -> Rect {
let mut block = Block::default().borders(borders);
if let Some(style) = border_style {
block = block.border_style(style);
}
let inner = block.inner(area);
block.render(area, surface);
inner
}

@ -74,11 +74,12 @@ impl<T: Item> Menu<T> {
// rendering)
pub fn new(
options: Vec<T>,
sort: bool,
editor_data: <T as Item>::Data,
callback_fn: impl Fn(&mut Editor, Option<&T>, MenuEvent) + 'static,
) -> Self {
let matches = (0..options.len()).map(|i| (i, 0)).collect();
Self {
let mut menu = Self {
options,
editor_data,
matcher: Box::new(Matcher::default()),
@ -90,7 +91,16 @@ impl<T: Item> Menu<T> {
size: (0, 0),
viewport: (0, 0),
recalculate: true,
};
if sort {
// TODO: scoring on empty input should just use a fastpath
menu.score("");
} else {
menu.matches = (0..menu.options.len()).map(|i| (i, 0)).collect();
}
menu
}
pub fn score(&mut self, pattern: &str) {

@ -1,5 +1,6 @@
mod completion;
pub(crate) mod editor;
mod explore;
mod fuzzy_match;
mod info;
pub mod lsp;
@ -12,11 +13,13 @@ mod prompt;
mod spinner;
mod statusline;
mod text;
mod tree;
use crate::compositor::{Component, Compositor};
use crate::job::{self, Callback};
pub use completion::Completion;
pub use editor::EditorView;
pub use explore::Explorer;
pub use markdown::Markdown;
pub use menu::Menu;
pub use picker::{DynamicPicker, FileLocation, FilePicker, Picker};
@ -24,6 +27,7 @@ pub use popup::Popup;
pub use prompt::{Prompt, PromptEvent};
pub use spinner::{ProgressSpinners, Spinner};
pub use text::Text;
pub use tree::{Tree, TreeItem, TreeOp};
use helix_core::regex::Regex;
use helix_core::regex::RegexBuilder;

@ -0,0 +1,707 @@
use std::cmp::Ordering;
use std::iter::Peekable;
use anyhow::Result;
use crate::{
compositor::{Context, EventResult},
ctrl, key, shift,
};
use helix_core::unicode::width::UnicodeWidthStr;
use helix_view::{
graphics::Rect,
input::{Event, KeyEvent},
};
use tui::{buffer::Buffer as Surface, text::Spans};
pub trait TreeItem: Sized {
type Params;
fn text(&self, cx: &mut Context, selected: bool, params: &mut Self::Params) -> Spans;
fn is_child(&self, other: &Self) -> bool;
fn cmp(&self, other: &Self) -> Ordering;
fn icon(&self) -> Option<(&'static str, &'static helix_view::theme::Color)>;
fn filter(&self, cx: &mut Context, s: &str, params: &mut Self::Params) -> bool {
self.text(cx, false, params)
.0
.into_iter()
.map(|s| s.content)
.collect::<Vec<_>>()
.concat()
.contains(s)
}
fn get_childs(&self) -> Result<Vec<Self>> {
Ok(vec![])
}
}
fn tree_item_cmp<T: TreeItem>(item1: &T, item2: &T) -> Ordering {
if item1.is_child(item2) {
return Ordering::Greater;
}
if item2.is_child(item1) {
return Ordering::Less;
}
T::cmp(item1, item2)
}
fn vec_to_tree<T: TreeItem>(mut items: Vec<T>, level: usize) -> Vec<Elem<T>> {
fn get_childs<T, Iter>(iter: &mut Peekable<Iter>, elem: &mut Elem<T>)
where
T: TreeItem,
Iter: Iterator<Item = T>,
{
let level = elem.level + 1;
loop {
if !iter.peek().map_or(false, |next| next.is_child(&elem.item)) {
break;
}
let mut child = Elem::new(iter.next().unwrap(), level);
if iter.peek().map_or(false, |nc| nc.is_child(&child.item)) {
get_childs(iter, &mut child);
}
elem.folded.push(child);
}
}
items.sort_by(tree_item_cmp);
let mut elems = Vec::with_capacity(items.len());
let mut iter = items.into_iter().peekable();
while let Some(item) = iter.next() {
let mut elem = Elem::new(item, level);
if iter.peek().map_or(false, |next| next.is_child(&elem.item)) {
get_childs(&mut iter, &mut elem);
}
expand_elems(&mut elems, elem);
}
elems
}
// return total elems's count contain self
fn get_elems_recursion<T: TreeItem>(t: &mut Elem<T>, depth: usize) -> Result<usize> {
let mut childs = t.item.get_childs()?;
childs.sort_by(tree_item_cmp);
let mut elems = Vec::with_capacity(childs.len());
let level = t.level + 1;
let mut total = 1;
for child in childs {
let mut elem = Elem::new(child, level);
let count = if depth > 0 {
get_elems_recursion(&mut elem, depth - 1)?
} else {
1
};
elems.push(elem);
total += count;
}
t.folded = elems;
Ok(total)
}
fn expand_elems<T: TreeItem>(dist: &mut Vec<Elem<T>>, mut t: Elem<T>) {
let childs = std::mem::take(&mut t.folded);
dist.push(t);
for child in childs {
expand_elems(dist, child)
}
}
pub enum TreeOp<T> {
Noop,
Restore,
InsertChild(Vec<T>),
GetChildsAndInsert,
ReplaceTree(Vec<T>),
}
pub struct Elem<T> {
item: T,
level: usize,
folded: Vec<Self>,
}
impl<T: Clone> Clone for Elem<T> {
fn clone(&self) -> Self {
Self {
item: self.item.clone(),
level: self.level,
folded: self.folded.clone(),
}
}
}
impl<T> Elem<T> {
pub fn new(item: T, level: usize) -> Self {
Self {
item,
level,
folded: vec![],
}
}
pub fn item(&self) -> &T {
&self.item
}
}
pub struct Tree<T: TreeItem> {
items: Vec<Elem<T>>,
recycle: Option<(String, Vec<Elem<T>>)>,
selected: usize,
save_view: (usize, usize), // (selected, row)
row: usize,
col: usize,
max_len: usize,
count: usize,
tree_symbol_style: String,
#[allow(clippy::type_complexity)]
pre_render: Option<Box<dyn Fn(&mut Self, Rect) + 'static>>,
#[allow(clippy::type_complexity)]
on_opened_fn:
Option<Box<dyn FnMut(&mut T, &mut Context, &mut T::Params) -> TreeOp<T> + 'static>>,
#[allow(clippy::type_complexity)]
on_folded_fn: Option<Box<dyn FnMut(&mut T, &mut Context, &mut T::Params) + 'static>>,
#[allow(clippy::type_complexity)]
on_next_key: Option<Box<dyn FnMut(&mut Context, &mut Self, KeyEvent)>>,
}
impl<T: TreeItem> Tree<T> {
pub fn new(items: Vec<Elem<T>>) -> Self {
Self {
items,
recycle: None,
selected: 0,
save_view: (0, 0),
row: 0,
col: 0,
max_len: 0,
count: 0,
tree_symbol_style: "ui.explorer.guide".into(),
pre_render: None,
on_opened_fn: None,
on_folded_fn: None,
on_next_key: None,
}
}
pub fn replace_with_new_items(&mut self, items: Vec<T>) {
let old = std::mem::replace(self, Self::new(vec_to_tree(items, 0)));
self.on_opened_fn = old.on_opened_fn;
self.on_folded_fn = old.on_folded_fn;
self.tree_symbol_style = old.tree_symbol_style;
}
pub fn build_tree(items: Vec<T>) -> Self {
Self::new(vec_to_tree(items, 0))
}
pub fn build_from_root(t: T, depth: usize) -> Result<Self> {
let mut elem = Elem::new(t, 0);
let count = get_elems_recursion(&mut elem, depth)?;
let mut elems = Vec::with_capacity(count);
expand_elems(&mut elems, elem);
Ok(Self::new(elems))
}
pub fn with_enter_fn<F>(mut self, f: F) -> Self
where
F: FnMut(&mut T, &mut Context, &mut T::Params) -> TreeOp<T> + 'static,
{
self.on_opened_fn = Some(Box::new(f));
self
}
pub fn with_folded_fn<F>(mut self, f: F) -> Self
where
F: FnMut(&mut T, &mut Context, &mut T::Params) + 'static,
{
self.on_folded_fn = Some(Box::new(f));
self
}
pub fn tree_symbol_style(mut self, style: String) -> Self {
self.tree_symbol_style = style;
self
}
fn next_item(&self) -> Option<&Elem<T>> {
self.items.get(self.selected + 1)
}
fn next_not_descendant_pos(&self, index: usize) -> usize {
let item = &self.items[index];
self.find(index + 1, false, |n| n.level <= item.level)
.unwrap_or(self.items.len())
}
fn find_parent(&self, index: usize) -> Option<usize> {
let item = &self.items[index];
self.find(index, true, |p| p.level < item.level)
}
// rev start: start - 1
fn find<F>(&self, start: usize, rev: bool, f: F) -> Option<usize>
where
F: FnMut(&Elem<T>) -> bool,
{
let iter = self.items.iter();
if rev {
iter.take(start).rposition(f)
} else {
iter.skip(start).position(f).map(|p| p + start)
}
}
}
impl<T: TreeItem> Tree<T> {
pub fn on_enter(&mut self, cx: &mut Context, params: &mut T::Params) {
if self.items.is_empty() {
return;
}
if let Some(next_level) = self.next_item().map(|elem| elem.level) {
let current = &mut self.items[self.selected];
let current_level = current.level;
if next_level > current_level {
if let Some(mut on_folded_fn) = self.on_folded_fn.take() {
on_folded_fn(&mut current.item, cx, params);
self.on_folded_fn = Some(on_folded_fn);
}
self.fold_current_child();
return;
}
}
if let Some(mut on_open_fn) = self.on_opened_fn.take() {
let mut f = || {
let current = &mut self.items[self.selected];
let items = match on_open_fn(&mut current.item, cx, params) {
TreeOp::Restore => {
let inserts = std::mem::take(&mut current.folded);
let _: Vec<_> = self
.items
.splice(self.selected + 1..self.selected + 1, inserts)
.collect();
return;
}
TreeOp::InsertChild(items) => items,
TreeOp::GetChildsAndInsert => match current.item.get_childs() {
Ok(items) => items,
Err(e) => return cx.editor.set_error(format!("{e}")),
},
TreeOp::ReplaceTree(items) => return self.replace_with_new_items(items),
TreeOp::Noop => return,
};
current.folded = vec![];
let inserts = vec_to_tree(items, current.level + 1);
let _: Vec<_> = self
.items
.splice(self.selected + 1..self.selected + 1, inserts)
.collect();
};
f();
self.on_opened_fn = Some(on_open_fn)
} else {
let current = &mut self.items[self.selected];
let inserts = std::mem::take(&mut current.folded);
let _: Vec<_> = self
.items
.splice(self.selected + 1..self.selected + 1, inserts)
.collect();
}
}
pub fn fold_current_level(&mut self) {
let start = match self.find_parent(self.selected) {
Some(start) => start,
None => return,
};
self.selected = start;
self.fold_current_child();
}
pub fn fold_current_child(&mut self) {
if self.selected + 1 >= self.items.len() {
return;
}
let pos = self.next_not_descendant_pos(self.selected);
if self.selected < pos {
self.items[self.selected].folded = self.items.drain(self.selected + 1..pos).collect();
}
}
pub fn search_next(&mut self, cx: &mut Context, s: &str, params: &mut T::Params) {
let skip = self.save_view.0 + 1;
self.selected = self
.find(skip, false, |e| e.item.filter(cx, s, params))
.unwrap_or(self.save_view.0);
self.row = (self.save_view.1 + self.selected).saturating_sub(self.save_view.0);
}
pub fn search_pre(&mut self, cx: &mut Context, s: &str, params: &mut T::Params) {
let take = self.save_view.0;
self.selected = self
.find(take, true, |e| e.item.filter(cx, s, params))
.unwrap_or(self.save_view.0);
self.row = (self.save_view.1 + self.selected).saturating_sub(self.save_view.0);
}
pub fn move_down(&mut self, rows: usize) {
let len = self.items.len();
if len > 0 {
self.selected = std::cmp::min(self.selected + rows, len.saturating_sub(1));
self.row = std::cmp::min(self.selected, self.row + rows);
}
}
pub fn move_up(&mut self, rows: usize) {
let len = self.items.len();
if len > 0 {
self.selected = self.selected.saturating_sub(rows);
self.row = std::cmp::min(self.selected, self.row.saturating_sub(rows));
}
}
pub fn move_left(&mut self, cols: usize) {
self.col = self.col.saturating_sub(cols);
}
pub fn move_right(&mut self, cols: usize) {
self.pre_render = Some(Box::new(move |tree: &mut Self, area: Rect| {
let max_scroll = tree.max_len.saturating_sub(area.width as usize);
tree.col = max_scroll.min(tree.col + cols);
}));
}
pub fn move_down_half_page(&mut self) {
self.pre_render = Some(Box::new(|tree: &mut Self, area: Rect| {
tree.move_down((area.height / 2) as usize);
}));
}
pub fn move_up_half_page(&mut self) {
self.pre_render = Some(Box::new(|tree: &mut Self, area: Rect| {
tree.move_up((area.height / 2) as usize);
}));
}
pub fn move_down_page(&mut self) {
self.pre_render = Some(Box::new(|tree: &mut Self, area: Rect| {
tree.move_down((area.height) as usize);
}));
}
pub fn move_up_page(&mut self) {
self.pre_render = Some(Box::new(|tree: &mut Self, area: Rect| {
tree.move_up((area.height) as usize);
}));
}
pub fn save_view(&mut self) {
self.save_view = (self.selected, self.row);
}
pub fn restore_view(&mut self) {
(self.selected, self.row) = self.save_view;
}
pub fn current(&self) -> &Elem<T> {
&self.items[self.selected]
}
pub fn current_item(&self) -> &T {
&self.items[self.selected].item
}
pub fn row(&self) -> usize {
self.row
}
pub fn remove_current(&mut self) -> T {
let elem = self.items.remove(self.selected);
self.selected = self.selected.saturating_sub(1);
elem.item
}
pub fn replace_current(&mut self, item: T) {
self.items[self.selected].item = item;
}
pub fn select(&mut self, select_item: &T) {
let selected = self
.items
.iter()
.enumerate()
.filter(|(_, i)| i.item.cmp(select_item) == Ordering::Equal)
.next();
if let Some((idx, _)) = selected {
self.selected = idx;
self.row = idx;
}
}
pub fn insert_current_level(&mut self, item: T) {
let current = self.current();
let level = current.level;
let pos = match current.item.cmp(&item) {
Ordering::Less => self
.find(self.selected + 1, false, |e| {
e.level < level || (e.level == level && e.item.cmp(&item) != Ordering::Less)
})
.unwrap_or(self.items.len()),
Ordering::Greater => {
match self.find(self.selected, true, |elem| {
elem.level < level
|| (elem.level == level && elem.item.cmp(&item) != Ordering::Greater)
}) {
Some(p) if self.items[p].level == level => self.next_not_descendant_pos(p),
Some(p) => p + 1,
None => 0,
}
}
Ordering::Equal => self.selected + 1,
};
self.items.insert(pos, Elem::new(item, level));
}
}
impl<T: TreeItem> Tree<T> {
pub fn render(
&mut self,
area: Rect,
surface: &mut Surface,
cx: &mut Context,
params: &mut T::Params,
) {
if let Some(pre_render) = self.pre_render.take() {
pre_render(self, area);
}
self.max_len = 0;
self.row = std::cmp::min(self.row, area.height.saturating_sub(1) as usize);
let style = cx.editor.theme.get(&self.tree_symbol_style);
let folder_style = cx.editor.theme.get("special");
let last_item_index = self.items.len().saturating_sub(1);
let skip = self.selected.saturating_sub(self.row);
let iter = self
.items
.iter()
.skip(skip)
.take(area.height as usize)
.enumerate();
for (index, elem) in iter {
let row = index as u16;
let mut area = Rect::new(area.x, area.y + row, area.width, 1);
let indent = if elem.level > 0 {
if index + skip != last_item_index {
format!("{}", "│ ".repeat(elem.level - 1))
} else {
format!("{}", "".repeat(elem.level - 1))
}
} else {
"".to_string()
};
let indent_len = indent.chars().count();
if indent_len > self.col {
let indent: String = indent.chars().skip(self.col).collect();
if !indent.is_empty() {
surface.set_stringn(area.x, area.y, &indent, area.width as usize, style);
area = area.clip_left(indent.width() as u16);
}
};
let mut start_index = self.col.saturating_sub(indent_len);
let mut text = elem.item.text(cx, skip + index == self.selected, params);
self.max_len = self.max_len.max(text.width() + indent.len() - 2);
for span in text.0.iter_mut() {
if area.width == 0 {
return;
}
if start_index == 0 {
let mut icon_offset = 0;
if let Some((icon, color)) = elem.item.icon() {
let style = folder_style.fg(*color);
surface.set_string(area.x, area.y, icon, style);
icon_offset = 2;
}
surface.set_span(area.x + icon_offset, area.y, span, area.width - icon_offset);
area = area.clip_left((span.width() - icon_offset as usize) as u16);
} else {
let span_width = span.width();
if start_index > span_width {
start_index -= span_width;
} else {
let content: String = span
.content
.chars()
.filter(|c| {
if start_index > 0 {
start_index = start_index.saturating_sub(c.to_string().width());
false
} else {
true
}
})
.collect();
let mut cont = String::new();
cont.push_str("");
cont.push_str(&content);
surface.set_string_truncated(
area.x,
area.y,
&cont,
area.width as usize,
|_| span.style,
false,
false,
);
start_index = 0
}
}
}
}
}
pub fn handle_event(
&mut self,
event: Event,
cx: &mut Context,
params: &mut T::Params,
) -> EventResult {
let key_event = match event {
Event::Key(event) => event,
Event::Resize(..) => return EventResult::Consumed(None),
_ => return EventResult::Ignored(None),
};
if let Some(mut on_next_key) = self.on_next_key.take() {
on_next_key(cx, self, key_event);
return EventResult::Consumed(None);
}
let count = std::mem::replace(&mut self.count, 0);
match key_event.into() {
key!(i @ '0'..='9') => self.count = i.to_digit(10).unwrap() as usize + count * 10,
key!('k') | shift!(Tab) | key!(Up) => self.move_up(1.max(count)),
key!('j') | key!(Tab) | key!(Down) => self.move_down(1.max(count)),
key!('z') => self.fold_current_level(),
key!('h') => self.move_left(1.max(count)),
key!('l') => self.move_right(1.max(count)),
shift!('G') => self.move_down(usize::MAX / 2),
key!(Enter) => self.on_enter(cx, params),
key!(' ') => self.on_enter(cx, params),
ctrl!('d') | ctrl!('j') => self.move_down_half_page(),
ctrl!('u') | ctrl!('k') => self.move_up_half_page(),
shift!('D') => self.move_down_page(),
shift!('U') => self.move_up_page(),
key!('g') => {
self.on_next_key = Some(Box::new(|_, tree, event| match event.into() {
key!('g') => tree.move_up(usize::MAX / 2),
key!('e') => tree.move_down(usize::MAX / 2),
_ => {}
}));
}
_ => return EventResult::Ignored(None),
}
EventResult::Consumed(None)
}
}
impl<T: TreeItem + Clone> Tree<T> {
pub fn filter(&mut self, s: &str, cx: &mut Context, params: &mut T::Params) {
fn filter_recursion<T>(
elems: &Vec<Elem<T>>,
mut index: usize,
s: &str,
cx: &mut Context,
params: &mut T::Params,
) -> (Vec<Elem<T>>, usize)
where
T: TreeItem + Clone,
{
let mut retain = vec![];
let elem = &elems[index];
loop {
let child = match elems.get(index + 1) {
Some(child) if child.item.is_child(&elem.item) => child,
_ => break,
};
index += 1;
let next = elems.get(index + 1);
if next.map_or(false, |n| n.item.is_child(&child.item)) {
let (sub_retain, current_index) = filter_recursion(elems, index, s, cx, params);
retain.extend(sub_retain);
index = current_index;
} else if child.item.filter(cx, s, params) {
retain.push(child.clone());
}
}
if !retain.is_empty() || elem.item.filter(cx, s, params) {
retain.insert(0, elem.clone());
}
(retain, index)
}
if s.is_empty() {
if let Some((_, recycle)) = self.recycle.take() {
self.items = recycle;
self.restore_view();
return;
}
}
let mut retain = vec![];
let mut index = 0;
let items = match &self.recycle {
Some((pre, _)) if pre == s => return,
Some((pre, recycle)) if pre.contains(s) => recycle,
_ => &self.items,
};
while let Some(elem) = items.get(index) {
let next = items.get(index + 1);
if next.map_or(false, |n| n.item.is_child(&elem.item)) {
let (sub_items, current_index) = filter_recursion(items, index, s, cx, params);
index = current_index;
retain.extend(sub_items);
} else if elem.item.filter(cx, s, params) {
retain.push(elem.clone())
}
index += 1;
}
if retain.is_empty() {
if let Some((_, recycle)) = self.recycle.take() {
self.items = recycle;
self.restore_view();
}
return;
}
let recycle = std::mem::replace(&mut self.items, retain);
if let Some(r) = self.recycle.as_mut() {
r.0 = s.into()
} else {
self.recycle = Some((s.into(), recycle));
self.save_view();
}
self.selected = self
.find(0, false, |elem| elem.item.filter(cx, s, params))
.unwrap_or(0);
self.row = self.selected;
}
pub fn clean_recycle(&mut self) {
self.recycle = None;
}
pub fn restore_recycle(&mut self) {
if let Some((_, recycle)) = self.recycle.take() {
self.items = recycle;
}
}
}

@ -16,11 +16,11 @@ include = ["src/**/*", "README.md"]
default = ["crossterm"]
[dependencies]
bitflags = "1.3"
cassowary = "0.3"
unicode-segmentation = "1.10"
crossterm = { version = "0.25", optional = true }
termini = "0.1"
serde = { version = "1", "optional" = true, features = ["derive"]}
bitflags = "1.3.2"
cassowary = "0.3.0"
unicode-segmentation = "1.10.0"
crossterm = { version = "0.25.0", optional = true }
termini = "0.1.4"
serde = { version = "1.0.152", "optional" = true, features = ["derive"] }
helix-view = { version = "0.6", path = "../helix-view", features = ["term"] }
helix-core = { version = "0.6", path = "../helix-core" }

@ -13,16 +13,16 @@ homepage = "https://helix-editor.com"
[dependencies]
helix-core = { version = "0.6", path = "../helix-core" }
tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "parking_lot", "macros"] }
parking_lot = "0.12"
tokio = { version = "1.24.1", features = ["rt", "rt-multi-thread", "time", "sync", "parking_lot", "macros"] }
parking_lot = "0.12.1"
git-repository = { version = "0.32", default-features = false , optional = true }
git-repository = { version = "0.33.0", default-features = false, optional = true }
imara-diff = "0.1.5"
log = "0.4"
log = "0.4.17"
[features]
git = ["git-repository"]
[dev-dependencies]
tempfile = "3.3"
tempfile = "3.3.0"

@ -14,39 +14,39 @@ default = []
term = ["crossterm"]
[dependencies]
bitflags = "1.3"
anyhow = "1"
bitflags = "1.3.2"
anyhow = "1.0.68"
helix-core = { version = "0.6", path = "../helix-core" }
helix-loader = { version = "0.6", path = "../helix-loader" }
helix-lsp = { version = "0.6", path = "../helix-lsp" }
helix-dap = { version = "0.6", path = "../helix-dap" }
crossterm = { version = "0.25", optional = true }
crossterm = { version = "0.25.0", optional = true }
helix-vcs = { version = "0.6", path = "../helix-vcs" }
# Conversion traits
once_cell = "1.17"
url = "2"
once_cell = "1.17.0"
url = "2.3.1"
arc-swap = { version = "1.6.0" }
arc-swap = "1.6.0"
tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] }
tokio-stream = "0.1"
futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
tokio = { version = "1.24.1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] }
tokio-stream = "0.1.11"
futures-util = { version = "0.3.25", features = ["std", "async-await"], default-features = false }
slotmap = "1"
slotmap = "1.0.6"
chardetng = "0.1"
chardetng = "0.1.17"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
toml = "0.5"
log = "~0.4"
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.91"
toml = "0.5.10"
log = "0.4.17"
which = "4.2"
which = "4.3.0"
[target.'cfg(windows)'.dependencies]
clipboard-win = { version = "4.5", features = ["std"] }
clipboard-win = { version = "4.5.0", features = ["std"] }
[dev-dependencies]
helix-tui = { path = "../helix-tui" }

@ -128,7 +128,7 @@ pub struct Document {
// be more troublesome.
pub history: Cell<History>,
pub savepoint: Option<Transaction>,
pub savepoint: Option<(i32, Transaction)>,
last_saved_revision: usize,
version: i32, // should be usize?
@ -510,6 +510,21 @@ impl Document {
Some(fut.boxed())
}
/// Deletes the file associated with this document
pub fn delete(&mut self) -> impl Future<Output = Result<(), anyhow::Error>> {
let path = self
.path()
.expect("Cannot delete with no path set!")
.clone();
async move {
use tokio::fs;
fs::remove_file(path).await?;
Ok(())
}
}
pub fn save<P: Into<PathBuf>>(
&mut self,
path: Option<P>,
@ -811,7 +826,8 @@ impl Document {
if self.savepoint.is_some() {
take_with(&mut self.savepoint, |prev_revert| {
let revert = transaction.invert(&old_doc);
Some(revert.compose(prev_revert.unwrap()))
let (version, prev_revert) = prev_revert.unwrap();
Some((version, revert.compose(prev_revert)))
});
}
@ -906,11 +922,11 @@ impl Document {
}
pub fn savepoint(&mut self) {
self.savepoint = Some(Transaction::new(self.text()));
self.savepoint = Some((self.version, Transaction::new(self.text())));
}
pub fn restore(&mut self, view: &mut View) {
if let Some(revert) = self.savepoint.take() {
if let Some((_, revert)) = self.savepoint.take() {
apply_transaction(&revert, self, view);
}
}

@ -115,6 +115,57 @@ impl Default for FilePickerConfig {
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ExplorerStyle {
Tree,
List,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ExplorerPosition {
Embed,
Overlay,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
pub struct ExplorerConfig {
pub style: ExplorerStyle,
pub position: ExplorerPosition,
/// explorer column width
pub column_width: usize,
}
impl ExplorerConfig {
pub fn is_embed(&self) -> bool {
return self.position == ExplorerPosition::Embed;
}
pub fn is_overlay(&self) -> bool {
return self.position == ExplorerPosition::Overlay;
}
pub fn is_list(&self) -> bool {
return self.style == ExplorerStyle::List;
}
pub fn is_tree(&self) -> bool {
return self.style == ExplorerStyle::Tree;
}
}
impl Default for ExplorerConfig {
fn default() -> Self {
Self {
style: ExplorerStyle::Tree,
position: ExplorerPosition::Embed,
column_width: 30,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
pub struct Config {
@ -154,6 +205,7 @@ pub struct Config {
)]
pub idle_timeout: Duration,
pub completion_trigger_len: u8,
pub completion_trigger_chars: Vec<char>,
/// Whether to display infoboxes. Defaults to true.
pub auto_info: bool,
pub file_picker: FilePickerConfig,
@ -178,6 +230,8 @@ pub struct Config {
pub indent_guides: IndentGuidesConfig,
/// Whether to color modes with different colors. Defaults to `false`.
pub color_modes: bool,
/// explore config
pub explorer: ExplorerConfig,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
@ -280,7 +334,16 @@ impl Default for StatusLineConfig {
Self {
left: vec![E::Mode, E::Spinner, E::FileName],
center: vec![],
right: vec![E::Diagnostics, E::Selections, E::Position, E::FileEncoding],
right: vec![
E::Diagnostics,
E::Selections,
E::Position,
E::PositionPercentage,
E::Separator,
E::FileEncoding,
E::FileLineEnding,
E::FileType,
],
separator: String::from("│"),
mode: ModeConfig::default(),
}
@ -407,7 +470,7 @@ impl std::ops::Deref for CursorShapeConfig {
impl Default for CursorShapeConfig {
fn default() -> Self {
Self([CursorKind::Block; 3])
Self([CursorKind::Block, CursorKind::Underline, CursorKind::Bar])
}
}
@ -574,20 +637,30 @@ impl Default for WhitespaceCharacters {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum RainbowIndentOptions {
None,
Dim,
Normal,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case")]
pub struct IndentGuidesConfig {
pub render: bool,
pub character: char,
pub rainbow: RainbowIndentOptions,
pub skip_levels: u8,
}
impl Default for IndentGuidesConfig {
fn default() -> Self {
Self {
render: true,
skip_levels: 0,
render: false,
character: '',
rainbow: RainbowIndentOptions::None,
}
}
}
@ -604,7 +677,7 @@ impl Default for Config {
vec!["sh".to_owned(), "-c".to_owned()]
},
line_number: LineNumber::Absolute,
cursorline: false,
cursorline: true,
cursorcolumn: false,
gutters: vec![
GutterType::Diagnostics,
@ -628,11 +701,13 @@ impl Default for Config {
search: SearchConfig::default(),
lsp: LspConfig::default(),
terminal: get_terminal_provider(),
rulers: Vec::new(),
rulers: vec![120],
whitespace: WhitespaceConfig::default(),
bufferline: BufferLine::default(),
indent_guides: IndentGuidesConfig::default(),
color_modes: false,
color_modes: true,
explorer: ExplorerConfig::default(),
completion_trigger_chars: vec!['.'],
}
}
}
@ -768,6 +843,7 @@ pub enum Action {
}
/// Error thrown on failed document closed
#[derive(Debug)]
pub enum CloseError {
/// Document doesn't exist
DoesNotExist,
@ -777,6 +853,18 @@ pub enum CloseError {
SaveError(anyhow::Error),
}
impl std::error::Error for CloseError {}
impl std::fmt::Display for CloseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CloseError::DoesNotExist => "Buffer does not exist".fmt(f),
CloseError::BufferModified(s) => write!(f, "The buffer {s} has been modified"),
CloseError::SaveError(e) => write!(f, "Failed to save document {e}"),
}
}
}
impl Editor {
pub fn new(
mut area: Rect,
@ -860,6 +948,10 @@ impl Editor {
.reset(Instant::now() + config.idle_timeout);
}
pub fn reset_idle_timer_zero(&mut self) {
self.idle_timer.as_mut().reset(Instant::now());
}
pub fn clear_status(&mut self) {
self.status_msg = None;
}
@ -938,6 +1030,27 @@ impl Editor {
Self::launch_language_server(&mut self.language_servers, doc)
}
/// Restarts a language server for a given document
pub fn restart_language_server(&mut self, doc_id: DocumentId) -> Option<()> {
let doc = self.documents.get_mut(&doc_id)?;
if let Some(language) = doc.language.as_ref() {
if let Ok(client) = self
.language_servers
.restart(&*language, doc.path())
.map_err(|e| {
log::error!(
"Failed to restart the LSP for `{}` {{ {} }}",
language.scope(),
e
)
})
{
doc.set_language_server(client);
}
};
Some(())
}
/// Launch a language server for a given document
fn launch_language_server(ls: &mut helix_lsp::Registry, doc: &mut Document) -> Option<()> {
// if doc doesn't have a URL it's a scratch buffer, ignore it

@ -202,6 +202,7 @@ pub struct Theme {
styles: HashMap<String, Style>,
// tree-sitter highlight styles are stored in a Vec to optimize lookups
scopes: Vec<String>,
rainbow_length: usize,
highlights: Vec<Style>,
}
@ -210,11 +211,12 @@ impl From<Value> for Theme {
let values: Result<HashMap<String, Value>> =
toml::from_str(&value.to_string()).context("Failed to load theme");
let (styles, scopes, highlights) = build_theme_values(values);
let (styles, scopes, rainbow_length, highlights) = build_theme_values(values);
Self {
styles,
scopes,
rainbow_length,
highlights,
..Default::default()
}
@ -226,13 +228,64 @@ impl<'de> Deserialize<'de> for Theme {
where
D: Deserializer<'de>,
{
let values = HashMap::<String, Value>::deserialize(deserializer)?;
let mut styles = HashMap::new();
let mut scopes = Vec::new();
let mut highlights = Vec::new();
let mut rainbow_length = 0;
if let Ok(mut colors) = HashMap::<String, Value>::deserialize(deserializer) {
// TODO: alert user of parsing failures in editor
let palette = colors
.remove("palette")
.map(|value| {
ThemePalette::try_from(value).unwrap_or_else(|err| {
warn!("{}", err);
ThemePalette::default()
})
})
.unwrap_or_default();
styles.reserve(colors.len());
scopes.reserve(colors.len());
highlights.reserve(colors.len());
for (i, style) in colors
.remove("rainbow")
.and_then(|value| match palette.parse_style_array(value) {
Ok(styles) => Some(styles),
Err(err) => {
warn!("{}", err);
None
}
})
.unwrap_or_else(Self::default_rainbow)
.iter()
.enumerate()
{
let name = format!("rainbow.{}", i);
styles.insert(name.clone(), *style);
scopes.push(name);
highlights.push(*style);
rainbow_length += 1;
}
let (styles, scopes, highlights) = build_theme_values(Ok(values));
for (name, style_value) in colors {
let mut style = Style::default();
if let Err(err) = palette.parse_style(&mut style, style_value) {
warn!("{}", err);
}
// these are used both as UI and as highlights
styles.insert(name.clone(), style);
scopes.push(name);
highlights.push(style);
}
}
Ok(Self {
styles,
scopes,
rainbow_length,
highlights,
..Default::default()
})
@ -241,10 +294,11 @@ impl<'de> Deserialize<'de> for Theme {
fn build_theme_values(
values: Result<HashMap<String, Value>>,
) -> (HashMap<String, Style>, Vec<String>, Vec<Style>) {
) -> (HashMap<String, Style>, Vec<String>, usize, Vec<Style>) {
let mut styles = HashMap::new();
let mut scopes = Vec::new();
let mut highlights = Vec::new();
let mut rainbow_length = 0;
if let Ok(mut colors) = values {
// TODO: alert user of parsing failures in editor
@ -262,6 +316,27 @@ fn build_theme_values(
styles.reserve(colors.len());
scopes.reserve(colors.len());
highlights.reserve(colors.len());
for (i, style) in colors
.remove("rainbow")
.and_then(|value| match palette.parse_style_array(value) {
Ok(styles) => Some(styles),
Err(err) => {
warn!("{}", err);
None
}
})
.unwrap_or_else(Theme::default_rainbow)
.iter()
.enumerate()
{
let name = format!("rainbow.{}", i);
styles.insert(name.clone(), *style);
scopes.push(name);
highlights.push(*style);
rainbow_length += 1;
}
for (name, style_value) in colors {
let mut style = Style::default();
if let Err(err) = palette.parse_style(&mut style, style_value) {
@ -275,9 +350,8 @@ fn build_theme_values(
}
}
(styles, scopes, highlights)
(styles, scopes, rainbow_length, highlights)
}
impl Theme {
#[inline]
pub fn highlight(&self, index: usize) -> Style {
@ -323,6 +397,29 @@ impl Theme {
.all(|color| !matches!(color, Some(Color::Rgb(..))))
})
}
pub fn rainbow_length(&self) -> usize {
if self.rainbow_length == 0 {
1
} else {
self.rainbow_length
}
}
pub fn get_rainbow(&self, index: usize) -> Style {
self.highlights[index % self.rainbow_length]
}
pub fn default_rainbow() -> Vec<Style> {
vec![
Style::default().fg(Color::Red),
Style::default().fg(Color::Yellow),
Style::default().fg(Color::Green),
Style::default().fg(Color::Blue),
Style::default().fg(Color::Cyan),
Style::default().fg(Color::Magenta),
]
}
}
struct ThemePalette {
@ -453,6 +550,24 @@ impl ThemePalette {
}
Ok(())
}
/// Parses a TOML array into a [`Vec`] of [`Style`]. If the value cannot be
/// parsed as an array or if any style in the array cannot be parsed then an
/// error is returned.
pub fn parse_style_array(&self, value: Value) -> Result<Vec<Style>, String> {
let mut styles = Vec::new();
for v in value
.as_array()
.ok_or_else(|| format!("Theme: could not parse value as an array: '{}'", value))?
{
let mut style = Style::default();
self.parse_style(&mut style, v.clone())?;
styles.push(style);
}
Ok(styles)
}
}
impl TryFrom<Value> for ThemePalette {
@ -529,4 +644,51 @@ mod tests {
.add_modifier(Modifier::BOLD)
);
}
#[test]
fn test_parse_valid_style_array() {
let theme = toml::toml! {
rainbow = ["#ff0000", "#ffa500", "#fff000", { fg = "#00ff00", modifiers = ["bold"] }]
};
let palette = ThemePalette::default();
let rainbow = theme.as_table().unwrap().get("rainbow").unwrap();
let parse_result = palette.parse_style_array(rainbow.clone());
assert_eq!(
Ok(vec![
Style::default().fg(Color::Rgb(255, 0, 0)),
Style::default().fg(Color::Rgb(255, 165, 0)),
Style::default().fg(Color::Rgb(255, 240, 0)),
Style::default()
.fg(Color::Rgb(0, 255, 0))
.add_modifier(Modifier::BOLD),
]),
parse_result
)
}
#[test]
fn test_parse_invalid_style_array() {
let palette = ThemePalette::default();
let theme = toml::toml! { invalid_hex_code = ["#f00"] };
let invalid_hex_code = theme.as_table().unwrap().get("invalid_hex_code").unwrap();
let parse_result = palette.parse_style_array(invalid_hex_code.clone());
assert_eq!(
Err("Theme: malformed hexcode: #f00".to_string()),
parse_result
);
let theme = toml::toml! { not_an_array = { red = "#ff0000" } };
let not_an_array = theme.as_table().unwrap().get("not_an_array").unwrap();
let parse_result = palette.parse_style_array(not_an_array.clone());
assert_eq!(
Err("Theme: could not parse value as an array: 'red = \"#ff0000\"\n'".to_string()),
parse_result
)
}
}

@ -1,3 +1,17 @@
<<<<<<< HEAD
(attribute_name) @attribute
(attribute_value) @string
(comment) @comment
(cdata_sect) @special
(tag_name) @tag
[
"version"
"encoding"
"standalone"
] @attribute
(xml_decl) @constant
||||||| ce469abf
=======
(comment) @comment
[
@ -40,3 +54,4 @@
[
"<" ">" "</" "/>" "<?" "?>" "<!"
] @punctuation.bracket
>>>>>>> master

@ -70,6 +70,12 @@
"warning" = "my_yellow2"
"error" = "my_red"
"ui.explorer.file" = { fg = "my_white" }
"ui.explorer.dir" = { fg = "my_yellow1" }
"ui.explorer.exe" = { fg = "my_green" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { modifiers = ["reversed"] }
[palette]
my_black = "#212121" # Cursorline
my_gray0 = "#262626" # Default Background

@ -54,6 +54,12 @@
"warning" = "base09"
"error" = "base08"
"ui.explorer.file" = { fg = "base05" }
"ui.explorer.dir" = { fg = "base0D" }
"ui.explorer.exe" = { fg = "base05" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "base02" }
"ui.bufferline" = { fg = "base04", bg = "base00" }
"ui.bufferline.active" = { fg = "base06", bg = "base01" }

@ -54,6 +54,12 @@
"warning" = "base09"
"error" = "base08"
"ui.explorer.file" = { fg = "base05" }
"ui.explorer.dir" = { fg = "base0D" }
"ui.explorer.exe" = { fg = "base05" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "base02" }
"ui.bufferline" = { fg = "base04", bg = "base01" }
"ui.bufferline.active" = { fg = "base07", bg = "base00" }

@ -50,3 +50,9 @@
"debug" = "gray"
"warning" = "yellow"
"error" = "light-red"
# "ui.explorer.file" = { fg = "base05" }
"ui.explorer.dir" = { fg = "light-blue" }
# "ui.explorer.exe" = { fg = "base05" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "light-gray" }

@ -77,7 +77,30 @@
"diagnostic.info" = { underline = { color = "bogster-teal", style = "curl"} }
"diagnostic.hint" = { underline = { color = "bogster-blue", style = "curl"} }
"ui.explorer.file" = { fg = "#e5ded6" }
"ui.explorer.dir" = { fg = "#59dcd8" }
"ui.explorer.exe" = { fg = "#e5ded6" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "#313f4e" }
[palette]
bogster0 = "#dc7759"
bogster1 = "#dcb659"
bogster2 = "#d32c5d"
bogster3 = "#7fdc59"
bogster4 = "#c6b8ad"
bogster5 = "#dc597f"
bogster6 = "#59dcd8"
bogster7 = "#627d9d"
bogster8 = "#59dcb7"
bogster9 = "#59c0dc"
bogster10 = "#161c23"
bogster11 = "#415367"
bogster12 = "#e5ded6"
bogster13 = "#131920"
bogster14 = "#232d38"
bogster15 = "#313f4e"
bogster16 = "#ABB2BF"
bogster-yellow = "#dcb659"
bogster-lblue = "#59dcd8"
bogster-teal = "#59dcb7"

@ -66,6 +66,12 @@
"diagnostic.info" = { underline = { color = "lilac", style = "curl"} }
"diagnostic.hint" = { underline = { color = "lilac", style = "curl"} }
"ui.explorer.file" = { fg = "lilac" }
"ui.explorer.dir" = { fg = "mint" }
"ui.explorer.exe" = { fg = "lilac" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "berry_saturated" }
[palette]
berry = "#3A2A4D"
berry_fade = "#5A3D6E"

@ -97,6 +97,12 @@
"diagnostic.error".underline = { color = "red", style = "curl" }
"diagnostic".underline = { color = "gold", style = "curl" }
"ui.explorer.file" = { fg = "text" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "text" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "dark_blue2" }
[palette]
white = "#ffffff"
orange = "#ce9178"

@ -0,0 +1,82 @@
# Author : Sam Sartor <me@samsartor.com>, Trivernis <trivernis@pm.me>
# A port of https://github.com/bceskavich/dracula-at-night
"comment" = { fg = "comment" }
"constant" = { fg = "purple" }
"constant.character.escape" = { fg = "pink" }
"function" = { fg = "green" }
"keyword" = { fg = "pink" }
"operator" = { fg = "pink" }
"special" = { fg = "yellow" }
"punctuation" = { fg = "foreground" }
"string" = { fg = "yellow" }
"string.regexp" = { fg = "red" }
"tag" = { fg = "pink" }
"attribute" = { fg = "cyan" }
"type" = { fg = "cyan", modifiers = ["italic"] }
"type.enum.variant" = { fg = "foreground", modifiers = ["italic"] }
"variable" = { fg = "foreground" }
"variable.builtin" = { fg = "cyan", modifiers = ["italic"] }
"variable.parameter" = { fg ="orange", modifiers = ["italic"] }
"diff.plus" = { fg = "green" }
"diff.delta" = { fg = "orange" }
"diff.minus" = { fg = "red" }
"ui.background" = { fg = "foreground", bg = "background" }
"ui.cursor" = { fg = "background", bg = "orange", modifiers = ["dim"] }
"ui.cursor.match" = { fg = "green", modifiers = ["underlined"] }
"ui.cursor.primary" = { fg = "background", bg = "cyan", modifier = ["dim"] }
"ui.cursorline" = {bg = "background_dark"}
"ui.help" = { fg = "foreground", bg = "background_dark" }
"ui.linenr" = { fg = "comment" }
"ui.linenr.selected" = { fg = "foreground" }
"ui.menu" = { fg = "foreground", bg = "background_dark" }
"ui.menu.selected" = { fg = "cyan", bg = "background_dark" }
"ui.popup" = { fg = "foreground", bg = "background_dark" }
"ui.selection" = { fg = "background", bg = "purple", modifiers = ["dim"] }
"ui.selection.primary" = { fg = "background", bg = "pink" }
"ui.text" = { fg = "foreground" }
"ui.text.focus" = { fg = "cyan" }
"ui.window" = { fg = "foreground" }
"ui.virtual.ruler" = { bg = "ruler" }
"ui.virtual.indent-guide" = { fg = "ruler" }
"ui.statusline" = { fg = "foreground", bg = "background_dark" }
"ui.statusline.inactive" = { fg = "comment", bg = "background_dark" }
"ui.statusline.normal" = { fg = "background_dark", bg = "purple"}
"ui.statusline.insert" = { fg = "background_dark", bg = "pink"}
"ui.statusline.select" = { fg = "background_dark", bg = "cyan"}
"error" = { fg = "red" }
"warning" = { fg = "cyan" }
"markup.heading" = { fg = "purple", modifiers = ["bold"] }
"markup.list" = "cyan"
"markup.bold" = { fg = "orange", modifiers = ["bold"] }
"markup.italic" = { fg = "yellow", modifiers = ["italic"] }
"markup.link.url" = "cyan"
"markup.link.text" = "pink"
"markup.quote" = { fg = "yellow", modifiers = ["italic"] }
"markup.raw" = { fg = "foreground" }
"ui.explorer.file" = { fg = "foreground" }
"ui.explorer.dir" = { fg = "cyan" }
"ui.explorer.exe" = { fg = "foreground" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "comment" }
rainbow = ["#7c5ea3", "#9c5b95", "#9c5e80", "#6b4466"]
[palette]
background = "#3A2A4D"
background_dark = "#2B1C3D"
foreground = "#f8f8f2"
ruler = "#453254"
comment = "#886C9C"
red = "#ff5555"
orange = "#ffb86c"
yellow = "#f1fa8c"
green = "#50fa7b"
purple = "#bd93f9"
cyan = "#8be9fd"
pink = "#ff79c6"

@ -55,6 +55,12 @@
"markup.quote" = { fg = "yellow", modifiers = ["italic"] }
"markup.raw" = { fg = "foreground" }
"ui.explorer.file" = { fg = "foreground" }
"ui.explorer.dir" = { fg = "cyan" }
"ui.explorer.exe" = { fg = "foreground" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "secondary_highlight" }
"diagnostic".underline = { color = "orange", style = "curl" }
"diagnostic.error".underline = { color = "red", style = "curl" }

@ -55,6 +55,12 @@
"markup.quote" = { fg = "yellow", modifiers = ["italic"] }
"markup.raw" = { fg = "foreground" }
"ui.explorer.file" = { fg = "foreground" }
"ui.explorer.dir" = { fg = "cyan" }
"ui.explorer.exe" = { fg = "foreground" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "comment" }
[palette]
background = "#0e1419"
background_dark = "#21222c"

@ -95,6 +95,12 @@
"diagnostic.error" = { underline = { color = "red", style = "curl" } }
"ui.explorer.file" = { fg = "fg" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "fg" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "grey1" }
[palette]
bg0 = "#2b3339"

@ -94,6 +94,12 @@
"diagnostic.warning" = { underline = { color = "yellow", style = "curl" } }
"diagnostic.error" = { underline = { color = "red", style = "curl" } }
"ui.explorer.file" = { fg = "fg" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "fg" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "grey1" }
[palette]
bg0 = "#fff9e8"

@ -73,6 +73,12 @@
"markup.link.text" = "red1"
"markup.raw" = "red1"
"ui.explorer.file" = { fg = "fg1" }
"ui.explorer.dir" = { fg = "blue0" }
"ui.explorer.exe" = { fg = "fg1" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "bg3" }
[palette]
bg0 = "#282828" # main background
bg1 = "#3c3836"

@ -74,6 +74,12 @@
"markup.link.text" = "red1"
"markup.raw" = "red1"
"ui.explorer.file" = { fg = "fg1" }
"ui.explorer.dir" = { fg = "blue0" }
"ui.explorer.exe" = { fg = "fg1" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "bg3" }
[palette]
bg0 = "#fbf1c7" # main background
bg1 = "#ebdbb2"

@ -68,6 +68,12 @@
"info" = "#839A53"
"hint" = "#A6B6CE"
"ui.explorer.file" = { fg = "#7B91B3" }
"ui.explorer.dir" = { fg = "#89BEB7" }
"ui.explorer.exe" = { fg = "#7B91B3" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "#F3EAE9" }
"diagnostic.warning" = { underline = { color = "#D4A520", style = "curl" } }
"diagnostic.error" = { underline = { color = "#D74E50", style = "curl" } }
"diagnostic.info" = { underline = { color = "#839A53", style = "curl" } }

@ -0,0 +1,84 @@
# Author : Ingrid Rebecca Abraham <git@ingrids.email>
"attribute" = "#839A53"
"keyword" = { fg = "#D74E50", modifiers = ["bold"] }
"keyword.directive" = "#6F873E"
"namespace" = "#839A53"
"punctuation" = "#C97270"
"punctuation.delimiter" = "#C97270"
"operator" = { fg = "#D74E50", modifiers = ["bold"] }
"special" = "#D68482"
"variable.other.member" = "#89BEB7"
"variable" = "#A6B6CE"
"variable.parameter" = "#89BEB7"
"type" = { fg = "#A6B6CE", modifiers = ["bold"] }
"type.builtin" = "#839A53"
"constructor" = { fg = "#839A53", modifiers = ["bold"] }
"function" = { fg = "#89BEB7", modifiers = ["bold"] }
"function.macro" = { fg = "#D4A520", modifiers = ["bold"] }
"function.builtin" = "#89BEB7"
"comment" = "#A6B6CE"
"variable.builtin" = "#D4A520"
"constant" = "#D4A520"
"constant.builtin" = "#D4A520"
"string" = "#D74E50"
"constant.numeric" = "#D74E50"
"constant.character.escape" = { fg = "#D74E50", modifiers = ["bold"] }
"label" = "#D68482"
"module" = "#839A53"
# TODO
"markup.heading" = "blue"
"markup.list" = "red"
"markup.bold" = { fg = "yellow", modifiers = ["bold"] }
"markup.italic" = { fg = "magenta", modifiers = ["italic"] }
"markup.link.url" = { fg = "yellow", modifiers = ["underlined"] }
"markup.link.text" = "red"
"markup.quote" = "cyan"
"markup.raw" = "green"
"diff.plus" = "#839A53"
"diff.delta" = "#D4A520"
"diff.minus" = "#D74E50"
"ui.background" = { bg = "#FFFCFD" }
"ui.linenr" = { fg = "#bbbbbb" }
"ui.linenr.selected" = { fg = "#ED5466", modifiers = ["bold"] }
"ui.cursorline" = { bg = "#F3EAE9" }
"ui.statusline" = { fg = "#250E07", bg = "#F3EAE9" }
"ui.statusline.inactive" = { fg = "#7b91b3", bg = "#F3EAE9" }
"ui.popup" = { fg = "#7B91b3", bg = "#F3E8E9" }
"ui.window" = { bg = "#D8B8B3" }
"ui.help" = { bg = "#D8B8B3", fg = "#250E07" }
"ui.text" = { fg = "#7B91B3" }
"ui.text.focus" = { fg = "#250E07", modifiers= ["bold"] }
"ui.virtual.whitespace" = "#A6B6CE"
"ui.virtual.ruler" = { bg = "#F3EAE9" }
"ui.selection" = { bg = "#F3EAE9" }
"ui.cursor.primary" = { bg = "#ED5466", fg = "#FFFCFD", modifiers = ["bold"] }
"ui.cursor.match" = { bg = "#F3EAE9", fg = "#ED5466", modifiers = ["bold"] }
"ui.menu" = { fg = "#7B91B3", bg = "#F3EAE9" }
"ui.menu.selected" = { fg = "#D74E50", bg = "#F3EAE9" }
"warning" = "#D4A520"
"error" = "#D74E50"
"info" = "#839A53"
"hint" = "#A6B6CE"
<<<<<<< HEAD
"ui.explorer.file" = { fg = "#7B91B3" }
"ui.explorer.dir" = { fg = "#89BEB7" }
"ui.explorer.exe" = { fg = "#7B91B3" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "#F3EAE9" }
||||||| 7ac72a39
=======
"diagnostic.warning" = { underline = { color = "#D4A520", style = "curl" } }
"diagnostic.error" = { underline = { color = "#D74E50", style = "curl" } }
"diagnostic.info" = { underline = { color = "#839A53", style = "curl" } }
"diagnostic.hint" = { underline = { color = "#A6B6CE", style = "curl" } }
>>>>>>> master

@ -0,0 +1,84 @@
# Author : Ingrid Rebecca Abraham <git@ingrids.email>
"attribute" = "#839A53"
"keyword" = { fg = "#D74E50", modifiers = ["bold"] }
"keyword.directive" = "#6F873E"
"namespace" = "#839A53"
"punctuation" = "#C97270"
"punctuation.delimiter" = "#C97270"
"operator" = { fg = "#D74E50", modifiers = ["bold"] }
"special" = "#D68482"
"variable.other.member" = "#89BEB7"
"variable" = "#A6B6CE"
"variable.parameter" = "#89BEB7"
"type" = { fg = "#A6B6CE", modifiers = ["bold"] }
"type.builtin" = "#839A53"
"constructor" = { fg = "#839A53", modifiers = ["bold"] }
"function" = { fg = "#89BEB7", modifiers = ["bold"] }
"function.macro" = { fg = "#D4A520", modifiers = ["bold"] }
"function.builtin" = "#89BEB7"
"comment" = "#A6B6CE"
"variable.builtin" = "#D4A520"
"constant" = "#D4A520"
"constant.builtin" = "#D4A520"
"string" = "#D74E50"
"constant.numeric" = "#D74E50"
"constant.character.escape" = { fg = "#D74E50", modifiers = ["bold"] }
"label" = "#D68482"
"module" = "#839A53"
# TODO
"markup.heading" = "blue"
"markup.list" = "red"
"markup.bold" = { fg = "yellow", modifiers = ["bold"] }
"markup.italic" = { fg = "magenta", modifiers = ["italic"] }
"markup.link.url" = { fg = "yellow", modifiers = ["underlined"] }
"markup.link.text" = "red"
"markup.quote" = "cyan"
"markup.raw" = "green"
"diff.plus" = "#839A53"
"diff.delta" = "#D4A520"
"diff.minus" = "#D74E50"
"ui.background" = { bg = "#FFFCFD" }
"ui.linenr" = { fg = "#bbbbbb" }
"ui.linenr.selected" = { fg = "#ED5466", modifiers = ["bold"] }
"ui.cursorline" = { bg = "#F3EAE9" }
"ui.statusline" = { fg = "#250E07", bg = "#F3EAE9" }
"ui.statusline.inactive" = { fg = "#7b91b3", bg = "#F3EAE9" }
"ui.popup" = { fg = "#7B91b3", bg = "#F3E8E9" }
"ui.window" = { bg = "#D8B8B3" }
"ui.help" = { bg = "#D8B8B3", fg = "#250E07" }
"ui.text" = { fg = "#7B91B3" }
"ui.text.focus" = { fg = "#250E07", modifiers= ["bold"] }
"ui.virtual.whitespace" = "#A6B6CE"
"ui.virtual.ruler" = { bg = "#F3EAE9" }
"ui.selection" = { bg = "#F3EAE9" }
"ui.cursor.primary" = { bg = "#ED5466", fg = "#FFFCFD", modifiers = ["bold"] }
"ui.cursor.match" = { bg = "#F3EAE9", fg = "#ED5466", modifiers = ["bold"] }
"ui.menu" = { fg = "#7B91B3", bg = "#F3EAE9" }
"ui.menu.selected" = { fg = "#D74E50", bg = "#F3EAE9" }
"warning" = "#D4A520"
"error" = "#D74E50"
"info" = "#839A53"
"hint" = "#A6B6CE"
<<<<<<< HEAD
"ui.explorer.file" = { fg = "#7B91B3" }
"ui.explorer.dir" = { fg = "#89BEB7" }
"ui.explorer.exe" = { fg = "#7B91B3" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "#F3EAE9" }
||||||| 7ac72a39
=======
"diagnostic.warning" = { underline = { color = "#D4A520", style = "curl" } }
"diagnostic.error" = { underline = { color = "#D74E50", style = "curl" } }
"diagnostic.info" = { underline = { color = "#839A53", style = "curl" } }
"diagnostic.hint" = { underline = { color = "#A6B6CE", style = "curl" } }
>>>>>>> master

@ -0,0 +1,69 @@
# Author : Ingrid Rebecca Abraham <git@ingrids.email>
"attribute" = "#839A53"
"keyword" = { fg = "#D74E50", modifiers = ["bold"] }
"keyword.directive" = "#6F873E"
"namespace" = "#839A53"
"punctuation" = "#C97270"
"punctuation.delimiter" = "#C97270"
"operator" = { fg = "#D74E50", modifiers = ["bold"] }
"special" = "#D68482"
"variable.other.member" = "#89BEB7"
"variable" = "#A6B6CE"
"variable.parameter" = "#89BEB7"
"type" = { fg = "#A6B6CE", modifiers = ["bold"] }
"type.builtin" = "#839A53"
"constructor" = { fg = "#839A53", modifiers = ["bold"] }
"function" = { fg = "#89BEB7", modifiers = ["bold"] }
"function.macro" = { fg = "#D4A520", modifiers = ["bold"] }
"function.builtin" = "#89BEB7"
"comment" = "#A6B6CE"
"variable.builtin" = "#D4A520"
"constant" = "#D4A520"
"constant.builtin" = "#D4A520"
"string" = "#D74E50"
"constant.numeric" = "#D74E50"
"constant.character.escape" = { fg = "#D74E50", modifiers = ["bold"] }
"label" = "#D68482"
"module" = "#839A53"
# TODO
"markup.heading" = "blue"
"markup.list" = "red"
"markup.bold" = { fg = "yellow", modifiers = ["bold"] }
"markup.italic" = { fg = "magenta", modifiers = ["italic"] }
"markup.link.url" = { fg = "yellow", modifiers = ["underlined"] }
"markup.link.text" = "red"
"markup.quote" = "cyan"
"markup.raw" = "green"
"diff.plus" = "#839A53"
"diff.delta" = "#D4A520"
"diff.minus" = "#D74E50"
"ui.background" = { bg = "#FFFCFD" }
"ui.linenr" = { fg = "#bbbbbb" }
"ui.linenr.selected" = { fg = "#ED5466", modifiers = ["bold"] }
"ui.cursorline" = { bg = "#F3EAE9" }
"ui.statusline" = { fg = "#250E07", bg = "#F3EAE9" }
"ui.statusline.inactive" = { fg = "#7b91b3", bg = "#F3EAE9" }
"ui.popup" = { fg = "#7B91b3", bg = "#F3E8E9" }
"ui.window" = { bg = "#D8B8B3" }
"ui.help" = { bg = "#D8B8B3", fg = "#250E07" }
"ui.text" = { fg = "#7B91B3" }
"ui.text.focus" = { fg = "#250E07", modifiers= ["bold"] }
"ui.virtual.whitespace" = "#A6B6CE"
"ui.virtual.ruler" = { bg = "#F3EAE9" }
"ui.selection" = { bg = "#F3EAE9" }
"ui.cursor.primary" = { bg = "#ED5466", fg = "#FFFCFD", modifiers = ["bold"] }
"ui.cursor.match" = { bg = "#F3EAE9", fg = "#ED5466", modifiers = ["bold"] }
"ui.menu" = { fg = "#7B91B3", bg = "#F3EAE9" }
"ui.menu.selected" = { fg = "#D74E50", bg = "#F3EAE9" }
"warning" = "#D4A520"
"error" = "#D74E50"
"info" = "#839A53"
"hint" = "#A6B6CE"

@ -0,0 +1,69 @@
# Author : Ingrid Rebecca Abraham <git@ingrids.email>
"attribute" = "#839A53"
"keyword" = { fg = "#D74E50", modifiers = ["bold"] }
"keyword.directive" = "#6F873E"
"namespace" = "#839A53"
"punctuation" = "#C97270"
"punctuation.delimiter" = "#C97270"
"operator" = { fg = "#D74E50", modifiers = ["bold"] }
"special" = "#D68482"
"variable.other.member" = "#89BEB7"
"variable" = "#A6B6CE"
"variable.parameter" = "#89BEB7"
"type" = { fg = "#A6B6CE", modifiers = ["bold"] }
"type.builtin" = "#839A53"
"constructor" = { fg = "#839A53", modifiers = ["bold"] }
"function" = { fg = "#89BEB7", modifiers = ["bold"] }
"function.macro" = { fg = "#D4A520", modifiers = ["bold"] }
"function.builtin" = "#89BEB7"
"comment" = "#A6B6CE"
"variable.builtin" = "#D4A520"
"constant" = "#D4A520"
"constant.builtin" = "#D4A520"
"string" = "#D74E50"
"constant.numeric" = "#D74E50"
"constant.character.escape" = { fg = "#D74E50", modifiers = ["bold"] }
"label" = "#D68482"
"module" = "#839A53"
# TODO
"markup.heading" = "blue"
"markup.list" = "red"
"markup.bold" = { fg = "yellow", modifiers = ["bold"] }
"markup.italic" = { fg = "magenta", modifiers = ["italic"] }
"markup.link.url" = { fg = "yellow", modifiers = ["underlined"] }
"markup.link.text" = "red"
"markup.quote" = "cyan"
"markup.raw" = "green"
"diff.plus" = "#839A53"
"diff.delta" = "#D4A520"
"diff.minus" = "#D74E50"
"ui.background" = { bg = "#FFFCFD" }
"ui.linenr" = { fg = "#bbbbbb" }
"ui.linenr.selected" = { fg = "#ED5466", modifiers = ["bold"] }
"ui.cursorline" = { bg = "#F3EAE9" }
"ui.statusline" = { fg = "#250E07", bg = "#F3EAE9" }
"ui.statusline.inactive" = { fg = "#7b91b3", bg = "#F3EAE9" }
"ui.popup" = { fg = "#7B91b3", bg = "#F3E8E9" }
"ui.window" = { bg = "#D8B8B3" }
"ui.help" = { bg = "#D8B8B3", fg = "#250E07" }
"ui.text" = { fg = "#7B91B3" }
"ui.text.focus" = { fg = "#250E07", modifiers= ["bold"] }
"ui.virtual.whitespace" = "#A6B6CE"
"ui.virtual.ruler" = { bg = "#F3EAE9" }
"ui.selection" = { bg = "#F3EAE9" }
"ui.cursor.primary" = { bg = "#ED5466", fg = "#FFFCFD", modifiers = ["bold"] }
"ui.cursor.match" = { bg = "#F3EAE9", fg = "#ED5466", modifiers = ["bold"] }
"ui.menu" = { fg = "#7B91B3", bg = "#F3EAE9" }
"ui.menu.selected" = { fg = "#D74E50", bg = "#F3EAE9" }
"warning" = "#D4A520"
"error" = "#D74E50"
"info" = "#839A53"
"hint" = "#A6B6CE"

@ -0,0 +1,75 @@
# Author : Ingrid Rebecca Abraham <git@ingrids.email>
"attribute" = "#839A53"
"keyword" = { fg = "#D74E50", modifiers = ["bold"] }
"keyword.directive" = "#6F873E"
"namespace" = "#839A53"
"punctuation" = "#C97270"
"punctuation.delimiter" = "#C97270"
"operator" = { fg = "#D74E50", modifiers = ["bold"] }
"special" = "#D68482"
"variable.other.member" = "#89BEB7"
"variable" = "#A6B6CE"
"variable.parameter" = "#89BEB7"
"type" = { fg = "#A6B6CE", modifiers = ["bold"] }
"type.builtin" = "#839A53"
"constructor" = { fg = "#839A53", modifiers = ["bold"] }
"function" = { fg = "#89BEB7", modifiers = ["bold"] }
"function.macro" = { fg = "#D4A520", modifiers = ["bold"] }
"function.builtin" = "#89BEB7"
"comment" = "#A6B6CE"
"variable.builtin" = "#D4A520"
"constant" = "#D4A520"
"constant.builtin" = "#D4A520"
"string" = "#D74E50"
"constant.numeric" = "#D74E50"
"constant.character.escape" = { fg = "#D74E50", modifiers = ["bold"] }
"label" = "#D68482"
"module" = "#839A53"
# TODO
"markup.heading" = "blue"
"markup.list" = "red"
"markup.bold" = { fg = "yellow", modifiers = ["bold"] }
"markup.italic" = { fg = "magenta", modifiers = ["italic"] }
"markup.link.url" = { fg = "yellow", modifiers = ["underlined"] }
"markup.link.text" = "red"
"markup.quote" = "cyan"
"markup.raw" = "green"
"diff.plus" = "#839A53"
"diff.delta" = "#D4A520"
"diff.minus" = "#D74E50"
"ui.background" = { bg = "#FFFCFD" }
"ui.linenr" = { fg = "#bbbbbb" }
"ui.linenr.selected" = { fg = "#ED5466", modifiers = ["bold"] }
"ui.cursorline" = { bg = "#F3EAE9" }
"ui.statusline" = { fg = "#250E07", bg = "#F3EAE9" }
"ui.statusline.inactive" = { fg = "#7b91b3", bg = "#F3EAE9" }
"ui.popup" = { fg = "#7B91b3", bg = "#F3E8E9" }
"ui.window" = { bg = "#D8B8B3" }
"ui.help" = { bg = "#D8B8B3", fg = "#250E07" }
"ui.text" = { fg = "#7B91B3" }
"ui.text.focus" = { fg = "#250E07", modifiers= ["bold"] }
"ui.virtual.whitespace" = "#A6B6CE"
"ui.virtual.ruler" = { bg = "#F3EAE9" }
"ui.selection" = { bg = "#F3EAE9" }
"ui.cursor.primary" = { bg = "#ED5466", fg = "#FFFCFD", modifiers = ["bold"] }
"ui.cursor.match" = { bg = "#F3EAE9", fg = "#ED5466", modifiers = ["bold"] }
"ui.menu" = { fg = "#7B91B3", bg = "#F3EAE9" }
"ui.menu.selected" = { fg = "#D74E50", bg = "#F3EAE9" }
"warning" = "#D4A520"
"error" = "#D74E50"
"info" = "#839A53"
"hint" = "#A6B6CE"
"ui.explorer.file" = { fg = "#7B91B3" }
"ui.explorer.dir" = { fg = "#89BEB7" }
"ui.explorer.exe" = { fg = "#7B91B3" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "#F3EAE9" }

@ -0,0 +1,75 @@
# Author : Ingrid Rebecca Abraham <git@ingrids.email>
"attribute" = "#839A53"
"keyword" = { fg = "#D74E50", modifiers = ["bold"] }
"keyword.directive" = "#6F873E"
"namespace" = "#839A53"
"punctuation" = "#C97270"
"punctuation.delimiter" = "#C97270"
"operator" = { fg = "#D74E50", modifiers = ["bold"] }
"special" = "#D68482"
"variable.other.member" = "#89BEB7"
"variable" = "#A6B6CE"
"variable.parameter" = "#89BEB7"
"type" = { fg = "#A6B6CE", modifiers = ["bold"] }
"type.builtin" = "#839A53"
"constructor" = { fg = "#839A53", modifiers = ["bold"] }
"function" = { fg = "#89BEB7", modifiers = ["bold"] }
"function.macro" = { fg = "#D4A520", modifiers = ["bold"] }
"function.builtin" = "#89BEB7"
"comment" = "#A6B6CE"
"variable.builtin" = "#D4A520"
"constant" = "#D4A520"
"constant.builtin" = "#D4A520"
"string" = "#D74E50"
"constant.numeric" = "#D74E50"
"constant.character.escape" = { fg = "#D74E50", modifiers = ["bold"] }
"label" = "#D68482"
"module" = "#839A53"
# TODO
"markup.heading" = "blue"
"markup.list" = "red"
"markup.bold" = { fg = "yellow", modifiers = ["bold"] }
"markup.italic" = { fg = "magenta", modifiers = ["italic"] }
"markup.link.url" = { fg = "yellow", modifiers = ["underlined"] }
"markup.link.text" = "red"
"markup.quote" = "cyan"
"markup.raw" = "green"
"diff.plus" = "#839A53"
"diff.delta" = "#D4A520"
"diff.minus" = "#D74E50"
"ui.background" = { bg = "#FFFCFD" }
"ui.linenr" = { fg = "#bbbbbb" }
"ui.linenr.selected" = { fg = "#ED5466", modifiers = ["bold"] }
"ui.cursorline" = { bg = "#F3EAE9" }
"ui.statusline" = { fg = "#250E07", bg = "#F3EAE9" }
"ui.statusline.inactive" = { fg = "#7b91b3", bg = "#F3EAE9" }
"ui.popup" = { fg = "#7B91b3", bg = "#F3E8E9" }
"ui.window" = { bg = "#D8B8B3" }
"ui.help" = { bg = "#D8B8B3", fg = "#250E07" }
"ui.text" = { fg = "#7B91B3" }
"ui.text.focus" = { fg = "#250E07", modifiers= ["bold"] }
"ui.virtual.whitespace" = "#A6B6CE"
"ui.virtual.ruler" = { bg = "#F3EAE9" }
"ui.selection" = { bg = "#F3EAE9" }
"ui.cursor.primary" = { bg = "#ED5466", fg = "#FFFCFD", modifiers = ["bold"] }
"ui.cursor.match" = { bg = "#F3EAE9", fg = "#ED5466", modifiers = ["bold"] }
"ui.menu" = { fg = "#7B91B3", bg = "#F3EAE9" }
"ui.menu.selected" = { fg = "#D74E50", bg = "#F3EAE9" }
"warning" = "#D4A520"
"error" = "#D74E50"
"info" = "#839A53"
"hint" = "#A6B6CE"
"ui.explorer.file" = { fg = "#7B91B3" }
"ui.explorer.dir" = { fg = "#89BEB7" }
"ui.explorer.exe" = { fg = "#7B91B3" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "#F3EAE9" }

@ -0,0 +1,74 @@
# Author : Ingrid Rebecca Abraham <git@ingrids.email>
"attribute" = "#839A53"
"keyword" = { fg = "#D74E50", modifiers = ["bold"] }
"keyword.directive" = "#6F873E"
"namespace" = "#839A53"
"punctuation" = "#C97270"
"punctuation.delimiter" = "#C97270"
"operator" = { fg = "#D74E50", modifiers = ["bold"] }
"special" = "#D68482"
"variable.other.member" = "#89BEB7"
"variable" = "#A6B6CE"
"variable.parameter" = "#89BEB7"
"type" = { fg = "#A6B6CE", modifiers = ["bold"] }
"type.builtin" = "#839A53"
"constructor" = { fg = "#839A53", modifiers = ["bold"] }
"function" = { fg = "#89BEB7", modifiers = ["bold"] }
"function.macro" = { fg = "#D4A520", modifiers = ["bold"] }
"function.builtin" = "#89BEB7"
"comment" = "#A6B6CE"
"variable.builtin" = "#D4A520"
"constant" = "#D4A520"
"constant.builtin" = "#D4A520"
"string" = "#D74E50"
"constant.numeric" = "#D74E50"
"constant.character.escape" = { fg = "#D74E50", modifiers = ["bold"] }
"label" = "#D68482"
"module" = "#839A53"
# TODO
"markup.heading" = "blue"
"markup.list" = "red"
"markup.bold" = { fg = "yellow", modifiers = ["bold"] }
"markup.italic" = { fg = "magenta", modifiers = ["italic"] }
"markup.link.url" = { fg = "yellow", modifiers = ["underlined"] }
"markup.link.text" = "red"
"markup.quote" = "cyan"
"markup.raw" = "green"
"diff.plus" = "#839A53"
"diff.delta" = "#D4A520"
"diff.minus" = "#D74E50"
"ui.background" = { bg = "#FFFCFD" }
"ui.linenr" = { fg = "#bbbbbb" }
"ui.linenr.selected" = { fg = "#ED5466", modifiers = ["bold"] }
"ui.cursorline" = { bg = "#F3EAE9" }
"ui.statusline" = { fg = "#250E07", bg = "#F3EAE9" }
"ui.statusline.inactive" = { fg = "#7b91b3", bg = "#F3EAE9" }
"ui.popup" = { fg = "#7B91b3", bg = "#F3E8E9" }
"ui.window" = { bg = "#D8B8B3" }
"ui.help" = { bg = "#D8B8B3", fg = "#250E07" }
"ui.text" = { fg = "#7B91B3" }
"ui.text.focus" = { fg = "#250E07", modifiers= ["bold"] }
"ui.virtual.whitespace" = "#A6B6CE"
"ui.virtual.ruler" = { bg = "#F3EAE9" }
"ui.selection" = { bg = "#F3EAE9" }
"ui.cursor.primary" = { bg = "#ED5466", fg = "#FFFCFD", modifiers = ["bold"] }
"ui.cursor.match" = { bg = "#F3EAE9", fg = "#ED5466", modifiers = ["bold"] }
"ui.menu" = { fg = "#7B91B3", bg = "#F3EAE9" }
"ui.menu.selected" = { fg = "#D74E50", bg = "#F3EAE9" }
"warning" = "#D4A520"
"error" = "#D74E50"
"info" = "#839A53"
"hint" = "#A6B6CE"
"diagnostic.warning" = { underline = { color = "#D4A520", style = "curl" } }
"diagnostic.error" = { underline = { color = "#D74E50", style = "curl" } }
"diagnostic.info" = { underline = { color = "#839A53", style = "curl" } }
"diagnostic.hint" = { underline = { color = "#A6B6CE", style = "curl" } }

@ -0,0 +1,74 @@
# Author : Ingrid Rebecca Abraham <git@ingrids.email>
"attribute" = "#839A53"
"keyword" = { fg = "#D74E50", modifiers = ["bold"] }
"keyword.directive" = "#6F873E"
"namespace" = "#839A53"
"punctuation" = "#C97270"
"punctuation.delimiter" = "#C97270"
"operator" = { fg = "#D74E50", modifiers = ["bold"] }
"special" = "#D68482"
"variable.other.member" = "#89BEB7"
"variable" = "#A6B6CE"
"variable.parameter" = "#89BEB7"
"type" = { fg = "#A6B6CE", modifiers = ["bold"] }
"type.builtin" = "#839A53"
"constructor" = { fg = "#839A53", modifiers = ["bold"] }
"function" = { fg = "#89BEB7", modifiers = ["bold"] }
"function.macro" = { fg = "#D4A520", modifiers = ["bold"] }
"function.builtin" = "#89BEB7"
"comment" = "#A6B6CE"
"variable.builtin" = "#D4A520"
"constant" = "#D4A520"
"constant.builtin" = "#D4A520"
"string" = "#D74E50"
"constant.numeric" = "#D74E50"
"constant.character.escape" = { fg = "#D74E50", modifiers = ["bold"] }
"label" = "#D68482"
"module" = "#839A53"
# TODO
"markup.heading" = "blue"
"markup.list" = "red"
"markup.bold" = { fg = "yellow", modifiers = ["bold"] }
"markup.italic" = { fg = "magenta", modifiers = ["italic"] }
"markup.link.url" = { fg = "yellow", modifiers = ["underlined"] }
"markup.link.text" = "red"
"markup.quote" = "cyan"
"markup.raw" = "green"
"diff.plus" = "#839A53"
"diff.delta" = "#D4A520"
"diff.minus" = "#D74E50"
"ui.background" = { bg = "#FFFCFD" }
"ui.linenr" = { fg = "#bbbbbb" }
"ui.linenr.selected" = { fg = "#ED5466", modifiers = ["bold"] }
"ui.cursorline" = { bg = "#F3EAE9" }
"ui.statusline" = { fg = "#250E07", bg = "#F3EAE9" }
"ui.statusline.inactive" = { fg = "#7b91b3", bg = "#F3EAE9" }
"ui.popup" = { fg = "#7B91b3", bg = "#F3E8E9" }
"ui.window" = { bg = "#D8B8B3" }
"ui.help" = { bg = "#D8B8B3", fg = "#250E07" }
"ui.text" = { fg = "#7B91B3" }
"ui.text.focus" = { fg = "#250E07", modifiers= ["bold"] }
"ui.virtual.whitespace" = "#A6B6CE"
"ui.virtual.ruler" = { bg = "#F3EAE9" }
"ui.selection" = { bg = "#F3EAE9" }
"ui.cursor.primary" = { bg = "#ED5466", fg = "#FFFCFD", modifiers = ["bold"] }
"ui.cursor.match" = { bg = "#F3EAE9", fg = "#ED5466", modifiers = ["bold"] }
"ui.menu" = { fg = "#7B91B3", bg = "#F3EAE9" }
"ui.menu.selected" = { fg = "#D74E50", bg = "#F3EAE9" }
"warning" = "#D4A520"
"error" = "#D74E50"
"info" = "#839A53"
"hint" = "#A6B6CE"
"diagnostic.warning" = { underline = { color = "#D4A520", style = "curl" } }
"diagnostic.error" = { underline = { color = "#D74E50", style = "curl" } }
"diagnostic.info" = { underline = { color = "#839A53", style = "curl" } }
"diagnostic.hint" = { underline = { color = "#A6B6CE", style = "curl" } }

@ -90,6 +90,12 @@
"diagnostic.info" = { underline = { color = "#75beff", style = "curl" } }
"diagnostic.hint" = { underline = { color = "#eeeeeb3", style = "curl" } }
"ui.explorer.file" = { fg = "text" }
"ui.explorer.dir" = { fg = "fn_declaration" }
"ui.explorer.exe" = { fg = "text" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "#75715e" }
[palette]
type = "#A6E22E"
keyword = "#F92672"

@ -103,6 +103,12 @@
"markup.link.text" = "yellow"
"markup.quote" = "green"
"ui.explorer.file" = { fg = "base8" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "base8" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "base4" }
[palette]
# primary colors
"red" = "#ff6188"

@ -100,6 +100,12 @@
"markup.link.text" = "yellow"
"markup.quote" = "green"
"ui.explorer.file" = { fg = "base8" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "base8" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "base4" }
[palette]
# primary colors
"red" = "#ff6d7e"

@ -103,6 +103,12 @@
"markup.link.text" = "yellow"
"markup.quote" = "green"
"ui.explorer.file" = { fg = "base8" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "base8" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "base4" }
[palette]
# primary colors
"red" = "#ff657a"

@ -100,6 +100,12 @@
"markup.link.text" = "yellow"
"markup.quote" = "green"
"ui.explorer.file" = { fg = "base8" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "base8" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "base4" }
[palette]
# primary colors
"red" = "#fd6883"

@ -100,6 +100,12 @@
"markup.link.text" = "yellow"
"markup.quote" = "green"
"ui.explorer.file" = { fg = "base8" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "base8" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "base4" }
[palette]
# primary colors
"red" = "#fc618d"

@ -91,6 +91,12 @@
'diff.delta' = { fg = 'blue' }
'diff.delta.moved' = { fg = 'blue', modifiers = ['italic'] }
"ui.explorer.file" = { fg = "foreground" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "foreground" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "selection" }
[palette]
background = '#011627'
background2 = '#112630'

@ -109,6 +109,12 @@
"diff.delta" = "nord12"
"diff.minus" = "nord11"
"ui.explorer.file" = { fg = "nord6" }
"ui.explorer.dir" = { fg = "nord8" }
"ui.explorer.exe" = { fg = "nord6" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "nord2" }
[palette]
nord0 = "#2e3440"
nord1 = "#3b4252"

@ -81,6 +81,18 @@
"ui.menu.selected" = { fg = "black", bg = "blue" }
"ui.menu.scroll" = { fg = "white", bg = "light-gray" }
"ui.explorer.file" = { fg = "white" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "white" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "light-gray" }
"ui.explorer.file" = { fg = "white" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "white" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "light-gray" }
[palette]
yellow = "#E5C07B"

@ -110,6 +110,12 @@
"ui.menu" = { fg = "black", bg = "light-white" }
"ui.menu.selected" = { fg = "white", bg = "light-blue" }
"ui.explorer.file" = { fg = "black" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "black" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "light-white" }
[palette]
white = "#FAFAFA"
yellow = "#A06600"

@ -123,6 +123,12 @@ namespace = { fg = 'orangeL' }
'diff.delta' = { fg = '#4d4ddd' }
'diff.delta.moved' = { fg = '#dd4ddd' }
"ui.explorer.file" = { fg = "greyT" }
"ui.explorer.dir" = { fg = "blueL" }
"ui.explorer.exe" = { fg = "greyT" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "greyL" }
[palette]
white = '#FFFFFF'
greyH = '#CFCFCF'

@ -163,6 +163,12 @@
"diff.delta" = "highlight_high"
# "diff.delta.moved" = ""
"ui.explorer.file" = { fg = "text" }
"ui.explorer.dir" = { fg = "rose" }
"ui.explorer.exe" = { fg = "text" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "highlight" }
[palette]
base = "#191724"
surface = "#1f1d2e"

@ -6,6 +6,12 @@
inherits = "rose_pine"
"ui.explorer.file" = { fg = "text" }
"ui.explorer.dir" = { fg = "rose" }
"ui.explorer.exe" = { fg = "text" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "highlight" }
[palette]
base = "#faf4ed"
surface = "#fffaf3"

@ -76,6 +76,18 @@
"markup.quote" = { fg = "yellow", modifiers = ["italic"] }
"markup.raw" = { fg = "fg" }
"ui.explorer.file" = { fg = "fg" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "fg" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "bg3" }
"ui.explorer.file" = { fg = "fg" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "fg" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "bg3" }
[palette]
bg0 = "#323437"

@ -76,6 +76,12 @@
"markup.quote" = { fg = "yellow", modifiers = ["italic"] }
"markup.raw" = { fg = "fg" }
"ui.explorer.file" = { fg = "fg" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "fg" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "bg3" }
[palette]
bg0 = "#e1e1e3"

@ -107,6 +107,12 @@
"diagnostic.info" = { underline = { style = "curl", color = "blue" } }
"diagnostic.hint" = { underline = { style = "curl", color = "base01" } }
"ui.explorer.file" = { fg = "base1" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "base1" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "base0175" }
[palette]
# 深色 越来越深
base03 = "#002b36"

@ -125,6 +125,12 @@
"diagnostic.hint" = { underline = { style = "curl", color = "base01" } }
"ui.explorer.file" = { fg = "base1" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "base1" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "base0175" }
[palette]
red = '#dc322f'
green = '#859900'

@ -77,6 +77,12 @@
"diagnostic.info" = { underline = { style = "curl", color = "theme_yellow" } }
"diagnostic.hint" = { underline = { style = "curl", color = "bg2" } }
"ui.explorer.file" = { fg = "fg1" }
"ui.explorer.dir" = { fg = "#715ab1" }
"ui.explorer.exe" = { fg = "fg1" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "bg3" }
[palette]
base = "#655370"
base-dim = "#a094a2"

@ -69,6 +69,12 @@
"markup.quote" = { fg = "yellow", modifiers = ["italic"] }
"markup.raw" = { fg = "cyan" }
"ui.explorer.file" = { fg = "foreground" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "foreground" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "background_highlight" }
[palette]
red = "#f7768e"
orange = "#ff9e64"

@ -2,6 +2,12 @@
inherits = "tokyonight"
"ui.explorer.file" = { fg = "foreground" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "foreground" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "background_highlight" }
[palette]
background = "#24283b"
background_highlight = "#373d5a"

@ -1,3 +1,3 @@
[toolchain]
channel = "1.61.0"
channel = "1.66.0"
components = ["rustfmt", "rust-src"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 KiB

After

Width:  |  Height:  |  Size: 271 KiB

@ -1,76 +1,76 @@
attribute = "lilac"
keyword = "almond"
"keyword.directive" = "lilac" # -- preprocessor comments (#if in C)
namespace = "lilac"
punctuation = "lavender"
"punctuation.delimiter" = "lavender"
operator = "lilac"
special = "honey"
"variable.other.member" = "white"
variable = "lavender"
# variable = "almond" # TODO: metavariables only
# "variable.parameter" = { fg = "lavender", modifiers = ["underlined"] }
"variable.parameter" = { fg = "lavender" }
"variable.builtin" = "mint"
type = "white"
"type.builtin" = "white" # TODO: distinguish?
constructor = "lilac"
function = "white"
"function.macro" = "lilac"
"function.builtin" = "white"
tag = "almond"
comment = "sirocco"
constant = "white"
"constant.builtin" = "white"
string = "silver"
"constant.numeric" = "chamois"
"constant.character.escape" = "honey"
# used for lifetimes
label = "honey"
# Author : Sam Sartor <me@samsartor.com>, Trivernis <trivernis@pm.me>
# A port of https://github.com/bceskavich/dracula-at-night
"comment" = { fg = "comment" }
"constant" = { fg = "purple" }
"constant.character.escape" = { fg = "pink" }
"function" = { fg = "green" }
"keyword" = { fg = "pink" }
"operator" = { fg = "pink" }
"special" = { fg = "yellow" }
"punctuation" = { fg = "foreground" }
"string" = { fg = "yellow" }
"string.regexp" = { fg = "red" }
"tag" = { fg = "pink" }
"attribute" = { fg = "cyan" }
"type" = { fg = "cyan", modifiers = ["italic"] }
"type.enum.variant" = { fg = "foreground", modifiers = ["italic"] }
"variable" = { fg = "foreground" }
"variable.builtin" = { fg = "cyan", modifiers = ["italic"] }
"variable.parameter" = { fg ="orange", modifiers = ["italic"] }
"markup.heading" = "lilac"
"markup.bold" = { modifiers = ["bold"] }
"markup.italic" = { modifiers = ["italic"] }
"markup.link.url" = { fg = "silver", modifiers = ["underlined"] }
"markup.link.text" = "almond"
"markup.raw" = "almond"
"diff.plus" = { fg = "green" }
"diff.delta" = { fg = "orange" }
"diff.minus" = { fg = "red" }
"diff.plus" = "#35bf86"
"diff.minus" = "#f22c86"
"diff.delta" = "#6f44f0"
"ui.background" = { fg = "foreground", bg = "background" }
"ui.cursor" = { fg = "background", bg = "orange", modifiers = ["dim"] }
"ui.cursor.match" = { fg = "green", modifiers = ["underlined"] }
"ui.cursor.primary" = { fg = "background", bg = "cyan", modifier = ["dim"] }
"ui.cursorline" = {bg = "background_dark"}
"ui.help" = { fg = "foreground", bg = "background_dark" }
"ui.linenr" = { fg = "comment" }
"ui.linenr.selected" = { fg = "foreground" }
"ui.menu" = { fg = "foreground", bg = "background_dark" }
"ui.menu.selected" = { fg = "cyan", bg = "background_dark" }
"ui.popup" = { fg = "foreground", bg = "background_dark" }
"ui.selection" = { fg = "background", bg = "purple", modifiers = ["dim"] }
"ui.selection.primary" = { fg = "background", bg = "pink" }
"ui.text" = { fg = "foreground" }
"ui.text.focus" = { fg = "cyan" }
"ui.window" = { fg = "foreground" }
"ui.virtual.ruler" = { bg = "ruler" }
"ui.virtual.indent-guide" = { fg = "ruler" }
# TODO: diferentiate doc comment
# concat (ERROR) @error.syntax and "MISSING ;" selectors for errors
"ui.statusline" = { fg = "foreground", bg = "background_dark" }
"ui.statusline.inactive" = { fg = "comment", bg = "background_dark" }
"ui.statusline.normal" = { fg = "background_dark", bg = "purple"}
"ui.statusline.insert" = { fg = "background_dark", bg = "pink"}
"ui.statusline.select" = { fg = "background_dark", bg = "cyan"}
"ui.background" = { bg = "midnight" }
"ui.background.separator" = { fg = "comet" }
"ui.linenr" = { fg = "comet" }
"ui.linenr.selected" = { fg = "lilac" }
"ui.statusline" = { fg = "lilac", bg = "revolver" }
"ui.statusline.inactive" = { fg = "lavender", bg = "revolver" }
"ui.popup" = { bg = "revolver" }
"ui.window" = { fg = "bossanova" }
"ui.help" = { bg = "#7958DC", fg = "#171452" }
"error" = { fg = "red" }
"warning" = { fg = "cyan" }
"ui.text" = { fg = "lavender" }
"ui.text.focus" = { fg = "white" }
"ui.text.inactive" = "sirocco"
"ui.virtual" = { fg = "comet" }
"markup.heading" = { fg = "purple", modifiers = ["bold"] }
"markup.list" = "cyan"
"markup.bold" = { fg = "orange", modifiers = ["bold"] }
"markup.italic" = { fg = "yellow", modifiers = ["italic"] }
"markup.link.url" = "cyan"
"markup.link.text" = "pink"
"markup.quote" = { fg = "yellow", modifiers = ["italic"] }
"markup.raw" = { fg = "foreground" }
"ui.virtual.indent-guide" = { fg = "comet" }
"ui.explorer.file" = { fg = "foreground" }
"ui.explorer.dir" = { fg = "cyan" }
"ui.explorer.exe" = { fg = "foreground" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "comment" }
"ui.selection" = { bg = "#540099" }
"ui.selection.primary" = { bg = "#540099" }
# TODO: namespace ui.cursor as ui.selection.cursor?
rainbow = ["#7c5ea3", "#9c5b95", "#9c5e80", "#6b4466"]
"ui.cursor.select" = { bg = "delta" }
"ui.cursor.insert" = { bg = "white" }
"ui.cursor.match" = { fg = "#212121", bg = "#6C6999" }
"ui.cursor" = { modifiers = ["reversed"] }
"ui.cursorline.primary" = { bg = "bossanova" }
"ui.highlight" = { bg = "bossanova" }
"ui.menu" = { fg = "lavender", bg = "revolver" }
"ui.menu.selected" = { fg = "revolver", bg = "white" }
"ui.menu.scroll" = { fg = "lavender", bg = "comet" }
"diagnostic.hint" = { underline = { color = "silver", style = "curl" } }
@ -78,27 +78,19 @@ label = "honey"
"diagnostic.warning" = { underline = { color = "lightning", style = "curl" } }
"diagnostic.error" = { underline = { color = "apricot", style = "curl" } }
warning = "lightning"
error = "apricot"
info = "delta"
hint = "silver"
[palette]
white = "#ffffff"
lilac = "#dbbfef"
lavender = "#a4a0e8"
comet = "#5a5977"
bossanova = "#452859"
midnight = "#3b224c"
revolver = "#281733"
silver = "#cccccc"
sirocco = "#697C81"
mint = "#9ff28f"
almond = "#eccdba"
chamois = "#E8DCA0"
honey = "#efba5d"
apricot = "#f47868"
lightning = "#ffcd1c"
delta = "#6F44F0"
background = "#3A2A4D"
background_dark = "#2B1C3D"
foreground = "#f8f8f2"
ruler = "#453254"
comment = "#886C9C"
red = "#ff5555"
orange = "#ffb86c"
yellow = "#f1fa8c"
green = "#50fa7b"
purple = "#bd93f9"
cyan = "#8be9fd"
pink = "#ff79c6"

@ -10,4 +10,4 @@ helix-term = { version = "0.6", path = "../helix-term" }
helix-core = { version = "0.6", path = "../helix-core" }
helix-view = { version = "0.6", path = "../helix-view" }
helix-loader = { version = "0.6", path = "../helix-loader" }
toml = "0.5"
toml = "0.5.10"

Loading…
Cancel
Save