on 5b1a628 help sign in
.cargo/confignew file+2
since splitsnapshots
unifiedsplit
@@ -0,0 +1,2 @@
1+[alias]
2+xtask = "run --package xtask --"
.cargo/config.tomldeleted−3
@@ -1,3 +0,0 @@
1−[alias]
2−xtask = "run --package xtask --"
3−integration-test = "test --features integration --profile integration --workspace --test integration"
.envrc−2
@@ -1,7 +1,5 @@
1watch_file shell.nix
1watch_file shell.nix
2watch_file flake.lock
2watch_file flake.lock
3−watch_file rust-toolchain.toml
4
3
5# try to use flakes, if it fails use normal nix (ie. shell.nix)
4# try to use flakes, if it fails use normal nix (ie. shell.nix)
6use flake || use nix
5use flake || use nix
7−eval "$shellHook"
.gitattributesdeleted−11
@@ -1,11 +0,0 @@
1−# Auto detect text files and perform normalization
2−* text=auto
3−
4−*.rs text diff=rust
5−*.toml text diff=toml
6−
7−*.scm text diff=scheme
8−*.md text diff=markdown
9−
10−book/theme/highlight.js linguist-vendored
11−Cargo.lock text
.github/FUNDING.ymldeleted−1
@@ -1 +0,0 @@
1−open_collective: helix-editor
.github/ISSUE_TEMPLATE/bug_report.mdnew file+28
@@ -0,0 +1,28 @@
1+---
2+name: Bug report
3+about: Create a report to help us improve
4+title: ''
5+labels: C-bug
6+assignees: ''
7+
8+---
9+
10+<!-- Your issue may already be reported!
11+Please search on the issue tracker before creating one. -->
12+
13+### Reproduction steps
14+
15+<!-- Ideally provide a key sequence and/or asciinema.org recording. -->
16+
17+### Environment
18+
19+- Platform: <!-- macOS / Windows / Linux -->
20+- Helix version: <!-- 'hx -V' if using a release, 'git describe' if building from master -->
21+
22+<details><summary>~/.cache/helix/helix.log</summary>
23+
24+```
25+please provide a copy of `~/.cache/helix/helix.log` here if possible, you may need to redact some of the lines
26+```
27+
28+</details>
.github/ISSUE_TEMPLATE/bug_report.yamldeleted−78
@@ -1,78 +0,0 @@
1−name: Bug Report
2−description: Create a report to help us improve
3−labels: C-bug
4−body:
5− - type: markdown
6− attributes:
7− value: Thank you for filing a bug report! 🐛
8− - type: textarea
9− id: problem
10− attributes:
11− label: Summary
12− description: >
13− Please provide a short summary of the bug, along with any information
14− you feel relevant to replicate the bug.
15− validations:
16− required: true
17− - type: textarea
18− id: reproduction-steps
19− attributes:
20− label: Reproduction Steps
21− value: |
22− <!-- Ideally provide a key sequence and/or asciinema.org recording. -->
23−
24− I tried this:
25−
26− 1. `hx`
27−
28− I expected this to happen:
29−
30− Instead, this happened:
31− - type: textarea
32− id: helix-log
33− attributes:
34− label: Helix log
35− description: See `hx -h` for log file path. If you can reproduce the issue run `RUST_BACKTRACE=1 hx -vv` to generate a more detailed log file.
36− value: |
37− <details><summary>~/.cache/helix/helix.log</summary>
38−
39− ```
40− please provide a copy of `~/.cache/helix/helix.log` here if possible, you may need to redact some of the lines
41− ```
42−
43− </details>
44− - type: input
45− id: platform
46− attributes:
47− label: Platform
48− placeholder: Linux / macOS / Windows
49− validations:
50− required: true
51− - type: input
52− id: terminal-emulator
53− attributes:
54− label: Terminal Emulator
55− placeholder: wezterm 20220101-133340-7edc5b5a
56− validations:
57− required: true
58− - type: input
59− id: installation-method
60− attributes:
61− label: Installation Method
62− description: >
63− How you installed Helix - from a package manager like Homebrew or the
64− AUR, built from source, downloaded a binary from the releases page, etc.
65− placeholder: "source / brew / nixpkgs / flake / releases page"
66− validations:
67− required: true
68− - type: input
69− id: helix-version
70− attributes:
71− label: Helix Version
72− description: >
73− Helix version (`hx -V` if using a release, `git describe` if building
74− from master).
75− **Make sure that you are using the [latest helix release](https://github.com/helix-editor/helix/releases) or a newer master build**
76− placeholder: "helix 22.12 (5eaa6d97)"
77− validations:
78− required: true
.github/ISSUE_TEMPLATE/enhancement.mddeleted−13
@@ -1,13 +0,0 @@
1−---
2−name: Enhancement
3−about: Suggest an improvement
4−title: ''
5−labels: C-enhancement
6−assignees: ''
7−---
8−
9−<!--
10−Your enhancement may already be reported!
11−Please search on the issue tracker before creating a new issue.
12−If this is an idea for a feature, please open an "Idea" Discussion instead.
13−-->
.github/ISSUE_TEMPLATE/feature_request.mdnew file+13
@@ -0,0 +1,13 @@
1+---
2+name: Feature request
3+about: Suggest a new feature or improvement
4+title: ''
5+labels: C-enhancement
6+assignees: ''
7+---
8+
9+<!-- Your feature may already be reported!
10+Please search on the issue tracker before creating one. -->
11+
12+#### Describe your feature request
13+
.github/workflows/build.yml+110−41
@@ -4,110 +4,179 @@ on:
4 push:
4 push:
5 branches:
5 branches:
6 - master
6 - master
7− merge_group:
8 schedule:
7 schedule:
9 - cron: '00 01 * * *'
8 - cron: '00 01 * * *'
10
9
11jobs:
10jobs:
12 check:
11 check:
13− name: Check (msrv)
12+ name: Check
14 runs-on: ubuntu-latest
13 runs-on: ubuntu-latest
15 steps:
14 steps:
16 - name: Checkout sources
15 - name: Checkout sources
17− uses: actions/checkout@v4
16+ uses: actions/checkout@v2
17+ with:
18+ submodules: true
19+
18 - name: Install stable toolchain
20 - name: Install stable toolchain
19− uses: helix-editor/rust-toolchain@v1
21+ uses: actions-rs/toolchain@v1
20 with:
22 with:
21 profile: minimal
23 profile: minimal
24+ toolchain: stable
22 override: true
25 override: true
23
26
27+ - name: Cache cargo registry
24− - uses: Swatinem/rust-cache@v2
28+ uses: actions/cache@v2.1.7
25 with:
29 with:
26− shared-key: "build"
30+ path: ~/.cargo/registry
31+ key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
32+
33+ - name: Cache cargo index
34+ uses: actions/cache@v2.1.7
35+ with:
36+ path: ~/.cargo/git
37+ key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }}
38+
39+ - name: Cache cargo target dir
40+ uses: actions/cache@v2.1.7
41+ with:
42+ path: target
43+ key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
27
44
28 - name: Run cargo check
45 - name: Run cargo check
46+ uses: actions-rs/cargo@v1
47+ with:
29− run: cargo check
48+ command: check
30
49
31 test:
50 test:
32 name: Test Suite
51 name: Test Suite
33 runs-on: ${{ matrix.os }}
52 runs-on: ${{ matrix.os }}
34− env:
35− RUST_BACKTRACE: 1
36− HELIX_LOG_LEVEL: info
37 steps:
53 steps:
38 - name: Checkout sources
54 - name: Checkout sources
39− uses: actions/checkout@v4
55+ uses: actions/checkout@v2
56+ with:
57+ submodules: true
40
58
41 - name: Install stable toolchain
59 - name: Install stable toolchain
42− uses: dtolnay/rust-toolchain@1.70
60+ uses: actions-rs/toolchain@v1
61+ with:
62+ profile: minimal
63+ toolchain: ${{ matrix.rust }}
64+ override: true
43
65
66+ - name: Cache cargo registry
44− - uses: Swatinem/rust-cache@v2
67+ uses: actions/cache@v2.1.7
45 with:
68 with:
46− shared-key: "build"
69+ path: ~/.cargo/registry
70+ key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
47
71
48− - name: Cache test tree-sitter grammar
72+ - name: Cache cargo index
49− uses: actions/cache@v3
73+ uses: actions/cache@v2.1.7
50 with:
74 with:
51− path: runtime/grammars
75+ path: ~/.cargo/git
52− key: ${{ runner.os }}-stable-v${{ env.CACHE_VERSION }}-tree-sitter-grammars-${{ hashFiles('languages.toml') }}
76+ key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }}
53− restore-keys: ${{ runner.os }}-stable-v${{ env.CACHE_VERSION }}-tree-sitter-grammars-
54
77
55− - name: Run cargo test
78+ - name: Cache cargo target dir
56− run: cargo test --workspace
79+ uses: actions/cache@v2.1.7
80+ with:
81+ path: target
82+ key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
57
83
58− - name: Run cargo integration-test
84+ - name: Run cargo test
59− run: cargo integration-test
85+ uses: actions-rs/cargo@v1
86+ with:
87+ command: test
60
88
61 strategy:
89 strategy:
62 matrix:
90 matrix:
63 os: [ubuntu-latest, macos-latest, windows-latest]
91 os: [ubuntu-latest, macos-latest, windows-latest]
92+ rust: [stable]
64
93
65 lints:
94 lints:
66 name: Lints
95 name: Lints
67 runs-on: ubuntu-latest
96 runs-on: ubuntu-latest
68 steps:
97 steps:
69 - name: Checkout sources
98 - name: Checkout sources
70− uses: actions/checkout@v4
99+ uses: actions/checkout@v2
100+ with:
101+ submodules: true
71
102
72 - name: Install stable toolchain
103 - name: Install stable toolchain
73− uses: dtolnay/rust-toolchain@1.70
104+ uses: actions-rs/toolchain@v1
74 with:
105 with:
106+ profile: minimal
107+ toolchain: stable
108+ override: true
75 components: rustfmt, clippy
109 components: rustfmt, clippy
76
110
77− - uses: Swatinem/rust-cache@v2
111+ - name: Cache cargo registry
112+ uses: actions/cache@v2.1.7
113+ with:
114+ path: ~/.cargo/registry
115+ key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
116+
117+ - name: Cache cargo index
118+ uses: actions/cache@v2.1.7
119+ with:
120+ path: ~/.cargo/git
121+ key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }}
122+
123+ - name: Cache cargo target dir
124+ uses: actions/cache@v2.1.7
78 with:
125 with:
79− shared-key: "build"
126+ path: target
127+ key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
80
128
81 - name: Run cargo fmt
129 - name: Run cargo fmt
130+ uses: actions-rs/cargo@v1
131+ with:
132+ command: fmt
82− run: cargo fmt --all --check
133+ args: --all -- --check
83
134
84 - name: Run cargo clippy
135 - name: Run cargo clippy
85− run: cargo clippy --workspace --all-targets -- -D warnings
136+ uses: actions-rs/cargo@v1
86−
137+ with:
87− - name: Run cargo doc
138+ command: clippy
88− run: cargo doc --no-deps --workspace --document-private-items
89− env:
90− RUSTDOCFLAGS: -D warnings
139+ args: -- -D warnings
91
140
92 docs:
141 docs:
93 name: Docs
142 name: Docs
94 runs-on: ubuntu-latest
143 runs-on: ubuntu-latest
95 steps:
144 steps:
96 - name: Checkout sources
145 - name: Checkout sources
97− uses: actions/checkout@v4
146+ uses: actions/checkout@v2
147+ with:
148+ submodules: true
98
149
99 - name: Install stable toolchain
150 - name: Install stable toolchain
100− uses: dtolnay/rust-toolchain@1.70
151+ uses: actions-rs/toolchain@v1
152+ with:
153+ profile: minimal
154+ toolchain: stable
155+ override: true
101
156
157+ - name: Cache cargo registry
102− - uses: Swatinem/rust-cache@v2
158+ uses: actions/cache@v2.1.6
103 with:
159 with:
104− shared-key: "build"
160+ path: ~/.cargo/registry
161+ key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
105
162
106− - name: Validate queries
163+ - name: Cache cargo index
107− run: cargo xtask query-check
164+ uses: actions/cache@v2.1.6
165+ with:
166+ path: ~/.cargo/git
167+ key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }}
168+
169+ - name: Cache cargo target dir
170+ uses: actions/cache@v2.1.6
171+ with:
172+ path: target
173+ key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
108
174
109 - name: Generate docs
175 - name: Generate docs
176+ uses: actions-rs/cargo@v1
177+ with:
178+ command: xtask
110− run: cargo xtask docgen
179+ args: docgen
111
180
112 - name: Check uncommitted documentation changes
181 - name: Check uncommitted documentation changes
113 run: |
182 run: |
.github/workflows/cachix.ymldeleted−26
@@ -1,26 +0,0 @@
1−# Publish the Nix flake outputs to Cachix
2−name: Cachix
3−on:
4− push:
5− branches:
6− - master
7−
8−jobs:
9− publish:
10− name: Publish Flake
11− runs-on: ubuntu-latest
12− steps:
13− - name: Checkout sources
14− uses: actions/checkout@v4
15−
16− - name: Install nix
17− uses: cachix/install-nix-action@v24
18−
19− - name: Authenticate with Cachix
20− uses: cachix/cachix-action@v13
21− with:
22− name: helix
23− authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
24−
25− - name: Build nix flake
26− run: nix build -L
.github/workflows/gh-pages.yml+2−16
@@ -4,14 +4,12 @@ on:
4 push:
4 push:
5 branches:
5 branches:
6 - master
6 - master
7− tags:
8− - '*'
9
7
10jobs:
8jobs:
11 deploy:
9 deploy:
12 runs-on: ubuntu-latest
10 runs-on: ubuntu-latest
13 steps:
11 steps:
14− - uses: actions/checkout@v4
12+ - uses: actions/checkout@v2
15
13
16 - name: Setup mdBook
14 - name: Setup mdBook
17 uses: peaceiris/actions-mdbook@v1
15 uses: peaceiris/actions-mdbook@v1
@@ -20,22 +18,10 @@ jobs:
20 # mdbook-version: '0.4.8'
18 # mdbook-version: '0.4.8'
21
19
22 - run: mdbook build book
20 - run: mdbook build book
23−
24− - name: Set output directory
25− run: |
26− OUTDIR=$(basename ${{ github.ref }})
27− echo "OUTDIR=$OUTDIR" >> $GITHUB_ENV
28−
29− - name: Deploy stable
30− uses: peaceiris/actions-gh-pages@v3
31− if: startswith(github.ref, 'refs/tags/')
32− with:
33− github_token: ${{ secrets.GITHUB_TOKEN }}
34− publish_dir: ./book/book
35
21
36 - name: Deploy
22 - name: Deploy
37 uses: peaceiris/actions-gh-pages@v3
23 uses: peaceiris/actions-gh-pages@v3
24+ if: github.ref == 'refs/heads/master'
38 with:
25 with:
39 github_token: ${{ secrets.GITHUB_TOKEN }}
26 github_token: ${{ secrets.GITHUB_TOKEN }}
40 publish_dir: ./book/book
27 publish_dir: ./book/book
41− destination_dir: ./${{ env.OUTDIR }}
.github/workflows/languages.tomldeleted−26
@@ -1,26 +0,0 @@
1−# This languages.toml is used for testing in CI.
2−
3−[[language]]
4−name = "rust"
5−scope = "source.rust"
6−injection-regex = "rust"
7−file-types = ["rs"]
8−comment-token = "//"
9−roots = ["Cargo.toml", "Cargo.lock"]
10−indent = { tab-width = 4, unit = " " }
11−
12−[[grammar]]
13−name = "rust"
14−source = { git = "https://github.com/tree-sitter/tree-sitter-rust", rev = "0431a2c60828731f27491ee9fdefe25e250ce9c9" }
15−
16−[[language]]
17−name = "nix"
18−scope = "source.nix"
19−injection-regex = "nix"
20−file-types = ["nix"]
21−shebangs = []
22−roots = []
23−comment-token = "#"
24−
25−# A grammar entry is not necessary for this language - it is only used for
26−# testing TOML merging behavior.
.github/workflows/release.yml+71−195
@@ -1,97 +1,46 @@
1name: Release
1name: Release
2on:
2on:
3+ # schedule:
4+ # - cron: '0 0 * * *' # midnight UTC
5+
3 push:
6 push:
4 tags:
7 tags:
5− - '[0-9]+.[0-9]+'
8+ - 'v[0-9]+.[0-9]+.[0-9]+'
6− - '[0-9]+.[0-9]+.[0-9]+'
9+ ## - release
7− branches:
8− - 'patch/ci-release-*'
9− pull_request:
10− paths:
11− - '.github/workflows/release.yml'
12−
13−env:
14− # Preview mode: Publishes the build output as a CI artifact instead of creating
15− # a release, allowing for manual inspection of the output. This mode is
16− # activated if the CI run was triggered by events other than pushed tags, or
17− # if the repository is a fork.
18− preview: ${{ !startsWith(github.ref, 'refs/tags/') || github.repository != 'helix-editor/helix' }}
19
10
20jobs:
11jobs:
21− fetch-grammars:
22− name: Fetch Grammars
23− runs-on: ubuntu-latest
24− steps:
25− - name: Checkout sources
26− uses: actions/checkout@v4
27−
28− - name: Install stable toolchain
29− uses: dtolnay/rust-toolchain@stable
30−
31− - uses: Swatinem/rust-cache@v2
32−
33− - name: Fetch tree-sitter grammars
34− run: cargo run --package=helix-loader --bin=hx-loader
35−
36− - name: Bundle grammars
37− run: tar cJf grammars.tar.xz -C runtime/grammars/sources .
38−
39− - uses: actions/upload-artifact@v4
40− with:
41− name: grammars
42− path: grammars.tar.xz
43−
44 dist:
12 dist:
45 name: Dist
13 name: Dist
46− needs: [fetch-grammars]
47− env:
48− # For some builds, we use cross to test on 32-bit and big-endian
49− # systems.
50− CARGO: cargo
51− # When CARGO is set to CROSS, this is set to `--target matrix.target`.
52− TARGET_FLAGS:
53− # When CARGO is set to CROSS, TARGET_DIR includes matrix.target.
54− TARGET_DIR: ./target
55− # Emit backtraces on panics.
56− RUST_BACKTRACE: 1
57 runs-on: ${{ matrix.os }}
14 runs-on: ${{ matrix.os }}
58 strategy:
15 strategy:
59 fail-fast: false # don't fail other jobs if one fails
16 fail-fast: false # don't fail other jobs if one fails
60 matrix:
17 matrix:
61− build: [x86_64-linux, x86_64-macos, x86_64-windows] #, x86_64-win-gnu, win32-msvc
18+ build: [x86_64-linux, aarch64-linux, x86_64-macos, x86_64-windows] #, x86_64-win-gnu, win32-msvc
62 include:
19 include:
63 - build: x86_64-linux
20 - build: x86_64-linux
64− os: ubuntu-latest
21+ os: ubuntu-20.04
65 rust: stable
22 rust: stable
66 target: x86_64-unknown-linux-gnu
23 target: x86_64-unknown-linux-gnu
67 cross: false
24 cross: false
68 - build: aarch64-linux
25 - build: aarch64-linux
69− os: ubuntu-latest
26+ os: ubuntu-20.04
70 rust: stable
27 rust: stable
71 target: aarch64-unknown-linux-gnu
28 target: aarch64-unknown-linux-gnu
72 cross: true
29 cross: true
73− # - build: riscv64-linux
74− # os: ubuntu-latest
75− # rust: stable
76− # target: riscv64gc-unknown-linux-gnu
77− # cross: true
78 - build: x86_64-macos
30 - build: x86_64-macos
79 os: macos-latest
31 os: macos-latest
80 rust: stable
32 rust: stable
81 target: x86_64-apple-darwin
33 target: x86_64-apple-darwin
82 cross: false
34 cross: false
83 - build: x86_64-windows
35 - build: x86_64-windows
84− os: windows-latest
36+ os: windows-2019
85 rust: stable
37 rust: stable
86 target: x86_64-pc-windows-msvc
38 target: x86_64-pc-windows-msvc
87 cross: false
39 cross: false
88− # 23.03: build issues
89− - build: aarch64-macos
40+ # - build: aarch64-macos
90− os: macos-latest
41+ # os: macos-latest
91− rust: stable
42+ # rust: stable
92− target: aarch64-apple-darwin
43+ # target: aarch64-apple-darwin
93− cross: false
94− skip_tests: true # x86_64 host can't run aarch64 code
95 # - build: x86_64-win-gnu
44 # - build: x86_64-win-gnu
96 # os: windows-2019
45 # os: windows-2019
97 # rust: stable-x86_64-gnu
46 # rust: stable-x86_64-gnu
@@ -103,124 +52,57 @@ jobs:
103
52
104 steps:
53 steps:
105 - name: Checkout sources
54 - name: Checkout sources
106− uses: actions/checkout@v4
55+ uses: actions/checkout@v2
107−
56+ with:
108− - name: Download grammars
57+ submodules: true
109− uses: actions/download-artifact@v4
110−
111− - name: Move grammars under runtime
112− if: "!startsWith(matrix.os, 'windows')"
113− run: |
114− mkdir -p runtime/grammars/sources
115− tar xJf grammars/grammars.tar.xz -C runtime/grammars/sources
116−
117− # The rust-toolchain action ignores rust-toolchain.toml files.
118− # Removing this before building with cargo ensures that the rust-toolchain
119− # is considered the same between installation and usage.
120− - name: Remove the rust-toolchain.toml file
121− run: rm rust-toolchain.toml
122
58
123 - name: Install ${{ matrix.rust }} toolchain
59 - name: Install ${{ matrix.rust }} toolchain
124− uses: dtolnay/rust-toolchain@master
60+ uses: actions-rs/toolchain@v1
125 with:
61 with:
62+ profile: minimal
126 toolchain: ${{ matrix.rust }}
63 toolchain: ${{ matrix.rust }}
127 target: ${{ matrix.target }}
64 target: ${{ matrix.target }}
128−
65+ override: true
129− # Install a pre-release version of Cross
130− # TODO: We need to pre-install Cross because we need cross-rs/cross#591 to
131− # get a newer C++ compiler toolchain. Remove this step when Cross
132− # 0.3.0, which includes cross-rs/cross#591, is released.
133− - name: Install Cross
134− if: "matrix.cross"
135− run: |
136− cargo install cross --git https://github.com/cross-rs/cross.git --rev 47df5c76e7cba682823a0b6aa6d95c17b31ba63a
137− echo "CARGO=cross" >> $GITHUB_ENV
138− # echo "TARGET_FLAGS=--target ${{ matrix.target }}" >> $GITHUB_ENV
139− # echo "TARGET_DIR=./target/${{ matrix.target }}" >> $GITHUB_ENV
140−
141− - name: Show command used for Cargo
142− run: |
143− echo "cargo command is: ${{ env.CARGO }}"
144− echo "target flag is: ${{ env.TARGET_FLAGS }}"
145
66
146 - name: Run cargo test
67 - name: Run cargo test
147− if: "!matrix.skip_tests"
68+ uses: actions-rs/cargo@v1
69+ with:
70+ use-cross: ${{ matrix.cross }}
71+ command: test
148− run: ${{ env.CARGO }} test --release --locked --target ${{ matrix.target }} --workspace
72+ args: --release --locked --target ${{ matrix.target }}
149−
150− - name: Set profile.release.strip = true
151− shell: bash
152− run: |
153− cat >> .cargo/config.toml <<EOF
154− [profile.release]
155− strip = true
156− EOF
157
73
158 - name: Build release binary
74 - name: Build release binary
159− run: ${{ env.CARGO }} build --release --locked --target ${{ matrix.target }}
75+ uses: actions-rs/cargo@v1
160−
76+ with:
161− - name: Build AppImage
77+ use-cross: ${{ matrix.cross }}
162− shell: bash
78+ command: build
163− if: matrix.build == 'x86_64-linux'
79+ args: --release --locked --target ${{ matrix.target }}
164− run: |
165− # Required as of 22.x https://github.com/AppImage/AppImageKit/wiki/FUSE
166− sudo add-apt-repository universe
167− sudo apt install libfuse2
168−
169− mkdir dist
170−
171− name=dev
172− if [[ $GITHUB_REF == refs/tags/* ]]; then
173− name=${GITHUB_REF:10}
174− fi
175−
176− build="${{ matrix.build }}"
177−
178− export VERSION="$name"
179− export ARCH=${build%-linux}
180− export APP=helix
181− export OUTPUT="helix-$VERSION-$ARCH.AppImage"
182− export UPDATE_INFORMATION="gh-releases-zsync|$GITHUB_REPOSITORY_OWNER|helix|latest|$APP-*-$ARCH.AppImage.zsync"
183−
184− mkdir -p "$APP.AppDir"/usr/{bin,lib/helix}
185−
186− cp "target/${{ matrix.target }}/release/hx" "$APP.AppDir/usr/bin/hx"
187− rm -rf runtime/grammars/sources
188− cp -r runtime "$APP.AppDir/usr/lib/helix/runtime"
189−
190− cat << 'EOF' > "$APP.AppDir/AppRun"
191− #!/bin/sh
192−
193− APPDIR="$(dirname "$(readlink -f "${0}")")"
194− HELIX_RUNTIME="$APPDIR/usr/lib/helix/runtime" exec "$APPDIR/usr/bin/hx" "$@"
195− EOF
196− chmod 755 "$APP.AppDir/AppRun"
197−
198− curl -Lo linuxdeploy-x86_64.AppImage \
199− https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
200− chmod +x linuxdeploy-x86_64.AppImage
201
80
202− ./linuxdeploy-x86_64.AppImage \
81+ - name: Strip release binary (linux and macos)
203− --appdir "$APP.AppDir" -d contrib/Helix.desktop \
82+ if: matrix.build == 'x86_64-linux' || matrix.build == 'x86_64-macos'
204− -i contrib/helix.png --output appimage
83+ run: strip "target/${{ matrix.target }}/release/hx"
205
84
206− mv "$APP-$VERSION-$ARCH.AppImage" \
85+ - name: Strip release binary (arm)
207− "$APP-$VERSION-$ARCH.AppImage.zsync" dist
86+ if: matrix.build == 'aarch64-linux'
87+ run: |
88+ docker run --rm -v \
89+ "$PWD/target:/target:Z" \
90+ rustembedded/cross:${{ matrix.target }} \
91+ aarch64-linux-gnu-strip \
92+ /target/${{ matrix.target }}/release/hx
208
93
209 - name: Build archive
94 - name: Build archive
210 shell: bash
95 shell: bash
211 run: |
96 run: |
212− mkdir -p dist
97+ mkdir dist
213 if [ "${{ matrix.os }}" = "windows-2019" ]; then
98 if [ "${{ matrix.os }}" = "windows-2019" ]; then
214 cp "target/${{ matrix.target }}/release/hx.exe" "dist/"
99 cp "target/${{ matrix.target }}/release/hx.exe" "dist/"
215 else
100 else
216 cp "target/${{ matrix.target }}/release/hx" "dist/"
101 cp "target/${{ matrix.target }}/release/hx" "dist/"
217 fi
102 fi
218− if [ -d runtime/grammars/sources ]; then
219− rm -rf runtime/grammars/sources
220− fi
221 cp -r runtime dist
103 cp -r runtime dist
222
104
223− - uses: actions/upload-artifact@v4
105+ - uses: actions/upload-artifact@v2.3.1
224 with:
106 with:
225 name: bins-${{ matrix.build }}
107 name: bins-${{ matrix.build }}
226 path: dist
108 path: dist
@@ -231,22 +113,33 @@ jobs:
231 runs-on: ubuntu-latest
113 runs-on: ubuntu-latest
232 steps:
114 steps:
233 - name: Checkout sources
115 - name: Checkout sources
234− uses: actions/checkout@v4
116+ uses: actions/checkout@v2
117+ with:
118+ submodules: false
235
119
236− - uses: actions/download-artifact@v4
120+ - uses: actions/download-artifact@v2
121+ # with:
122+ # path: dist
123+ # - run: ls -al ./dist
124+ - run: ls -al bins-*
125+
126+ - name: Calculate tag name
127+ run: |
128+ name=dev
129+ if [[ $GITHUB_REF == refs/tags/v* ]]; then
130+ name=${GITHUB_REF:10}
131+ fi
132+ echo ::set-output name=val::$name
133+ echo TAG=$name >> $GITHUB_ENV
134+ id: tagname
237
135
238 - name: Build archive
136 - name: Build archive
239 shell: bash
137 shell: bash
240 run: |
138 run: |
241 set -ex
139 set -ex
242
140
243− source="$(pwd)"
244− mkdir -p runtime/grammars/sources
245− tar xJf grammars/grammars.tar.xz -C runtime/grammars/sources
246− rm -rf grammars
141+ rm -rf tmp
247−
142+ mkdir tmp
248− cd "$(mktemp -d)"
249− mv $source/bins-* .
250 mkdir dist
143 mkdir dist
251
144
252 for dir in bins-* ; do
145 for dir in bins-* ; do
@@ -254,42 +147,25 @@ jobs:
254 if [[ $platform =~ "windows" ]]; then
147 if [[ $platform =~ "windows" ]]; then
255 exe=".exe"
148 exe=".exe"
256 fi
149 fi
257− pkgname=helix-$GITHUB_REF_NAME-$platform
150+ pkgname=helix-$TAG-$platform
258− mkdir -p $pkgname
151+ mkdir tmp/$pkgname
259− cp $source/LICENSE $source/README.md $pkgname
152+ cp LICENSE README.md tmp/$pkgname
260− mkdir $pkgname/contrib
261− cp -r $source/contrib/completion $pkgname/contrib
262− mv bins-$platform/runtime $pkgname/
153+ mv bins-$platform/runtime tmp/$pkgname/
263− mv bins-$platform/hx$exe $pkgname
154+ mv bins-$platform/hx$exe tmp/$pkgname
264− chmod +x $pkgname/hx$exe
155+ chmod +x tmp/$pkgname/hx$exe
265−
266− if [[ "$platform" = "x86_64-linux" ]]; then
267− mv bins-$platform/helix-*.AppImage* dist/
268− fi
269
156
270 if [ "$exe" = "" ]; then
157 if [ "$exe" = "" ]; then
271− tar cJf dist/$pkgname.tar.xz $pkgname
158+ tar cJf dist/$pkgname.tar.xz -C tmp $pkgname
272 else
159 else
273− 7z a -r dist/$pkgname.zip $pkgname
160+ (cd tmp && 7z a -r ../dist/$pkgname.zip $pkgname)
274 fi
161 fi
275 done
162 done
276
163
277− tar cJf dist/helix-$GITHUB_REF_NAME-source.tar.xz -C $source .
278− mv dist $source/
279−
280 - name: Upload binaries to release
164 - name: Upload binaries to release
281 uses: svenstaro/upload-release-action@v2
165 uses: svenstaro/upload-release-action@v2
282− if: env.preview == 'false'
283 with:
166 with:
284 repo_token: ${{ secrets.GITHUB_TOKEN }}
167 repo_token: ${{ secrets.GITHUB_TOKEN }}
285 file: dist/*
168 file: dist/*
286 file_glob: true
169 file_glob: true
287− tag: ${{ github.ref_name }}
170+ tag: ${{ steps.tagname.outputs.val }}
288 overwrite: true
171 overwrite: true
289−
290− - name: Upload binaries as artifact
291− uses: actions/upload-artifact@v4
292− if: env.preview == 'true'
293− with:
294− name: release
295− path: dist/*
.gitignore+1
@@ -1,5 +1,6 @@
1target
1target
2.direnv
2.direnv
3helix-term/rustfmt.toml
3helix-term/rustfmt.toml
4+helix-syntax/languages/
4result
5result
5runtime/grammars
6runtime/grammars
.gitmodulesnew file+192
@@ -0,0 +1,192 @@
1+[submodule "helix-syntax/languages/tree-sitter-cpp"]
2+ path = helix-syntax/languages/tree-sitter-cpp
3+ url = https://github.com/tree-sitter/tree-sitter-cpp
4+ shallow = true
5+[submodule "helix-syntax/languages/tree-sitter-javascript"]
6+ path = helix-syntax/languages/tree-sitter-javascript
7+ url = https://github.com/tree-sitter/tree-sitter-javascript
8+ shallow = true
9+[submodule "helix-syntax/languages/tree-sitter-julia"]
10+ path = helix-syntax/languages/tree-sitter-julia
11+ url = https://github.com/tree-sitter/tree-sitter-julia
12+ shallow = true
13+[submodule "helix-syntax/languages/tree-sitter-python"]
14+ path = helix-syntax/languages/tree-sitter-python
15+ url = https://github.com/tree-sitter/tree-sitter-python
16+ shallow = true
17+[submodule "helix-syntax/languages/tree-sitter-typescript"]
18+ path = helix-syntax/languages/tree-sitter-typescript
19+ url = https://github.com/tree-sitter/tree-sitter-typescript
20+ shallow = true
21+[submodule "helix-syntax/languages/tree-sitter-agda"]
22+ path = helix-syntax/languages/tree-sitter-agda
23+ url = https://github.com/tree-sitter/tree-sitter-agda
24+ shallow = true
25+[submodule "helix-syntax/languages/tree-sitter-go"]
26+ path = helix-syntax/languages/tree-sitter-go
27+ url = https://github.com/tree-sitter/tree-sitter-go
28+ shallow = true
29+[submodule "helix-syntax/languages/tree-sitter-ruby"]
30+ path = helix-syntax/languages/tree-sitter-ruby
31+ url = https://github.com/tree-sitter/tree-sitter-ruby
32+ shallow = true
33+[submodule "helix-syntax/languages/tree-sitter-java"]
34+ path = helix-syntax/languages/tree-sitter-java
35+ url = https://github.com/tree-sitter/tree-sitter-java
36+ shallow = true
37+[submodule "helix-syntax/languages/tree-sitter-php"]
38+ path = helix-syntax/languages/tree-sitter-php
39+ url = https://github.com/tree-sitter/tree-sitter-php
40+ shallow = true
41+[submodule "helix-syntax/languages/tree-sitter-html"]
42+ path = helix-syntax/languages/tree-sitter-html
43+ url = https://github.com/tree-sitter/tree-sitter-html
44+ shallow = true
45+[submodule "helix-syntax/languages/tree-sitter-scala"]
46+ path = helix-syntax/languages/tree-sitter-scala
47+ url = https://github.com/tree-sitter/tree-sitter-scala
48+ shallow = true
49+[submodule "helix-syntax/languages/tree-sitter-bash"]
50+ path = helix-syntax/languages/tree-sitter-bash
51+ url = https://github.com/tree-sitter/tree-sitter-bash
52+ shallow = true
53+[submodule "helix-syntax/languages/tree-sitter-rust"]
54+ path = helix-syntax/languages/tree-sitter-rust
55+ url = https://github.com/tree-sitter/tree-sitter-rust
56+ shallow = true
57+[submodule "helix-syntax/languages/tree-sitter-json"]
58+ path = helix-syntax/languages/tree-sitter-json
59+ url = https://github.com/tree-sitter/tree-sitter-json
60+ shallow = true
61+[submodule "helix-syntax/languages/tree-sitter-css"]
62+ path = helix-syntax/languages/tree-sitter-css
63+ url = https://github.com/tree-sitter/tree-sitter-css
64+ shallow = true
65+[submodule "helix-syntax/languages/tree-sitter-c-sharp"]
66+ path = helix-syntax/languages/tree-sitter-c-sharp
67+ url = https://github.com/tree-sitter/tree-sitter-c-sharp
68+ shallow = true
69+[submodule "helix-syntax/languages/tree-sitter-c"]
70+ path = helix-syntax/languages/tree-sitter-c
71+ url = https://github.com/tree-sitter/tree-sitter-c
72+ shallow = true
73+[submodule "helix-syntax/languages/tree-sitter-haskell"]
74+ path = helix-syntax/languages/tree-sitter-haskell
75+ url = https://github.com/tree-sitter/tree-sitter-haskell
76+ shallow = true
77+[submodule "helix-syntax/languages/tree-sitter-swift"]
78+ path = helix-syntax/languages/tree-sitter-swift
79+ url = https://github.com/tree-sitter/tree-sitter-swift
80+ shallow = true
81+[submodule "helix-syntax/languages/tree-sitter-toml"]
82+ path = helix-syntax/languages/tree-sitter-toml
83+ url = https://github.com/ikatyang/tree-sitter-toml
84+ shallow = true
85+[submodule "helix-syntax/languages/tree-sitter-elixir"]
86+ path = helix-syntax/languages/tree-sitter-elixir
87+ url = https://github.com/elixir-lang/tree-sitter-elixir
88+ shallow = true
89+[submodule "helix-syntax/languages/tree-sitter-nix"]
90+ path = helix-syntax/languages/tree-sitter-nix
91+ url = https://github.com/cstrahan/tree-sitter-nix
92+ shallow = true
93+[submodule "helix-syntax/languages/tree-sitter-latex"]
94+ path = helix-syntax/languages/tree-sitter-latex
95+ url = https://github.com/latex-lsp/tree-sitter-latex
96+ shallow = true
97+[submodule "helix-syntax/languages/tree-sitter-ledger"]
98+ path = helix-syntax/languages/tree-sitter-ledger
99+ url = https://github.com/cbarrete/tree-sitter-ledger
100+ shallow = true
101+[submodule "helix-syntax/languages/tree-sitter-protobuf"]
102+ path = helix-syntax/languages/tree-sitter-protobuf
103+ url = https://github.com/yusdacra/tree-sitter-protobuf.git
104+ shallow = true
105+[submodule "helix-syntax/languages/tree-sitter-ocaml"]
106+ path = helix-syntax/languages/tree-sitter-ocaml
107+ url = https://github.com/tree-sitter/tree-sitter-ocaml
108+ shallow = true
109+[submodule "helix-syntax/languages/tree-sitter-lua"]
110+ path = helix-syntax/languages/tree-sitter-lua
111+ url = https://github.com/nvim-treesitter/tree-sitter-lua
112+ shallow = true
113+[submodule "helix-syntax/languages/tree-sitter-yaml"]
114+ path = helix-syntax/languages/tree-sitter-yaml
115+ url = https://github.com/ikatyang/tree-sitter-yaml
116+ shallow = true
117+[submodule "helix-syntax/languages/tree-sitter-zig"]
118+ path = helix-syntax/languages/tree-sitter-zig
119+ url = https://github.com/maxxnino/tree-sitter-zig
120+ shallow = true
121+[submodule "helix-syntax/languages/tree-sitter-svelte"]
122+ path = helix-syntax/languages/tree-sitter-svelte
123+ url = https://github.com/Himujjal/tree-sitter-svelte
124+ shallow = true
125+[submodule "helix-syntax/languages/tree-sitter-vue"]
126+ path = helix-syntax/languages/tree-sitter-vue
127+ url = https://github.com/ikatyang/tree-sitter-vue
128+ shallow = true
129+[submodule "helix-syntax/languages/tree-sitter-tsq"]
130+ path = helix-syntax/languages/tree-sitter-tsq
131+ url = https://github.com/tree-sitter/tree-sitter-tsq
132+ shallow = true
133+[submodule "helix-syntax/languages/tree-sitter-cmake"]
134+ path = helix-syntax/languages/tree-sitter-cmake
135+ url = https://github.com/uyha/tree-sitter-cmake
136+ shallow = true
137+[submodule "helix-syntax/languages/tree-sitter-glsl"]
138+ path = helix-syntax/languages/tree-sitter-glsl
139+ url = https://github.com/theHamsta/tree-sitter-glsl.git
140+ shallow = true
141+[submodule "helix-syntax/languages/tree-sitter-perl"]
142+ path = helix-syntax/languages/tree-sitter-perl
143+ url = https://github.com/ganezdragon/tree-sitter-perl
144+ shallow = true
145+[submodule "helix-syntax/languages/tree-sitter-comment"]
146+ path = helix-syntax/languages/tree-sitter-comment
147+ url = https://github.com/stsewd/tree-sitter-comment
148+ shallow = true
149+[submodule "helix-syntax/languages/tree-sitter-wgsl"]
150+ path = helix-syntax/languages/tree-sitter-wgsl
151+ url = https://github.com/szebniok/tree-sitter-wgsl
152+ shallow = true
153+[submodule "helix-syntax/languages/tree-sitter-llvm"]
154+ path = helix-syntax/languages/tree-sitter-llvm
155+ url = https://github.com/benwilliamgraham/tree-sitter-llvm
156+ shallow = true
157+[submodule "helix-syntax/languages/tree-sitter-markdown"]
158+ path = helix-syntax/languages/tree-sitter-markdown
159+ url = https://github.com/MDeiml/tree-sitter-markdown
160+ shallow = true
161+[submodule "helix-syntax/languages/tree-sitter-dart"]
162+ path = helix-syntax/languages/tree-sitter-dart
163+ url = https://github.com/UserNobody14/tree-sitter-dart.git
164+ shallow = true
165+[submodule "helix-syntax/languages/tree-sitter-dockerfile"]
166+ path = helix-syntax/languages/tree-sitter-dockerfile
167+ url = https://github.com/camdencheek/tree-sitter-dockerfile.git
168+ shallow = true
169+[submodule "helix-syntax/languages/tree-sitter-fish"]
170+ path = helix-syntax/languages/tree-sitter-fish
171+ url = https://github.com/ram02z/tree-sitter-fish
172+ shallow = true
173+[submodule "helix-syntax/languages/tree-sitter-git-commit"]
174+ path = helix-syntax/languages/tree-sitter-git-commit
175+ url = https://github.com/the-mikedavis/tree-sitter-git-commit.git
176+ shallow = true
177+[submodule "helix-syntax/languages/tree-sitter-llvm-mir"]
178+ path = helix-syntax/languages/tree-sitter-llvm-mir
179+ url = https://github.com/Flakebi/tree-sitter-llvm-mir.git
180+ shallow = true
181+[submodule "helix-syntax/languages/tree-sitter-git-diff"]
182+ path = helix-syntax/languages/tree-sitter-git-diff
183+ url = https://github.com/the-mikedavis/tree-sitter-git-diff.git
184+ shallow = true
185+[submodule "helix-syntax/languages/tree-sitter-tablegen"]
186+ path = helix-syntax/languages/tree-sitter-tablegen
187+ url = https://github.com/Flakebi/tree-sitter-tablegen
188+ shallow = true
189+[submodule "helix-syntax/languages/tree-sitter-git-rebase"]
190+ path = helix-syntax/languages/tree-sitter-git-rebase
191+ url = https://github.com/the-mikedavis/tree-sitter-git-rebase.git
192+ shallow = true
.ignoredeleted−2
@@ -1,2 +0,0 @@
1−# Things that we don't want ripgrep to search that we do want in git
2−# https://github.com/BurntSushi/ripgrep/blob/master/GUIDE.md#automatic-filtering
CHANGELOG.md+29−1702
@@ -1,1675 +1,3 @@
1−# 23.10 (2023-10-24)
2−
3−A big shout out to all the contributors! We had 118 contributors in this release.
4−
5−Breaking changes:
6−
7−- Support multiple language servers per language ([#2507](https://github.com/helix-editor/helix/pull/2507))
8− - This is a breaking change to language configuration
9−
10−Features:
11−
12−- Support multiple language servers per language ([#2507](https://github.com/helix-editor/helix/pull/2507), [#7082](https://github.com/helix-editor/helix/pull/7082), [#7286](https://github.com/helix-editor/helix/pull/7286), [#8374](https://github.com/helix-editor/helix/pull/8374))
13−- Add a statusline element for the selected register ([#7222](https://github.com/helix-editor/helix/pull/7222))
14−- Add `%`, `#`, `.`, `*` and `+` special registers ([#6985](https://github.com/helix-editor/helix/pull/6985))
15−- Add initial support for LSP DidChangeWatchedFiles notifications ([#7665](https://github.com/helix-editor/helix/pull/7665))
16−- Search buffer contents in `global_search` ([#5652](https://github.com/helix-editor/helix/pull/5652))
17−- Add a "smart tab" command that intelligently jumps the cursor on tab ([#4443](https://github.com/helix-editor/helix/pull/4443))
18−- Add a statusline element for whether a file is read-only ([#7222](https://github.com/helix-editor/helix/pull/7222), [#7875](https://github.com/helix-editor/helix/pull/7875))
19−- Syntax highlight regex prompts ([#7738](https://github.com/helix-editor/helix/pull/7738))
20−- Allow defining alignment in indent queries ([#5355](https://github.com/helix-editor/helix/pull/5355))
21−- Show visual feedback in `surround_replace` ([#7588](https://github.com/helix-editor/helix/pull/7588))
22−- Switch to Nucleo for fuzzy matching ([#7814](https://github.com/helix-editor/helix/pull/7814), [#8148](https://github.com/helix-editor/helix/pull/8148), [#8192](https://github.com/helix-editor/helix/pull/8192), [#8194](https://github.com/helix-editor/helix/pull/8194))
23−- Insert a trailing newline on write ([#8157](https://github.com/helix-editor/helix/pull/8157))
24−- Add a `-w`/`--working-dir` CLI flag for specifying a working directory on startup ([#8223](https://github.com/helix-editor/helix/pull/8223), [#8498](https://github.com/helix-editor/helix/pull/8498), [#8520](https://github.com/helix-editor/helix/pull/8520))
25−- Accept a `+N` CLI argument to set the first file's line number ([#8521](https://github.com/helix-editor/helix/pull/8521))
26−- Accept Helix-specific ignore files in `.helix/ignore` and `~/.config/helix/ignore` ([#8099](https://github.com/helix-editor/helix/pull/8099))
27−
28−Commands:
29−
30−- `merge_selections` (`A-minus`) - merge all selections into one selection that covers all ranges ([#7053](https://github.com/helix-editor/helix/pull/7053))
31−- `move_prev_long_word_end` and `extend_prev_long_word_end` - move/extend to the end of the previous WORD ([#6905](https://github.com/helix-editor/helix/pull/6905))
32−- `reverse_selection_contents` - swaps the values of each selection so they are reversed ([#7329](https://github.com/helix-editor/helix/pull/7329))
33−- Add `:rl` and `:rla` aliases for `:reload` and `:reload-all` ([#7158](https://github.com/helix-editor/helix/pull/7158))
34−- `yank_joined` - join the selections and yank to the selected register ([#7195](https://github.com/helix-editor/helix/pull/7195))
35−- `:write-all!` (`:wa!`) - forcibly write all buffers to disk and create any necessary subdirectories ([#7577](https://github.com/helix-editor/helix/pull/7577))
36−- `:redraw` - clear re-render the UI ([#6949](https://github.com/helix-editor/helix/pull/6949))
37−- `:tree-sitter-highlight-name` - show the theme scope name of the highlight under the cursor ([#8170](https://github.com/helix-editor/helix/pull/8170))
38−
39−Usability improvements:
40−
41−- Allow cycling option values at runtime ([#4411](https://github.com/helix-editor/helix/pull/4411), [#7240](https://github.com/helix-editor/helix/pull/7240), [#7877](https://github.com/helix-editor/helix/pull/7877))
42−- Exit gracefully on termination signals ([#7236](https://github.com/helix-editor/helix/pull/7236))
43−- Add plaintext matching fallback to tree-sitter pair matching ([#4288](https://github.com/helix-editor/helix/pull/4288))
44−- Persist register selection in pending keymaps ([0e08349](https://github.com/helix-editor/helix/commit/0e08349))
45−- Propagate the count and register to command palette commands ([b394997](https://github.com/helix-editor/helix/commit/b394997))
46−- Auto indent on `insert_at_line_start` ([#5837](https://github.com/helix-editor/helix/pull/5837))
47−- Add a config option to control whether LSP completions are automatically inserted on preview ([#7189](https://github.com/helix-editor/helix/pull/7189))
48−- Add a config option for default line endings ([#5621](https://github.com/helix-editor/helix/pull/5621), [#7357](https://github.com/helix-editor/helix/pull/7357))
49−- Allow ANSI colors in themes ([#5119](https://github.com/helix-editor/helix/pull/5119))
50−- Match pairs that don't form a standalone tree-sitter node ([#7242](https://github.com/helix-editor/helix/pull/7242))
51−- Allow indent sizes of up to 16 columns ([#7429](https://github.com/helix-editor/helix/pull/7429))
52−- Improve performance of mapping positions through changes ([#7408](https://github.com/helix-editor/helix/pull/7408), [8d39a81](https://github.com/helix-editor/helix/commit/8d39a81), [#7471](https://github.com/helix-editor/helix/pull/7471))
53−- Mark buffers created from stdin as modified ([#7431](https://github.com/helix-editor/helix/pull/7431))
54−- Forcibly shut down uninitialized language servers ([#7449](https://github.com/helix-editor/helix/pull/7449))
55−- Add filename completer for shell prompts ([#7569](https://github.com/helix-editor/helix/pull/7569))
56−- Allow binding F13-F24 ([#7672](https://github.com/helix-editor/helix/pull/7672))
57−- Resolve LSP code actions ([#7677](https://github.com/helix-editor/helix/pull/7677), [#8421](https://github.com/helix-editor/helix/pull/8421))
58−- Save an undo checkpoint before accepting completions ([#7747](https://github.com/helix-editor/helix/pull/7747))
59−- Include gitignored files in debugger completions ([#7936](https://github.com/helix-editor/helix/pull/7936))
60−- Make editor remember the last search register ([#5244](https://github.com/helix-editor/helix/pull/5244))
61−- Open directories with `goto_file` ([#7909](https://github.com/helix-editor/helix/pull/7909))
62−- Use relative path to open buffer in `goto_file` (`gf`) ([#7965](https://github.com/helix-editor/helix/pull/7965))
63−- Support `default` color in themes ([#8083](https://github.com/helix-editor/helix/pull/8083), [#8114](https://github.com/helix-editor/helix/pull/8114))
64−- Toggle between relative and absolute line numbers when the terminal loses focus ([#7955](https://github.com/helix-editor/helix/pull/7955))
65−- Lower default idle-timeout to 250ms ([060e73a](https://github.com/helix-editor/helix/commit/060e73a))
66−- Allow theming diff gutters separately from other diff colors ([#8343](https://github.com/helix-editor/helix/pull/8343))
67−- Style bold/italic/strikethrough in markdown doc popups ([#8385](https://github.com/helix-editor/helix/pull/8385))
68−- Maintain the cursor position and view when splitting with `:hsplit`/`:vsplit` ([#8109](https://github.com/helix-editor/helix/pull/8109))
69−- Accept `-` in macros outside of `<`/`>` ([#8475](https://github.com/helix-editor/helix/pull/8475))
70−- Show all language servers for each language in `--health` ([#7315](https://github.com/helix-editor/helix/pull/7315))
71−- Don't break on hyphens in `:reflow` ([#8569](https://github.com/helix-editor/helix/pull/8569))
72−
73−Fixes:
74−
75−- Update diagnostics correctly on language server exit ([#7111](https://github.com/helix-editor/helix/pull/7111))
76−- Fix off-by-one in `select_references_to_symbol_under_cursor` ([#7132](https://github.com/helix-editor/helix/pull/7132))
77−- Extend selection with repeat-last-motion only if the original motion extended the selection ([#7159](https://github.com/helix-editor/helix/pull/7159))
78−- Fix undefined behavior in the diff gutter ([#7227](https://github.com/helix-editor/helix/pull/7227))
79−- Check that tab width is non-zero ([#7178](https://github.com/helix-editor/helix/pull/7178))
80−- Fix styles being overwritten in table rows with multiple cells ([#7281](https://github.com/helix-editor/helix/pull/7281))
81−- Add file for `--log` CLI arg in help text ([#7307](https://github.com/helix-editor/helix/pull/7307))
82−- Fix underflow when repeating a completion that has a negative shift position ([#7322](https://github.com/helix-editor/helix/pull/7322))
83−- Prefer longer matches in `select_next_sibling` and `select_prev_sibling` ([#7332](https://github.com/helix-editor/helix/pull/7332))
84−- Preview scratch buffers in the jumplist picker ([#7331](https://github.com/helix-editor/helix/pull/7331))
85−- Fix chunking by bytes in tree-sitter parsing ([#7417](https://github.com/helix-editor/helix/pull/7417))
86−- Discard LSP publishDiagnostic from uninitialized servers ([#7467](https://github.com/helix-editor/helix/pull/7467))
87−- Use negotiated position encoding for LSP workspace edits ([#7469](https://github.com/helix-editor/helix/pull/7469))
88−- Fix error message for unknown gutter types in config ([#7534](https://github.com/helix-editor/helix/pull/7534))
89−- Fix `:log-open` when `--log` CLI arg is specified ([#7573](https://github.com/helix-editor/helix/pull/7573), [#7585](https://github.com/helix-editor/helix/pull/7585))
90−- Fix debouncing of LSP messages to fix the last message sticking around ([#7538](https://github.com/helix-editor/helix/pull/7538), [#8023](https://github.com/helix-editor/helix/pull/8023))
91−- Fix crash when the current working directory is deleted ([#7185](https://github.com/helix-editor/helix/pull/7185))
92−- Fix piping to Helix on macOS ([#5468](https://github.com/helix-editor/helix/pull/5468))
93−- Fix crash when parsing overlapping injections ([#7621](https://github.com/helix-editor/helix/pull/7621))
94−- Clear the statusline when the prompt is visible ([#7646](https://github.com/helix-editor/helix/pull/7646))
95−- Fix range formatting error message typo ([#7823](https://github.com/helix-editor/helix/pull/7823))
96−- Skip rendering gutters when gutter width exceeds view width ([#7821](https://github.com/helix-editor/helix/pull/7821))
97−- Center the picker preview using visual lines ([#7837](https://github.com/helix-editor/helix/pull/7837))
98−- Align view correctly for background buffers opened with `A-ret` ([#7691](https://github.com/helix-editor/helix/pull/7691))
99−- Fix cursor resetting to block when quitting via a keybind ([#7931](https://github.com/helix-editor/helix/pull/7931))
100−- Remove path completions for the `:new` command ([#8010](https://github.com/helix-editor/helix/pull/8010))
101−- Use binary path resolved by `which` for formatter commands ([#8064](https://github.com/helix-editor/helix/pull/8064))
102−- Handle crossterm's `hidden` modifier ([#8120](https://github.com/helix-editor/helix/pull/8120))
103−- Clear completion when switching between windows with the mouse ([#8118](https://github.com/helix-editor/helix/pull/8118))
104−- Eagerly remove the last picker (`<space>'`) when the picker has many items ([#8127](https://github.com/helix-editor/helix/pull/8127))
105−- Fix find commands for buffers with non-LF line-endings ([#8111](https://github.com/helix-editor/helix/pull/8111))
106−- Detect the tmux clipboard provider on macOS ([#8182](https://github.com/helix-editor/helix/pull/8182))
107−- Fix syntax highlighting in dynamic picker preview pane ([#8206](https://github.com/helix-editor/helix/pull/8206))
108−- Recognize HTML code tags with attributes as code in markdown previews ([#8397](https://github.com/helix-editor/helix/pull/8397))
109−- Fix multicursor snippet placeholder directions ([#8423](https://github.com/helix-editor/helix/pull/8423))
110−- Only show diagnostic highlights when diagnostics are enabled for a language server ([#8551](https://github.com/helix-editor/helix/pull/8551))
111−
112−Themes:
113−
114−- Improve the selection color in `ferra` ([#7138](https://github.com/helix-editor/helix/pull/7138))
115−- Add `variable.other.member` theming to `spacebones_light` ([#7125](https://github.com/helix-editor/helix/pull/7125))
116−- Update `autumn` and theme the soft-wrap indicator ([#7229](https://github.com/helix-editor/helix/pull/7229))
117−- Add `gruvbox_dark_soft` ([#7139](https://github.com/helix-editor/helix/pull/7139))
118−- Add `merionette` ([#7186](https://github.com/helix-editor/helix/pull/7186))
119−- Add `zed_onedark` and `zed_onelight` ([#7250](https://github.com/helix-editor/helix/pull/7250))
120−- Use light-gray for `onedarker` inlay hint theming ([#7433](https://github.com/helix-editor/helix/pull/7433))
121−- Update the Nord theme to follow the style guidelines ([#7490](https://github.com/helix-editor/helix/pull/7490))
122−- Tune `dark_plus` inlay hint colors ([#7611](https://github.com/helix-editor/helix/pull/7611))
123−- Add `naysayer` ([#7570](https://github.com/helix-editor/helix/pull/7570))
124−- Add `kaolin-dark`, `kaolin-light` and `kaolin-valley-dark` ([#7151](https://github.com/helix-editor/helix/pull/7151))
125−- Fix selection highlighting in gruvbox variants ([#7717](https://github.com/helix-editor/helix/pull/7717))
126−- Add soft-wrap indicator to `gruvbox` ([#7736](https://github.com/helix-editor/helix/pull/7736))
127−- Add missing palette definitions in `everforest_dark` ([#7739](https://github.com/helix-editor/helix/pull/7739))
128−- Increase diagnostics clarity in `pop-dark` ([#7702](https://github.com/helix-editor/helix/pull/7702))
129−- Add `vim_dark_high_contrast` ([#7785](https://github.com/helix-editor/helix/pull/7785))
130−- Add `new_moon` ([#7834](https://github.com/helix-editor/helix/pull/7834))
131−- Add `yellowed` ([#7849](https://github.com/helix-editor/helix/pull/7849))
132−- Improve comment readability for `autumn` ([#7939](https://github.com/helix-editor/helix/pull/7939))
133−- Distinguish active bufferline buffer in `monokai` ([#7983](https://github.com/helix-editor/helix/pull/7983))
134−- Update ruler colors in `nord` ([#7995](https://github.com/helix-editor/helix/pull/7995))
135−- Update Catppuccin themes ([#8102](https://github.com/helix-editor/helix/pull/8102))
136−- Add text focus scope and diagnostics undercurls for `nord` ([#8165](https://github.com/helix-editor/helix/pull/8165))
137−- Add material theme collection ([#8211](https://github.com/helix-editor/helix/pull/8211))
138−- Improve indent line color in `dracula` ([#8266](https://github.com/helix-editor/helix/pull/8266))
139−- Clean up and refactor `papercolor` to use inheritance ([#8276](https://github.com/helix-editor/helix/pull/8276))
140−- Fix `zenburn` inlay hint color ([#8278](https://github.com/helix-editor/helix/pull/8278)a)
141−- Fix picker crash when previewing an invalid range ([e9d0bd7](https://github.com/helix-editor/helix/commit/e9d0bd7))
142−- Correctly center items in the picker preview ([13d4463](https://github.com/helix-editor/helix/commit/13d4463))
143−- Add `cyan_light` ([#8293](https://github.com/helix-editor/helix/pull/8293), [#8587](https://github.com/helix-editor/helix/pull/8587))
144−- Theme HTML tags in `onedark` ([#8409](https://github.com/helix-editor/helix/pull/8409))
145−- Refine `darcula` and `darcula-solid` themes ([#8412](https://github.com/helix-editor/helix/pull/8412))
146−- Improve `nord` highlights ([#8414](https://github.com/helix-editor/helix/pull/8414))
147−- Add `nord-night` ([#8549](https://github.com/helix-editor/helix/pull/8549))
148−
149−New languages:
150−
151−- Blueprint ([#7213](https://github.com/helix-editor/helix/pull/7213), [#8161](https://github.com/helix-editor/helix/pull/8161))
152−- Forth ([#7256](https://github.com/helix-editor/helix/pull/7256), [#7334](https://github.com/helix-editor/helix/pull/7334))
153−- t32 ([#7140](https://github.com/helix-editor/helix/pull/7140), [#7811](https://github.com/helix-editor/helix/pull/7811))
154−- WebC ([#7290](https://github.com/helix-editor/helix/pull/7290))
155−- Persistent DSL for Haskell ([#7261](https://github.com/helix-editor/helix/pull/7261))
156−- F# ([#7619](https://github.com/helix-editor/helix/pull/7619), [#8024](https://github.com/helix-editor/helix/pull/8024))
157−- Wren ([#7765](https://github.com/helix-editor/helix/pull/7765), [#7819](https://github.com/helix-editor/helix/pull/7819))
158−- Unison ([#7724](https://github.com/helix-editor/helix/pull/7724))
159−- Todo.txt ([#7835](https://github.com/helix-editor/helix/pull/7835))
160−- Jinja and Handlebars ([#7233](https://github.com/helix-editor/helix/pull/7233))
161−- Pod ([#7907](https://github.com/helix-editor/helix/pull/7907))
162−- Strace ([#7928](https://github.com/helix-editor/helix/pull/7928))
163−- Gemini ([#8070](https://github.com/helix-editor/helix/pull/8070))
164−- GNU Assembler (GAS) ([#8291](https://github.com/helix-editor/helix/pull/8291))
165−- JSON5 ([#8473](https://github.com/helix-editor/helix/pull/8473))
166−- TEMPL ([#8540](https://github.com/helix-editor/helix/pull/8540))
167−
168−Updated languages and queries:
169−
170−- Add one to the ruler numbers for git-commit ([#7072](https://github.com/helix-editor/helix/pull/7072))
171−- Recognize XAML files as XML ([#7083](https://github.com/helix-editor/helix/pull/7083))
172−- Recognize `Cargo.lock` as TOML ([#7095](https://github.com/helix-editor/helix/pull/7095))
173−- Use Rust grammar for Cairo ([c6d1430](https://github.com/helix-editor/helix/commit/c6d1430))
174−- Update tree-sitter-nickel ([#7059](https://github.com/helix-editor/helix/pull/7059), [#7551](https://github.com/helix-editor/helix/pull/7551))
175−- Tune auto-pair characters for Nickel ([#7059](https://github.com/helix-editor/helix/pull/7059))
176−- Recognize `Vagrantfile` as Ruby ([#7112](https://github.com/helix-editor/helix/pull/7112))
177−- Recognize hidden justfiles as Just ([#7088](https://github.com/helix-editor/helix/pull/7088))
178−- Update Java and TypeScript highlight queries ([#7145](https://github.com/helix-editor/helix/pull/7145))
179−- Recognize `.zimrc` as Bash ([#7146](https://github.com/helix-editor/helix/pull/7146))
180−- Recognize `.gir` as XML ([#7152](https://github.com/helix-editor/helix/pull/7152))
181−- Update tree-sitter-scala ([#7147](https://github.com/helix-editor/helix/pull/7147))
182−- Recognize make file-type as Makefile ([#7212](https://github.com/helix-editor/helix/pull/7212))
183−- Update tree-sitter-verilog ([#7262](https://github.com/helix-editor/helix/pull/7262))
184−- Update tree-sitter-cpp ([#7285](https://github.com/helix-editor/helix/pull/7285))
185−- Support core mode for delve debugger ([#7300](https://github.com/helix-editor/helix/pull/7300))
186−- Add Fortran comment injections ([#7305](https://github.com/helix-editor/helix/pull/7305))
187−- Switch Vue language server to `vue-language-server` ([#7312](https://github.com/helix-editor/helix/pull/7312))
188−- Update tree-sitter-sql ([#7387](https://github.com/helix-editor/helix/pull/7387), [#8464](https://github.com/helix-editor/helix/pull/8464))
189−- Replace the MATLAB tre-sitter grammar ([#7388](https://github.com/helix-editor/helix/pull/7388), [#7442](https://github.com/helix-editor/helix/pull/7442), [#7491](https://github.com/helix-editor/helix/pull/7491), [#7493](https://github.com/helix-editor/helix/pull/7493), [#7511](https://github.com/helix-editor/helix/pull/7511), [#7532](https://github.com/helix-editor/helix/pull/7532), [#8040](https://github.com/helix-editor/helix/pull/8040))
190−- Highlight TOML table headers ([#7441](https://github.com/helix-editor/helix/pull/7441))
191−- Recognize `cppm` file-type as C++ ([#7492](https://github.com/helix-editor/helix/pull/7492))
192−- Refactor ecma language queries into private and public queries ([#7207](https://github.com/helix-editor/helix/pull/7207))
193−- Update tree-sitter-dart ([#7576](https://github.com/helix-editor/helix/pull/7576))
194−- Add shebang for nushell files ([#7606](https://github.com/helix-editor/helix/pull/7606))
195−- Recognize systemd files as INI ([#7592](https://github.com/helix-editor/helix/pull/7592))
196−- Update TypeScript, TSX and Svelte grammars ([#6874](https://github.com/helix-editor/helix/pull/6874))
197−- Enable inlay hints in the Svelte language server ([#7622](https://github.com/helix-editor/helix/pull/7622))
198−- Recognize `Brewfile`s as Ruby ([#7629](https://github.com/helix-editor/helix/pull/7629))
199−- Add more file-types for R ([#7633](https://github.com/helix-editor/helix/pull/7633))
200−- Switch tree-sitter-perl to official upstream parser ([#7644](https://github.com/helix-editor/helix/pull/7644), [#7947](https://github.com/helix-editor/helix/pull/7947))
201−- Fix predicate typo in comment highlights ([#7732](https://github.com/helix-editor/helix/pull/7732))
202−- Update tree-sitter-prql ([#7771](https://github.com/helix-editor/helix/pull/7771))
203−- Recognize `.gitf` as JSON ([#7781](https://github.com/helix-editor/helix/pull/7781))
204−- Switch V language server to `v-analyzer` ([#7760](https://github.com/helix-editor/helix/pull/7760))
205−- Add protobuf language servers ([#7796](https://github.com/helix-editor/helix/pull/7796))
206−- Update tree-sitter-zig ([#7803](https://github.com/helix-editor/helix/pull/7803))
207−- Update tree-sitter-hare ([#7784](https://github.com/helix-editor/helix/pull/7784))
208−- Add Java indent queries ([#7844](https://github.com/helix-editor/helix/pull/7844))
209−- Update tree-sitter-scheme ([979933b](https://github.com/helix-editor/helix/commit/979933b))
210−- Recognize `scm` as Scheme instead of TSQ ([5707151](https://github.com/helix-editor/helix/commit/5707151))
211−- Update tree-sitter-git-commit ([#7831](https://github.com/helix-editor/helix/pull/7831))
212−- Update JavaScript, TypeScript and TSX grammars ([#7852](https://github.com/helix-editor/helix/pull/7852))
213−- Update tree-sitter-nu ([#7873](https://github.com/helix-editor/helix/pull/7873))
214−- Fix YAML indentation ([#6768](https://github.com/helix-editor/helix/pull/6768))
215−- Add `csharp-ls`, Pyright, Pylyzer and add roots for Python ([#7897](https://github.com/helix-editor/helix/pull/7897), [#8032](https://github.com/helix-editor/helix/pull/8032))
216−- Update tree-sitter-slint ([#7893](https://github.com/helix-editor/helix/pull/7893))
217−- Recognize more ZSH file-types as Bash ([#7930](https://github.com/helix-editor/helix/pull/7930))
218−- Recognize `star` extension as Starlark ([#7922](https://github.com/helix-editor/helix/pull/7922))
219−- Fix inline HTML tag highlighting in markdown ([#7960](https://github.com/helix-editor/helix/pull/7960))
220−- Update tree-sitter-robot ([#7970](https://github.com/helix-editor/helix/pull/7970))
221−- Highlight Dart 3 `sealed` and `base` keywords ([#7974](https://github.com/helix-editor/helix/pull/7974))
222−- Add configuration for `ltex-ls` to the default `languages.toml` ([#7838](https://github.com/helix-editor/helix/pull/7838))
223−- Update tree-sitter-strace ([#8087](https://github.com/helix-editor/helix/pull/8087))
224−- Update tree-sitter-gleam, enable auto-format ([#8085](https://github.com/helix-editor/helix/pull/8085))
225−- Update tree-sitter-esdl ([#8222](https://github.com/helix-editor/helix/pull/8222))
226−- Expand ignore file-types ([#8220](https://github.com/helix-editor/helix/pull/8220))
227−- Recognize feed related formats as XML ([#8232](https://github.com/helix-editor/helix/pull/8232))
228−- Improve YAML injections ([#8217](https://github.com/helix-editor/helix/pull/8217))
229−- Add shebangs for TypeScript, Julia, Java and OCaml ([95e994a](https://github.com/helix-editor/helix/commit/95e994a))
230−- Highlight abbreviations in Scheme ([ef23847](https://github.com/helix-editor/helix/commit/ef23847))
231−- Remove backtic auto-pair in OCaml ([#8260](https://github.com/helix-editor/helix/pull/8260))
232−- Recognize `flake.lock` as JSON ([#8304](https://github.com/helix-editor/helix/pull/8304))
233−- Add Python test script injection for Nix ([b4494e1](https://github.com/helix-editor/helix/commit/b4494e1))
234−- Fix Nix comment injection precedence ([37e48f4](https://github.com/helix-editor/helix/commit/37e48f4))
235−- Recognize editorconfig files as INI ([#8308](https://github.com/helix-editor/helix/pull/8308))
236−- Recognize `.babelrc` as JSON ([#8309](https://github.com/helix-editor/helix/pull/8309))
237−- Switch Purescript to its own tree-sitter parser ([#8306](https://github.com/helix-editor/helix/pull/8306), [#8338](https://github.com/helix-editor/helix/pull/8338), [#8527](https://github.com/helix-editor/helix/pull/8527))
238−- Update Unison highlights ([#8315](https://github.com/helix-editor/helix/pull/8315))
239−- Recognize `.webmanifest` as JSON ([#8342](https://github.com/helix-editor/helix/pull/8342))
240−- Recognize polkit policy files as XML ([#8369](https://github.com/helix-editor/helix/pull/8369))
241−- Recognize polkit rules files as JavaScript ([#8370](https://github.com/helix-editor/helix/pull/8370))
242−- Update Go highlight queries ([#8399](https://github.com/helix-editor/helix/pull/8399))
243−- Add shebangs for Makefiles ([#8410](https://github.com/helix-editor/helix/pull/8410))
244−- Add file-type associations from VSCode ([#8388](https://github.com/helix-editor/helix/pull/8388))
245−- Add validation to JSON/CSS language server configs ([#8433](https://github.com/helix-editor/helix/pull/8433))
246−- Add a configuration for the tailwind language server ([#8442](https://github.com/helix-editor/helix/pull/8442))
247−- Add a configuration for the ansible language server ([#7973](https://github.com/helix-editor/helix/pull/7973))
248−- Add a configuration for the GraphQL language server ([#8492](https://github.com/helix-editor/helix/pull/8492))
249−- Indent while statements in Bash ([#8528](https://github.com/helix-editor/helix/pull/8528))
250−- Update tree-sitter-haskell and queries ([#8558](https://github.com/helix-editor/helix/pull/8558))
251−
252−Packaging:
253−
254−- Add an overlay to the Nix flake ([#7078](https://github.com/helix-editor/helix/pull/7078))
255−- Check for `git` before fetching or building grammars ([#7320](https://github.com/helix-editor/helix/pull/7320))
256−- Refactor Nix flake to use Crane ([#7763](https://github.com/helix-editor/helix/pull/7763))
257−- Remove the aarch64 appimage from the release CI ([#7832](https://github.com/helix-editor/helix/pull/7832))
258−- Add desktop and icon files to Nix flake output ([#7979](https://github.com/helix-editor/helix/pull/7979))
259−- Build flake packages with the latest stable Rust ([#8133](https://github.com/helix-editor/helix/pull/8133))
260−
261−# 23.05 (2023-05-18)
262−
263−23.05 is a smaller release focusing on fixes. There were 88 contributors in this release. Thank you all!
264−
265−Features:
266−
267−- Add a config option to exclude declaration from LSP references request ([#6886](https://github.com/helix-editor/helix/pull/6886))
268−- Enable injecting languages based on their file extension and shebang ([#3970](https://github.com/helix-editor/helix/pull/3970))
269−- Sort the buffer picker by most recent access ([#2980](https://github.com/helix-editor/helix/pull/2980))
270−- Perform syntax highlighting in the picker asynchronously ([#7028](https://github.com/helix-editor/helix/pull/7028))
271−
272−Commands:
273−
274−- `:update` is now aliased as `:u` ([#6835](https://github.com/helix-editor/helix/pull/6835))
275−- Add `extend_to_first_nonwhitespace` which acts the same as `goto_first_nonwhitespace` but always extends ([#6837](https://github.com/helix-editor/helix/pull/6837))
276−- Add `:clear-register` for clearing the given register or all registers ([#5695](https://github.com/helix-editor/helix/pull/5695))
277−- Add `:write-buffer-close` and `:write-buffer-close!` ([#6947](https://github.com/helix-editor/helix/pull/6947))
278−
279−Fixes:
280−
281−- Normalize LSP workspace paths ([#6517](https://github.com/helix-editor/helix/pull/6517))
282−- Robustly handle invalid LSP ranges ([#6512](https://github.com/helix-editor/helix/pull/6512))
283−- Fix line number display for LSP goto pickers ([#6559](https://github.com/helix-editor/helix/pull/6559))
284−- Fix toggling of `soft-wrap.enable` option ([#6656](https://github.com/helix-editor/helix/pull/6656), [58e457a](https://github.com/helix-editor/helix/commit/58e457a), [#6742](https://github.com/helix-editor/helix/pull/6742))
285−- Handle `workspace/configuration` requests from stopped language servers ([#6693](https://github.com/helix-editor/helix/pull/6693))
286−- Fix possible crash from opening the jumplist picker ([#6672](https://github.com/helix-editor/helix/pull/6672))
287−- Fix theme preview returning to current theme on line and word deletions ([#6694](https://github.com/helix-editor/helix/pull/6694))
288−- Re-run crate build scripts on changes to revision and grammar repositories ([#6743](https://github.com/helix-editor/helix/pull/6743))
289−- Fix crash on opening from suspended state ([#6764](https://github.com/helix-editor/helix/pull/6764))
290−- Fix unwrap bug in DAP ([#6786](https://github.com/helix-editor/helix/pull/6786))
291−- Always build tree-sitter parsers with C++14 and C11 ([#6792](https://github.com/helix-editor/helix/pull/6792), [#6834](https://github.com/helix-editor/helix/pull/6834), [#6845](https://github.com/helix-editor/helix/pull/6845))
292−- Exit with a non-zero statuscode when tree-sitter parser builds fail ([#6795](https://github.com/helix-editor/helix/pull/6795))
293−- Flip symbol range in LSP goto commands ([#6794](https://github.com/helix-editor/helix/pull/6794))
294−- Fix runtime toggling of the `mouse` option ([#6675](https://github.com/helix-editor/helix/pull/6675))
295−- Fix panic in inlay hint computation when view anchor is out of bounds ([#6883](https://github.com/helix-editor/helix/pull/6883))
296−- Significantly improve performance of git discovery on slow file systems ([#6890](https://github.com/helix-editor/helix/pull/6890))
297−- Downgrade gix log level to info ([#6915](https://github.com/helix-editor/helix/pull/6915))
298−- Conserve BOM and properly support saving UTF16 files ([#6497](https://github.com/helix-editor/helix/pull/6497))
299−- Correctly handle completion re-request ([#6594](https://github.com/helix-editor/helix/pull/6594))
300−- Fix offset encoding in LSP `didChange` notifications ([#6921](https://github.com/helix-editor/helix/pull/6921))
301−- Change `gix` logging level to info ([#6915](https://github.com/helix-editor/helix/pull/6915))
302−- Improve error message when writes fail because parent directories do not exist ([#7014](https://github.com/helix-editor/helix/pull/7014))
303−- Replace DAP variables popup instead of pushing more popups ([#7034](https://github.com/helix-editor/helix/pull/7034))
304−- Disable tree-sitter for files after parsing for 500ms ([#7028](https://github.com/helix-editor/helix/pull/7028))
305−- Fix crash when deleting with multiple cursors ([#6024](https://github.com/helix-editor/helix/pull/6024))
306−- Fix selection sliding when deleting forwards in append mode ([#6024](https://github.com/helix-editor/helix/pull/6024))
307−- Fix completion on paths containing spaces ([#6779](https://github.com/helix-editor/helix/pull/6779))
308−
309−Themes:
310−
311−- Style inlay hints in `dracula` theme ([#6515](https://github.com/helix-editor/helix/pull/6515))
312−- Style inlay hints in `onedark` theme ([#6503](https://github.com/helix-editor/helix/pull/6503))
313−- Style inlay hints and the soft-wrap indicator in `varua` ([#6568](https://github.com/helix-editor/helix/pull/6568), [#6589](https://github.com/helix-editor/helix/pull/6589))
314−- Style inlay hints in `emacs` theme ([#6569](https://github.com/helix-editor/helix/pull/6569))
315−- Update `base16_transparent` and `dark_high_contrast` themes ([#6577](https://github.com/helix-editor/helix/pull/6577))
316−- Style inlay hints for `mellow` and `rasmus` themes ([#6583](https://github.com/helix-editor/helix/pull/6583))
317−- Dim pane divider for `base16_transparent` theme ([#6534](https://github.com/helix-editor/helix/pull/6534))
318−- Style inlay hints in `zenburn` theme ([#6593](https://github.com/helix-editor/helix/pull/6593))
319−- Style inlay hints in `boo_berry` theme ([#6625](https://github.com/helix-editor/helix/pull/6625))
320−- Add `ferra` theme ([#6619](https://github.com/helix-editor/helix/pull/6619), [#6776](https://github.com/helix-editor/helix/pull/6776))
321−- Style inlay hints in `nightfox` theme ([#6655](https://github.com/helix-editor/helix/pull/6655))
322−- Fix `ayu` theme family markup code block background ([#6538](https://github.com/helix-editor/helix/pull/6538))
323−- Improve whitespace and search match colors in `rose_pine` theme ([#6679](https://github.com/helix-editor/helix/pull/6679))
324−- Highlight selected items in `base16_transparent` theme ([#6716](https://github.com/helix-editor/helix/pull/6716))
325−- Adjust everforest to resemble original more closely ([#5866](https://github.com/helix-editor/helix/pull/5866))
326−- Refactor `dracula` theme ([#6552](https://github.com/helix-editor/helix/pull/6552), [#6767](https://github.com/helix-editor/helix/pull/6767), [#6855](https://github.com/helix-editor/helix/pull/6855), [#6987](https://github.com/helix-editor/helix/pull/6987))
327−- Style inlay hints in `darcula` theme ([#6732](https://github.com/helix-editor/helix/pull/6732))
328−- Style inlay hints in `kanagawa` theme ([#6773](https://github.com/helix-editor/helix/pull/6773))
329−- Improve `ayu_dark` theme ([#6622](https://github.com/helix-editor/helix/pull/6622))
330−- Refactor `noctis` theme multiple cursor highlighting ([96720e7](https://github.com/helix-editor/helix/commit/96720e7))
331−- Refactor `noctis` theme whitespace rendering and indent guides ([f2ccc03](https://github.com/helix-editor/helix/commit/f2ccc03))
332−- Add `amberwood` theme ([#6924](https://github.com/helix-editor/helix/pull/6924))
333−- Update `nightfox` theme ([#7061](https://github.com/helix-editor/helix/pull/7061))
334−
335−Language support:
336−
337−- R language server: use the `--no-echo` flag to silence output ([#6570](https://github.com/helix-editor/helix/pull/6570))
338−- Recognize CUDA files as C++ ([#6521](https://github.com/helix-editor/helix/pull/6521))
339−- Add support for Hurl ([#6450](https://github.com/helix-editor/helix/pull/6450))
340−- Add textobject queries for Julia ([#6588](https://github.com/helix-editor/helix/pull/6588))
341−- Update Ruby highlight queries ([#6587](https://github.com/helix-editor/helix/pull/6587))
342−- Add xsd to XML file-types ([#6631](https://github.com/helix-editor/helix/pull/6631))
343−- Support Robot Framework ([#6611](https://github.com/helix-editor/helix/pull/6611))
344−- Update Gleam tree-sitter parser ([#6641](https://github.com/helix-editor/helix/pull/6641))
345−- Update git-commit tree-sitter parser ([#6692](https://github.com/helix-editor/helix/pull/6692))
346−- Update Haskell tree-sitter parser ([#6317](https://github.com/helix-editor/helix/pull/6317))
347−- Add injection queries for Haskell quasiquotes ([#6474](https://github.com/helix-editor/helix/pull/6474))
348−- Highlight C/C++ escape sequences ([#6724](https://github.com/helix-editor/helix/pull/6724))
349−- Support Markdoc ([#6432](https://github.com/helix-editor/helix/pull/6432))
350−- Support OpenCL ([#6473](https://github.com/helix-editor/helix/pull/6473))
351−- Support DTD ([#6644](https://github.com/helix-editor/helix/pull/6644))
352−- Fix constant highlighting in Python queries ([#6751](https://github.com/helix-editor/helix/pull/6751))
353−- Support Just ([#6453](https://github.com/helix-editor/helix/pull/6453))
354−- Fix Go locals query for `var_spec` identifiers ([#6763](https://github.com/helix-editor/helix/pull/6763))
355−- Update Markdown tree-sitter parser ([#6785](https://github.com/helix-editor/helix/pull/6785))
356−- Fix Haskell workspace root for cabal projects ([#6828](https://github.com/helix-editor/helix/pull/6828))
357−- Avoid extra indentation in Go switches ([#6817](https://github.com/helix-editor/helix/pull/6817))
358−- Fix Go workspace roots ([#6884](https://github.com/helix-editor/helix/pull/6884))
359−- Set PerlNavigator as the default Perl language server ([#6860](https://github.com/helix-editor/helix/pull/6860))
360−- Highlight more sqlx macros in Rust ([#6793](https://github.com/helix-editor/helix/pull/6793))
361−- Switch Odin tree-sitter grammar ([#6766](https://github.com/helix-editor/helix/pull/6766))
362−- Recognize `poetry.lock` as TOML ([#6928](https://github.com/helix-editor/helix/pull/6928))
363−- Recognize Jupyter notebooks as JSON ([#6927](https://github.com/helix-editor/helix/pull/6927))
364−- Add language server configuration for Crystal ([#6948](https://github.com/helix-editor/helix/pull/6948))
365−- Add `build.gradle.kts` to Java and Scala roots ([#6970](https://github.com/helix-editor/helix/pull/6970))
366−- Recognize `sty` and `cls` files as latex ([#6986](https://github.com/helix-editor/helix/pull/6986))
367−- Update Dockerfile tree-sitter grammar ([#6895](https://github.com/helix-editor/helix/pull/6895))
368−- Add comment injections for Odin ([#7027](https://github.com/helix-editor/helix/pull/7027))
369−- Recognize `gml` as XML ([#7055](https://github.com/helix-editor/helix/pull/7055))
370−- Recognize `geojson` as JSON ([#7054](https://github.com/helix-editor/helix/pull/7054))
371−
372−Packaging:
373−
374−- Update the Nix flake dependencies, remove a deprecated option ([#6546](https://github.com/helix-editor/helix/pull/6546))
375−- Fix and re-enable aarch64-macos release binary builds ([#6504](https://github.com/helix-editor/helix/pull/6504))
376−- The git dependency on `tree-sitter` has been replaced with a regular crates.io dependency ([#6608](https://github.com/helix-editor/helix/pull/6608))
377−
378−# 23.03 (2023-03-31)
379−
380−23.03 brings some long-awaited and exciting features. Thank you to everyone involved! This release saw changes from 102 contributors.
381−
382−For the full log, check out the [git log](https://github.com/helix-editor/helix/compare/22.12..23.03).
383−Also check out the [release notes](https://helix-editor.com/news/release-23-03-highlights/) for more commentary on larger features.
384−
385−Breaking changes:
386−
387−- Select diagnostic range in `goto_*_diag` commands ([#4713](https://github.com/helix-editor/helix/pull/4713), [#5164](https://github.com/helix-editor/helix/pull/5164), [#6193](https://github.com/helix-editor/helix/pull/6193))
388−- Remove jump behavior from `increment`/`decrement` ([#4123](https://github.com/helix-editor/helix/pull/4123), [#5929](https://github.com/helix-editor/helix/pull/5929))
389−- Select change range in `goto_*_change` commands ([#5206](https://github.com/helix-editor/helix/pull/5206))
390−- Split file modification indicator from filename statusline elements ([#4731](https://github.com/helix-editor/helix/pull/4731), [#6036](https://github.com/helix-editor/helix/pull/6036))
391−- Jump to symbol ranges in LSP goto commands ([#5986](https://github.com/helix-editor/helix/pull/5986))
392−- Workspace detection now stops at the first `.helix/` directory (merging multiple `.helix/languages.toml` configurations is no longer supported) ([#5748](https://github.com/helix-editor/helix/pull/5748))
393−
394−Features:
395−
396−- Dynamic workspace symbol picker ([#5055](https://github.com/helix-editor/helix/pull/5055))
397−- Soft-wrap ([#5420](https://github.com/helix-editor/helix/pull/5420), [#5786](https://github.com/helix-editor/helix/pull/5786), [#5893](https://github.com/helix-editor/helix/pull/5893), [#6142](https://github.com/helix-editor/helix/pull/6142), [#6440](https://github.com/helix-editor/helix/pull/6440))
398−- Initial support for LSP snippet completions ([#5864](https://github.com/helix-editor/helix/pull/5864), [b1f7528](https://github.com/helix-editor/helix/commit/b1f7528), [#6263](https://github.com/helix-editor/helix/pull/6263), [bbf4800](https://github.com/helix-editor/helix/commit/bbf4800), [90348b8](https://github.com/helix-editor/helix/commit/90348b8), [f87299f](https://github.com/helix-editor/helix/commit/f87299f), [#6371](https://github.com/helix-editor/helix/pull/6371), [9fe3adc](https://github.com/helix-editor/helix/commit/9fe3adc))
399−- Add a statusline element for showing the current version control HEAD ([#5682](https://github.com/helix-editor/helix/pull/5682))
400−- Display LSP type hints ([#5420](https://github.com/helix-editor/helix/pull/5420), [#5934](https://github.com/helix-editor/helix/pull/5934), [#6312](https://github.com/helix-editor/helix/pull/6312))
401−- Enable the Kitty keyboard protocol on terminals with support ([#4939](https://github.com/helix-editor/helix/pull/4939), [#6170](https://github.com/helix-editor/helix/pull/6170), [#6194](https://github.com/helix-editor/helix/pull/6194), [#6438](https://github.com/helix-editor/helix/pull/6438))
402−- Add a statusline element for the basename of the current file ([#5318](https://github.com/helix-editor/helix/pull/5318))
403−- Add substring matching syntax for the picker ([#5658](https://github.com/helix-editor/helix/pull/5658))
404−- Support LSP `textDocument/prepareRename` ([#6103](https://github.com/helix-editor/helix/pull/6103))
405−- Allow multiple runtime directories with priorities ([#5411](https://github.com/helix-editor/helix/pull/5411))
406−- Allow configuring whether to insert or replace completions ([#5728](https://github.com/helix-editor/helix/pull/5728))
407−- Allow per-workspace config file `.helix/config.toml` ([#5748](https://github.com/helix-editor/helix/pull/5748))
408−- Add `workspace-lsp-roots` config option to support multiple LSP roots for use with monorepos ([#5748](https://github.com/helix-editor/helix/pull/5748))
409−
410−Commands:
411−
412−- `:pipe-to` which pipes selections into a shell command and ignores output ([#4931](https://github.com/helix-editor/helix/pull/4931))
413−- `merge_consecutive_selections` (`A-_`) combines all consecutive selections ([#5047](https://github.com/helix-editor/helix/pull/5047))
414−- `rotate_view_reverse` which focuses the previous view ([#5356](https://github.com/helix-editor/helix/pull/5356))
415−- `goto_declaration` (`gD`, requires LSP) which jumps to a symbol's declaration ([#5646](https://github.com/helix-editor/helix/pull/5646))
416−- `file_picker_in_current_buffer_directory` ([#4666](https://github.com/helix-editor/helix/pull/4666))
417−- `:character-info` which shows information about the character under the cursor ([#4000](https://github.com/helix-editor/helix/pull/4000))
418−- `:toggle-option` for toggling config options at runtime ([#4085](https://github.com/helix-editor/helix/pull/4085))
419−- `dap_restart` for restarting a debug session in DAP ([#5651](https://github.com/helix-editor/helix/pull/5651))
420−- `:lsp-stop` to stop the language server of the current buffer ([#5964](https://github.com/helix-editor/helix/pull/5964))
421−- `:reset-diff-change` for resetting a diff hunk to its original text ([#4974](https://github.com/helix-editor/helix/pull/4974))
422−- `:config-open-workspace` for opening the config file local to the current workspace ([#5748](https://github.com/helix-editor/helix/pull/5748))
423−
424−Usability improvements:
425−
426−- Remove empty detail section in completion menu when LSP doesn't send details ([#4902](https://github.com/helix-editor/helix/pull/4902))
427−- Pass client information on LSP initialization ([#4904](https://github.com/helix-editor/helix/pull/4904))
428−- Allow specifying environment variables for language servers in language config ([#4004](https://github.com/helix-editor/helix/pull/4004))
429−- Allow detached git worktrees to be recognized as root paths ([#5097](https://github.com/helix-editor/helix/pull/5097))
430−- Improve error message handling for theme loading failures ([#5073](https://github.com/helix-editor/helix/pull/5073))
431−- Print the names of binaries required for LSP/DAP in health-check ([#5195](https://github.com/helix-editor/helix/pull/5195))
432−- Improve sorting in the picker in cases of ties ([#5169](https://github.com/helix-editor/helix/pull/5169))
433−- Add theming for prompt suggestions ([#5104](https://github.com/helix-editor/helix/pull/5104))
434−- Open a file picker when using `:open` on directories ([#2707](https://github.com/helix-editor/helix/pull/2707), [#5278](https://github.com/helix-editor/helix/pull/5278))
435−- Reload language config with `:config-reload` ([#5239](https://github.com/helix-editor/helix/pull/5239), [#5381](https://github.com/helix-editor/helix/pull/5381), [#5431](https://github.com/helix-editor/helix/pull/5431))
436−- Improve indent queries for python when the tree is errored ([#5332](https://github.com/helix-editor/helix/pull/5332))
437−- Picker: Open files without closing the picker with `A-ret` ([#4435](https://github.com/helix-editor/helix/pull/4435))
438−- Allow theming cursors by primary/secondary and by mode ([#5130](https://github.com/helix-editor/helix/pull/5130))
439−- Allow configuration of the minimum width for the line-numbers gutter ([#4724](https://github.com/helix-editor/helix/pull/4724), [#5696](https://github.com/helix-editor/helix/pull/5696))
440−- Use filename completer for `:run-shell-command` command ([#5729](https://github.com/helix-editor/helix/pull/5729))
441−- Surround with line-endings with `ms<ret>` ([#4571](https://github.com/helix-editor/helix/pull/4571))
442−- Hide duplicate symlinks in file pickers ([#5658](https://github.com/helix-editor/helix/pull/5658))
443−- Tabulate buffer picker contents ([#5777](https://github.com/helix-editor/helix/pull/5777))
444−- Add an option to disable LSP ([#4425](https://github.com/helix-editor/helix/pull/4425))
445−- Short-circuit tree-sitter and word object motions ([#5851](https://github.com/helix-editor/helix/pull/5851))
446−- Add exit code to failed command message ([#5898](https://github.com/helix-editor/helix/pull/5898))
447−- Make `m` textobject look for pairs enclosing selections ([#3344](https://github.com/helix-editor/helix/pull/3344))
448−- Negotiate LSP position encoding ([#5894](https://github.com/helix-editor/helix/pull/5894), [a48d1a4](https://github.com/helix-editor/helix/commit/a48d1a4))
449−- Display deprecated LSP completions with strikethrough ([#5932](https://github.com/helix-editor/helix/pull/5932))
450−- Add JSONRPC request ID to failed LSP/DAP request log messages ([#6010](https://github.com/helix-editor/helix/pull/6010), [#6018](https://github.com/helix-editor/helix/pull/6018))
451−- Ignore case when filtering LSP completions ([#6008](https://github.com/helix-editor/helix/pull/6008))
452−- Show current language when no arguments are passed to `:set-language` ([#5895](https://github.com/helix-editor/helix/pull/5895))
453−- Refactor and rewrite all book documentation ([#5534](https://github.com/helix-editor/helix/pull/5534))
454−- Separate diagnostic picker message and code ([#6095](https://github.com/helix-editor/helix/pull/6095))
455−- Add a config option to bypass undercurl detection ([#6253](https://github.com/helix-editor/helix/pull/6253))
456−- Only complete appropriate arguments for typed commands ([#5966](https://github.com/helix-editor/helix/pull/5966))
457−- Discard outdated LSP diagnostics ([3c9d5d0](https://github.com/helix-editor/helix/commit/3c9d5d0))
458−- Discard outdated LSP workspace edits ([b6a4927](https://github.com/helix-editor/helix/commit/b6a4927))
459−- Run shell commands asynchronously ([#6373](https://github.com/helix-editor/helix/pull/6373))
460−- Show diagnostic codes in LSP diagnostic messages ([#6378](https://github.com/helix-editor/helix/pull/6378))
461−- Highlight the current line in a DAP debug session ([#5957](https://github.com/helix-editor/helix/pull/5957))
462−- Hide signature help if it overlaps with the completion menu ([#5523](https://github.com/helix-editor/helix/pull/5523), [7a69c40](https://github.com/helix-editor/helix/commit/7a69c40))
463−
464−Fixes:
465−
466−- Fix behavior of `auto-completion` flag for completion-on-trigger ([#5042](https://github.com/helix-editor/helix/pull/5042))
467−- Reset editor mode when changing buffers ([#5072](https://github.com/helix-editor/helix/pull/5072))
468−- Respect scrolloff settings in mouse movements ([#5255](https://github.com/helix-editor/helix/pull/5255))
469−- Avoid trailing `s` when only one file is opened ([#5189](https://github.com/helix-editor/helix/pull/5189))
470−- Fix erroneous indent between closers of auto-pairs ([#5330](https://github.com/helix-editor/helix/pull/5330))
471−- Expand `~` when parsing file paths in `:open` ([#5329](https://github.com/helix-editor/helix/pull/5329))
472−- Fix theme inheritance for default themes ([#5218](https://github.com/helix-editor/helix/pull/5218))
473−- Fix `extend_line` with a count when the current line(s) are selected ([#5288](https://github.com/helix-editor/helix/pull/5288))
474−- Prompt: Fix autocompletion for paths containing periods ([#5175](https://github.com/helix-editor/helix/pull/5175))
475−- Skip serializing JSONRPC params if params is null ([#5471](https://github.com/helix-editor/helix/pull/5471))
476−- Fix interaction with the `xclip` clipboard provider ([#5426](https://github.com/helix-editor/helix/pull/5426))
477−- Fix undo/redo execution from the command palette ([#5294](https://github.com/helix-editor/helix/pull/5294))
478−- Fix highlighting of non-block cursors ([#5575](https://github.com/helix-editor/helix/pull/5575))
479−- Fix panic when nooping in `join_selections` and `join_selections_space` ([#5423](https://github.com/helix-editor/helix/pull/5423))
480−- Fix selecting a changed file in global search ([#5639](https://github.com/helix-editor/helix/pull/5639))
481−- Fix initial syntax highlight layer sort order ([#5196](https://github.com/helix-editor/helix/pull/5196))
482−- Fix UTF-8 length handling for shellwords ([#5738](https://github.com/helix-editor/helix/pull/5738))
483−- Remove C-j and C-k bindings from the completion menu ([#5070](https://github.com/helix-editor/helix/pull/5070))
484−- Always commit to history when pasting ([#5790](https://github.com/helix-editor/helix/pull/5790))
485−- Properly handle LSP position encoding ([#5711](https://github.com/helix-editor/helix/pull/5711))
486−- Fix infinite loop in `copy_selection_on_prev_line` ([#5888](https://github.com/helix-editor/helix/pull/5888))
487−- Fix completion popup positioning ([#5842](https://github.com/helix-editor/helix/pull/5842))
488−- Fix a panic when uncommenting a line with only a comment token ([#5933](https://github.com/helix-editor/helix/pull/5933))
489−- Fix panic in `goto_window_center` at EOF ([#5987](https://github.com/helix-editor/helix/pull/5987))
490−- Ignore invalid file URIs sent by a language server ([#6000](https://github.com/helix-editor/helix/pull/6000))
491−- Decode LSP URIs for the workspace diagnostics picker ([#6016](https://github.com/helix-editor/helix/pull/6016))
492−- Fix incorrect usages of `tab_width` with `indent_width` ([#5918](https://github.com/helix-editor/helix/pull/5918))
493−- DAP: Send Disconnect if the Terminated event is received ([#5532](https://github.com/helix-editor/helix/pull/5532))
494−- DAP: Validate key and index exist when requesting variables ([#5628](https://github.com/helix-editor/helix/pull/5628))
495−- Check LSP renaming support before prompting for rename text ([#6257](https://github.com/helix-editor/helix/pull/6257))
496−- Fix indent guide rendering ([#6136](https://github.com/helix-editor/helix/pull/6136))
497−- Fix division by zero panic ([#6155](https://github.com/helix-editor/helix/pull/6155))
498−- Fix lacking space panic ([#6109](https://github.com/helix-editor/helix/pull/6109))
499−- Send error replies for malformed and unhandled LSP requests ([#6058](https://github.com/helix-editor/helix/pull/6058))
500−- Fix table column calculations for dynamic pickers ([#5920](https://github.com/helix-editor/helix/pull/5920))
501−- Skip adding jumplist entries for `:<n>` line number previews ([#5751](https://github.com/helix-editor/helix/pull/5751))
502−- Fix completion race conditions ([#6173](https://github.com/helix-editor/helix/pull/6173))
503−- Fix `shrink_selection` with multiple cursors ([#6093](https://github.com/helix-editor/helix/pull/6093))
504−- Fix indentation calculation for lines with mixed tabs/spaces ([#6278](https://github.com/helix-editor/helix/pull/6278))
505−- No-op `client/registerCapability` LSP requests ([#6258](https://github.com/helix-editor/helix/pull/6258))
506−- Send the STOP signal to all processes in the process group ([#3546](https://github.com/helix-editor/helix/pull/3546))
507−- Fix workspace edit client capabilities declaration ([7bf168d](https://github.com/helix-editor/helix/commit/7bf168d))
508−- Fix highlighting in picker results with multiple columns ([#6333](https://github.com/helix-editor/helix/pull/6333))
509−- Canonicalize paths before stripping the current dir as a prefix ([#6290](https://github.com/helix-editor/helix/pull/6290))
510−- Fix truncation behavior for long path names in the file picker ([#6410](https://github.com/helix-editor/helix/pull/6410), [67783dd](https://github.com/helix-editor/helix/commit/67783dd))
511−- Fix theme reloading behavior in `:config-reload` ([ab819d8](https://github.com/helix-editor/helix/commit/ab819d8))
512−
513−Themes:
514−
515−- Update `serika` ([#5038](https://github.com/helix-editor/helix/pull/5038), [#6344](https://github.com/helix-editor/helix/pull/6344))
516−- Update `flatwhite` ([#5036](https://github.com/helix-editor/helix/pull/5036), [#6323](https://github.com/helix-editor/helix/pull/6323))
517−- Update `autumn` ([#5051](https://github.com/helix-editor/helix/pull/5051), [#5397](https://github.com/helix-editor/helix/pull/5397), [#6280](https://github.com/helix-editor/helix/pull/6280), [#6316](https://github.com/helix-editor/helix/pull/6316))
518−- Update `acme` ([#5019](https://github.com/helix-editor/helix/pull/5019), [#5486](https://github.com/helix-editor/helix/pull/5486), [#5488](https://github.com/helix-editor/helix/pull/5488))
519−- Update `gruvbox` themes ([#5066](https://github.com/helix-editor/helix/pull/5066), [#5333](https://github.com/helix-editor/helix/pull/5333), [#5540](https://github.com/helix-editor/helix/pull/5540), [#6285](https://github.com/helix-editor/helix/pull/6285), [#6295](https://github.com/helix-editor/helix/pull/6295))
520−- Update `base16_transparent` ([#5105](https://github.com/helix-editor/helix/pull/5105))
521−- Update `dark_high_contrast` ([#5105](https://github.com/helix-editor/helix/pull/5105))
522−- Update `dracula` ([#5236](https://github.com/helix-editor/helix/pull/5236), [#5627](https://github.com/helix-editor/helix/pull/5627), [#6414](https://github.com/helix-editor/helix/pull/6414))
523−- Update `monokai_pro_spectrum` ([#5250](https://github.com/helix-editor/helix/pull/5250), [#5602](https://github.com/helix-editor/helix/pull/5602))
524−- Update `rose_pine` ([#5267](https://github.com/helix-editor/helix/pull/5267), [#5489](https://github.com/helix-editor/helix/pull/5489), [#6384](https://github.com/helix-editor/helix/pull/6384))
525−- Update `kanagawa` ([#5273](https://github.com/helix-editor/helix/pull/5273), [#5571](https://github.com/helix-editor/helix/pull/5571), [#6085](https://github.com/helix-editor/helix/pull/6085))
526−- Update `emacs` ([#5334](https://github.com/helix-editor/helix/pull/5334))
527−- Add `github` themes ([#5353](https://github.com/helix-editor/helix/pull/5353), [efeec12](https://github.com/helix-editor/helix/commit/efeec12))
528− - Dark themes: `github_dark`, `github_dark_colorblind`, `github_dark_dimmed`, `github_dark_high_contrast`, `github_dark_tritanopia`
529− - Light themes: `github_light`, `github_light_colorblind`, `github_light_dimmed`, `github_light_high_contrast`, `github_light_tritanopia`
530−- Update `solarized` variants ([#5445](https://github.com/helix-editor/helix/pull/5445), [#6327](https://github.com/helix-editor/helix/pull/6327))
531−- Update `catppuccin` variants ([#5404](https://github.com/helix-editor/helix/pull/5404), [#6107](https://github.com/helix-editor/helix/pull/6107), [#6269](https://github.com/helix-editor/helix/pull/6269), [#6464](https://github.com/helix-editor/helix/pull/6464))
532−- Use curly underlines in built-in themes ([#5419](https://github.com/helix-editor/helix/pull/5419))
533−- Update `zenburn` ([#5573](https://github.com/helix-editor/helix/pull/5573))
534−- Rewrite `snazzy` ([#3971](https://github.com/helix-editor/helix/pull/3971))
535−- Add `monokai_aqua` ([#5578](https://github.com/helix-editor/helix/pull/5578))
536−- Add `markup.strikethrough` to existing themes ([#5619](https://github.com/helix-editor/helix/pull/5619))
537−- Update `sonokai` ([#5440](https://github.com/helix-editor/helix/pull/5440))
538−- Update `onedark` ([#5755](https://github.com/helix-editor/helix/pull/5755))
539−- Add `ayu_evolve` ([#5638](https://github.com/helix-editor/helix/pull/5638), [#6028](https://github.com/helix-editor/helix/pull/6028), [#6225](https://github.com/helix-editor/helix/pull/6225))
540−- Add `jellybeans` ([#5719](https://github.com/helix-editor/helix/pull/5719))
541−- Update `fleet_dark` ([#5605](https://github.com/helix-editor/helix/pull/5605), [#6266](https://github.com/helix-editor/helix/pull/6266), [#6324](https://github.com/helix-editor/helix/pull/6324), [#6375](https://github.com/helix-editor/helix/pull/6375))
542−- Add `darcula-solid` ([#5778](https://github.com/helix-editor/helix/pull/5778))
543−- Remove text background from monokai themes ([#6009](https://github.com/helix-editor/helix/pull/6009))
544−- Update `pop_dark` ([#5992](https://github.com/helix-editor/helix/pull/5992), [#6208](https://github.com/helix-editor/helix/pull/6208), [#6227](https://github.com/helix-editor/helix/pull/6227), [#6292](https://github.com/helix-editor/helix/pull/6292))
545−- Add `everblush` ([#6086](https://github.com/helix-editor/helix/pull/6086))
546−- Add `adwaita-dark` ([#6042](https://github.com/helix-editor/helix/pull/6042), [#6342](https://github.com/helix-editor/helix/pull/6342))
547−- Update `papercolor` ([#6162](https://github.com/helix-editor/helix/pull/6162))
548−- Update `onelight` ([#6192](https://github.com/helix-editor/helix/pull/6192), [#6276](https://github.com/helix-editor/helix/pull/6276))
549−- Add `molokai` ([#6260](https://github.com/helix-editor/helix/pull/6260))
550−- Update `ayu` variants ([#6329](https://github.com/helix-editor/helix/pull/6329))
551−- Update `tokyonight` variants ([#6349](https://github.com/helix-editor/helix/pull/6349))
552−- Update `nord` variants ([#6376](https://github.com/helix-editor/helix/pull/6376))
553−
554−New languages:
555−
556−- BibTeX ([#5064](https://github.com/helix-editor/helix/pull/5064))
557−- Mermaid.js ([#5147](https://github.com/helix-editor/helix/pull/5147))
558−- Crystal ([#4993](https://github.com/helix-editor/helix/pull/4993), [#5205](https://github.com/helix-editor/helix/pull/5205))
559−- MATLAB/Octave ([#5192](https://github.com/helix-editor/helix/pull/5192))
560−- `tfvars` (uses HCL) ([#5396](https://github.com/helix-editor/helix/pull/5396))
561−- Ponylang ([#5416](https://github.com/helix-editor/helix/pull/5416))
562−- DHall ([1f6809c](https://github.com/helix-editor/helix/commit/1f6809c))
563−- Sagemath ([#5649](https://github.com/helix-editor/helix/pull/5649))
564−- MSBuild ([#5793](https://github.com/helix-editor/helix/pull/5793))
565−- pem ([#5797](https://github.com/helix-editor/helix/pull/5797))
566−- passwd ([#4959](https://github.com/helix-editor/helix/pull/4959))
567−- hosts ([#4950](https://github.com/helix-editor/helix/pull/4950), [#5914](https://github.com/helix-editor/helix/pull/5914))
568−- uxntal ([#6047](https://github.com/helix-editor/helix/pull/6047))
569−- Yuck ([#6064](https://github.com/helix-editor/helix/pull/6064), [#6242](https://github.com/helix-editor/helix/pull/6242))
570−- GNU gettext PO ([#5996](https://github.com/helix-editor/helix/pull/5996))
571−- Sway ([#6023](https://github.com/helix-editor/helix/pull/6023))
572−- NASM ([#6068](https://github.com/helix-editor/helix/pull/6068))
573−- PRQL ([#6126](https://github.com/helix-editor/helix/pull/6126))
574−- reStructuredText ([#6180](https://github.com/helix-editor/helix/pull/6180))
575−- Smithy ([#6370](https://github.com/helix-editor/helix/pull/6370))
576−- VHDL ([#5826](https://github.com/helix-editor/helix/pull/5826))
577−- Rego (OpenPolicy Agent) ([#6415](https://github.com/helix-editor/helix/pull/6415))
578−- Nim ([#6123](https://github.com/helix-editor/helix/pull/6123))
579−
580−Updated languages and queries:
581−
582−- Use diff syntax for patch files ([#5085](https://github.com/helix-editor/helix/pull/5085))
583−- Add Haskell textobjects ([#5061](https://github.com/helix-editor/helix/pull/5061))
584−- Fix commonlisp configuration ([#5091](https://github.com/helix-editor/helix/pull/5091))
585−- Update Scheme ([bae890d](https://github.com/helix-editor/helix/commit/bae890d))
586−- Add indent queries for Bash ([#5149](https://github.com/helix-editor/helix/pull/5149))
587−- Recognize `c++` as a C++ extension ([#5183](https://github.com/helix-editor/helix/pull/5183))
588−- Enable HTTP server in `metals` (Scala) config ([#5551](https://github.com/helix-editor/helix/pull/5551))
589−- Change V-lang language server to `v ls` from `vls` ([#5677](https://github.com/helix-editor/helix/pull/5677))
590−- Inject comment grammar into Nix ([#5208](https://github.com/helix-editor/helix/pull/5208))
591−- Update Rust highlights ([#5238](https://github.com/helix-editor/helix/pull/5238), [#5349](https://github.com/helix-editor/helix/pull/5349))
592−- Fix HTML injection within Markdown ([#5265](https://github.com/helix-editor/helix/pull/5265))
593−- Fix comment token for godot ([#5276](https://github.com/helix-editor/helix/pull/5276))
594−- Expand injections for Vue ([#5268](https://github.com/helix-editor/helix/pull/5268))
595−- Add `.bash_aliases` as a Bash file-type ([#5347](https://github.com/helix-editor/helix/pull/5347))
596−- Fix comment token for sshclientconfig ([#5351](https://github.com/helix-editor/helix/pull/5351))
597−- Update Prisma ([#5417](https://github.com/helix-editor/helix/pull/5417))
598−- Update C++ ([#5457](https://github.com/helix-editor/helix/pull/5457))
599−- Add more file-types for Python ([#5593](https://github.com/helix-editor/helix/pull/5593))
600−- Update tree-sitter-scala ([#5576](https://github.com/helix-editor/helix/pull/5576))
601−- Add an injection regex for Lua ([#5606](https://github.com/helix-editor/helix/pull/5606))
602−- Add `build.gradle` to java roots configuration ([#5641](https://github.com/helix-editor/helix/pull/5641))
603−- Add Hub PR files to markdown file-types ([#5634](https://github.com/helix-editor/helix/pull/5634))
604−- Add an external formatter configuration for Cue ([#5679](https://github.com/helix-editor/helix/pull/5679))
605−- Add injections for builders and writers to Nix ([#5629](https://github.com/helix-editor/helix/pull/5629))
606−- Update tree-sitter-xml to fix whitespace parsing ([#5685](https://github.com/helix-editor/helix/pull/5685))
607−- Add `Justfile` to the make file-types configuration ([#5687](https://github.com/helix-editor/helix/pull/5687))
608−- Update tree-sitter-sql and highlight queries ([#5683](https://github.com/helix-editor/helix/pull/5683), [#5772](https://github.com/helix-editor/helix/pull/5772))
609−- Use the bash grammar and queries for env language ([#5720](https://github.com/helix-editor/helix/pull/5720))
610−- Add podspec files to ruby file-types ([#5811](https://github.com/helix-editor/helix/pull/5811))
611−- Recognize `.C` and `.H` file-types as C++ ([#5808](https://github.com/helix-editor/helix/pull/5808))
612−- Recognize plist and mobileconfig files as XML ([#5863](https://github.com/helix-editor/helix/pull/5863))
613−- Fix `select` indentation in Go ([#5713](https://github.com/helix-editor/helix/pull/5713))
614−- Check for external file modifications when writing ([#5805](https://github.com/helix-editor/helix/pull/5805))
615−- Recognize containerfiles as dockerfile syntax ([#5873](https://github.com/helix-editor/helix/pull/5873))
616−- Update godot grammar and queries ([#5944](https://github.com/helix-editor/helix/pull/5944), [#6186](https://github.com/helix-editor/helix/pull/6186))
617−- Improve DHall highlights ([#5959](https://github.com/helix-editor/helix/pull/5959))
618−- Recognize `.env.dist` and `source.env` as env language ([#6003](https://github.com/helix-editor/helix/pull/6003))
619−- Update tree-sitter-git-rebase ([#6030](https://github.com/helix-editor/helix/pull/6030), [#6094](https://github.com/helix-editor/helix/pull/6094))
620−- Improve SQL highlights ([#6041](https://github.com/helix-editor/helix/pull/6041))
621−- Improve markdown highlights and inject LaTeX ([#6100](https://github.com/helix-editor/helix/pull/6100))
622−- Add textobject queries for Elm ([#6084](https://github.com/helix-editor/helix/pull/6084))
623−- Recognize graphql schema file type ([#6159](https://github.com/helix-editor/helix/pull/6159))
624−- Improve highlighting in comments ([#6143](https://github.com/helix-editor/helix/pull/6143))
625−- Improve highlighting for JavaScript/TypeScript/ECMAScript languages ([#6205](https://github.com/helix-editor/helix/pull/6205))
626−- Improve PHP highlights ([#6203](https://github.com/helix-editor/helix/pull/6203), [#6250](https://github.com/helix-editor/helix/pull/6250), [#6299](https://github.com/helix-editor/helix/pull/6299))
627−- Improve Go highlights ([#6204](https://github.com/helix-editor/helix/pull/6204))
628−- Highlight unchecked sqlx functions as SQL in Rust ([#6256](https://github.com/helix-editor/helix/pull/6256))
629−- Improve Erlang highlights ([cdd6c8d](https://github.com/helix-editor/helix/commit/cdd6c8d))
630−- Improve Nix highlights ([fb4d703](https://github.com/helix-editor/helix/commit/fb4d703))
631−- Improve gdscript highlights ([#6311](https://github.com/helix-editor/helix/pull/6311))
632−- Improve Vlang highlights ([#6279](https://github.com/helix-editor/helix/pull/6279))
633−- Improve Makefile highlights ([#6339](https://github.com/helix-editor/helix/pull/6339))
634−- Remove auto-pair for `'` in OCaml ([#6381](https://github.com/helix-editor/helix/pull/6381))
635−- Fix indents in switch statements in ECMA languages ([#6369](https://github.com/helix-editor/helix/pull/6369))
636−- Recognize xlb and storyboard file-types as XML ([#6407](https://github.com/helix-editor/helix/pull/6407))
637−- Recognize cts and mts file-types as TypeScript ([#6424](https://github.com/helix-editor/helix/pull/6424))
638−- Recognize SVG file-type as XML ([#6431](https://github.com/helix-editor/helix/pull/6431))
639−- Add theme scopes for (un)checked list item markup scopes ([#6434](https://github.com/helix-editor/helix/pull/6434))
640−- Update git commit grammar and add the comment textobject ([#6439](https://github.com/helix-editor/helix/pull/6439), [#6493](https://github.com/helix-editor/helix/pull/6493))
641−- Recognize ARB file-type as JSON ([#6452](https://github.com/helix-editor/helix/pull/6452))
642−- Inject markdown into markdown strings in Julia ([#6489](https://github.com/helix-editor/helix/pull/6489))
643−
644−Packaging:
645−
646−- Fix Nix flake devShell for darwin hosts ([#5368](https://github.com/helix-editor/helix/pull/5368))
647−- Add Appstream metadata file to `contrib/` ([#5643](https://github.com/helix-editor/helix/pull/5643))
648−- Increase the MSRV to 1.65 ([#5570](https://github.com/helix-editor/helix/pull/5570), [#6185](https://github.com/helix-editor/helix/pull/6185))
649−- Expose the Nix flake's `wrapper` ([#5994](https://github.com/helix-editor/helix/pull/5994))
650−
651−# 22.12 (2022-12-06)
652−
653−This is a great big release filled with changes from a 99 contributors. A big _thank you_ to you all!
654−
655−As usual, the following is a summary of each of the changes since the last release.
656−For the full log, check out the [git log](https://github.com/helix-editor/helix/compare/22.08.1..22.12).
657−
658−Breaking changes:
659−
660−- Remove readline-like navigation bindings from the default insert mode keymap ([e12690e](https://github.com/helix-editor/helix/commit/e12690e), [#3811](https://github.com/helix-editor/helix/pull/3811), [#3827](https://github.com/helix-editor/helix/pull/3827), [#3915](https://github.com/helix-editor/helix/pull/3915), [#4088](https://github.com/helix-editor/helix/pull/4088))
661−- Rename `append_to_line` as `insert_at_line_end` and `prepend_to_line` as `insert_at_line_start` ([#3753](https://github.com/helix-editor/helix/pull/3753))
662−- Swap diagnostic picker and debug mode bindings in the space keymap ([#4229](https://github.com/helix-editor/helix/pull/4229))
663−- Select newly inserted text on paste or from shell commands ([#4458](https://github.com/helix-editor/helix/pull/4458), [#4608](https://github.com/helix-editor/helix/pull/4608), [#4619](https://github.com/helix-editor/helix/pull/4619), [#4824](https://github.com/helix-editor/helix/pull/4824))
664−- Select newly inserted surrounding characters on `ms<char>` ([#4752](https://github.com/helix-editor/helix/pull/4752))
665−- Exit select-mode after executing `replace_*` commands ([#4554](https://github.com/helix-editor/helix/pull/4554))
666−- Exit select-mode after executing surround commands ([#4858](https://github.com/helix-editor/helix/pull/4858))
667−- Change tree-sitter text-object keys ([#3782](https://github.com/helix-editor/helix/pull/3782))
668−- Rename `fleetish` theme to `fleet_dark` ([#4997](https://github.com/helix-editor/helix/pull/4997))
669−
670−Features:
671−
672−- Bufferline ([#2759](https://github.com/helix-editor/helix/pull/2759))
673−- Support underline styles and colors ([#4061](https://github.com/helix-editor/helix/pull/4061), [98c121c](https://github.com/helix-editor/helix/commit/98c121c))
674−- Inheritance for themes ([#3067](https://github.com/helix-editor/helix/pull/3067), [#4096](https://github.com/helix-editor/helix/pull/4096))
675−- Cursorcolumn ([#4084](https://github.com/helix-editor/helix/pull/4084))
676−- Overhauled system for writing files and quiting ([#2267](https://github.com/helix-editor/helix/pull/2267), [#4397](https://github.com/helix-editor/helix/pull/4397))
677−- Autosave when terminal loses focus ([#3178](https://github.com/helix-editor/helix/pull/3178))
678−- Use OSC52 as a fallback for the system clipboard ([#3220](https://github.com/helix-editor/helix/pull/3220))
679−- Show git diffs in the gutter ([#3890](https://github.com/helix-editor/helix/pull/3890), [#5012](https://github.com/helix-editor/helix/pull/5012), [#4995](https://github.com/helix-editor/helix/pull/4995))
680−- Add a logo ([dc1ec56](https://github.com/helix-editor/helix/commit/dc1ec56))
681−- Multi-cursor completion ([#4496](https://github.com/helix-editor/helix/pull/4496))
682−
683−Commands:
684−
685−- `file_picker_in_current_directory` (`<space>F`) ([#3701](https://github.com/helix-editor/helix/pull/3701))
686−- `:lsp-restart` to restart the current document's language server ([#3435](https://github.com/helix-editor/helix/pull/3435), [#3972](https://github.com/helix-editor/helix/pull/3972))
687−- `join_selections_space` (`A-j`) which joins selections and selects the joining whitespace ([#3549](https://github.com/helix-editor/helix/pull/3549))
688−- `:update` to write the current file if it is modified ([#4426](https://github.com/helix-editor/helix/pull/4426))
689−- `:lsp-workspace-command` for picking LSP commands to execute ([#3140](https://github.com/helix-editor/helix/pull/3140))
690−- `extend_prev_word_end` - the extend variant for `move_prev_word_end` ([7468fa2](https://github.com/helix-editor/helix/commit/7468fa2))
691−- `make_search_word_bounded` which adds regex word boundaries to the current search register value ([#4322](https://github.com/helix-editor/helix/pull/4322))
692−- `:reload-all` - `:reload` for all open buffers ([#4663](https://github.com/helix-editor/helix/pull/4663), [#4901](https://github.com/helix-editor/helix/pull/4901))
693−- `goto_next_change` (`]g`), `goto_prev_change` (`[g`), `goto_first_change` (`[G`), `goto_last_change` (`]G`) textobjects for jumping between VCS changes ([#4650](https://github.com/helix-editor/helix/pull/4650))
694−
695−Usability improvements and fixes:
696−
697−- Don't log 'LSP not defined' errors in the logfile ([1caba2d](https://github.com/helix-editor/helix/commit/1caba2d))
698−- Look for the external formatter program before invoking it ([#3670](https://github.com/helix-editor/helix/pull/3670))
699−- Don't send LSP didOpen events for documents without URLs ([44b4479](https://github.com/helix-editor/helix/commit/44b4479))
700−- Fix off-by-one in `extend_line_above` command ([#3689](https://github.com/helix-editor/helix/pull/3689))
701−- Use the original scroll offset when opening a split ([1acdfaa](https://github.com/helix-editor/helix/commit/1acdfaa))
702−- Handle auto-formatting failures and save the file anyway ([#3684](https://github.com/helix-editor/helix/pull/3684))
703−- Ensure the cursor is in view after `:reflow` ([#3733](https://github.com/helix-editor/helix/pull/3733))
704−- Add default rulers and reflow config for git commit messages ([#3738](https://github.com/helix-editor/helix/pull/3738))
705−- Improve grammar fetching and building output ([#3773](https://github.com/helix-editor/helix/pull/3773))
706−- Add a `text` language to language completion ([cc47d3f](https://github.com/helix-editor/helix/commit/cc47d3f))
707−- Improve error handling for `:set-language` ([e8add6f](https://github.com/helix-editor/helix/commit/e8add6f))
708−- Improve error handling for `:config-reload` ([#3668](https://github.com/helix-editor/helix/pull/3668))
709−- Improve error handling when passing improper ranges to syntax highlighting ([#3826](https://github.com/helix-editor/helix/pull/3826))
710−- Render `<code>` tags as raw markup in markdown ([#3425](https://github.com/helix-editor/helix/pull/3425))
711−- Remove border around the LSP code-actions popup ([#3444](https://github.com/helix-editor/helix/pull/3444))
712−- Canonicalize the path to the runtime directory ([#3794](https://github.com/helix-editor/helix/pull/3794))
713−- Add a `themelint` xtask for linting themes ([#3234](https://github.com/helix-editor/helix/pull/3234))
714−- Re-sort LSP diagnostics after applying transactions ([#3895](https://github.com/helix-editor/helix/pull/3895), [#4319](https://github.com/helix-editor/helix/pull/4319))
715−- Add a command-line flag to specify the log file ([#3807](https://github.com/helix-editor/helix/pull/3807))
716−- Track source and tag information in LSP diagnostics ([#3898](https://github.com/helix-editor/helix/pull/3898), [1df32c9](https://github.com/helix-editor/helix/commit/1df32c9))
717−- Fix theme returning to normal when exiting the `:theme` completion ([#3644](https://github.com/helix-editor/helix/pull/3644))
718−- Improve error messages for invalid commands in the keymap ([#3931](https://github.com/helix-editor/helix/pull/3931))
719−- Deduplicate regexs in `search_selection` command ([#3941](https://github.com/helix-editor/helix/pull/3941))
720−- Split the finding of LSP root and config roots ([#3929](https://github.com/helix-editor/helix/pull/3929))
721−- Ensure that the cursor is within view after auto-formatting ([#4047](https://github.com/helix-editor/helix/pull/4047))
722−- Add pseudo-pending to commands with on-next-key callbacks ([#4062](https://github.com/helix-editor/helix/pull/4062), [#4077](https://github.com/helix-editor/helix/pull/4077))
723−- Add live preview to `:goto` ([#2982](https://github.com/helix-editor/helix/pull/2982))
724−- Show regex compilation failure in a popup ([#3049](https://github.com/helix-editor/helix/pull/3049))
725−- Add 'cycled to end' and 'no more matches' for search ([#3176](https://github.com/helix-editor/helix/pull/3176), [#4101](https://github.com/helix-editor/helix/pull/4101))
726−- Add extending behavior to tree-sitter textobjects ([#3266](https://github.com/helix-editor/helix/pull/3266))
727−- Add `ui.gutter.selected` option for themes ([#3303](https://github.com/helix-editor/helix/pull/3303))
728−- Make statusline mode names configurable ([#3311](https://github.com/helix-editor/helix/pull/3311))
729−- Add a statusline element for total line count ([#3960](https://github.com/helix-editor/helix/pull/3960))
730−- Add extending behavior to `goto_window_*` commands ([#3985](https://github.com/helix-editor/helix/pull/3985))
731−- Fix a panic in signature help when the preview is too large ([#4030](https://github.com/helix-editor/helix/pull/4030))
732−- Add command names to the command palette ([#4071](https://github.com/helix-editor/helix/pull/4071), [#4223](https://github.com/helix-editor/helix/pull/4223), [#4495](https://github.com/helix-editor/helix/pull/4495))
733−- Find the LSP workspace root from the current document's path ([#3553](https://github.com/helix-editor/helix/pull/3553))
734−- Add an option to skip indent-guide levels ([#3819](https://github.com/helix-editor/helix/pull/3819), [2c36e33](https://github.com/helix-editor/helix/commit/2c36e33))
735−- Change focus to modified docs on quit ([#3872](https://github.com/helix-editor/helix/pull/3872))
736−- Respond to `USR1` signal by reloading config ([#3952](https://github.com/helix-editor/helix/pull/3952))
737−- Exit gracefully when the close operation fails ([#4081](https://github.com/helix-editor/helix/pull/4081))
738−- Fix goto/view center mismatch ([#4135](https://github.com/helix-editor/helix/pull/4135))
739−- Highlight the current file picker document on idle-timeout ([#3172](https://github.com/helix-editor/helix/pull/3172), [a85e386](https://github.com/helix-editor/helix/commit/a85e386))
740−- Apply transactions to jumplist selections ([#4186](https://github.com/helix-editor/helix/pull/4186), [#4227](https://github.com/helix-editor/helix/pull/4227), [#4733](https://github.com/helix-editor/helix/pull/4733), [#4865](https://github.com/helix-editor/helix/pull/4865), [#4912](https://github.com/helix-editor/helix/pull/4912), [#4965](https://github.com/helix-editor/helix/pull/4965), [#4981](https://github.com/helix-editor/helix/pull/4981))
741−- Use space as a separator for fuzzy matcher ([#3969](https://github.com/helix-editor/helix/pull/3969))
742−- Overlay all diagnostics with highest severity on top ([#4113](https://github.com/helix-editor/helix/pull/4113))
743−- Avoid re-parsing unmodified tree-sitter injections ([#4146](https://github.com/helix-editor/helix/pull/4146))
744−- Add extending captures for indentation, re-enable python indentation ([#3382](https://github.com/helix-editor/helix/pull/3382), [3e84434](https://github.com/helix-editor/helix/commit/3e84434))
745−- Only allow either `--vsplit` or `--hsplit` CLI flags at once ([#4202](https://github.com/helix-editor/helix/pull/4202))
746−- Fix append cursor location when selection anchor is at the end of the document ([#4147](https://github.com/helix-editor/helix/pull/4147))
747−- Improve selection yanking message ([#4275](https://github.com/helix-editor/helix/pull/4275))
748−- Log failures to load tree-sitter grammars as errors ([#4315](https://github.com/helix-editor/helix/pull/4315))
749−- Fix rendering of lines longer than 65,536 columns ([#4172](https://github.com/helix-editor/helix/pull/4172))
750−- Skip searching `.git` in `global_search` ([#4334](https://github.com/helix-editor/helix/pull/4334))
751−- Display tree-sitter scopes in a popup ([#4337](https://github.com/helix-editor/helix/pull/4337))
752−- Fix deleting a word from the end of the buffer ([#4328](https://github.com/helix-editor/helix/pull/4328))
753−- Pretty print the syntax tree in `:tree-sitter-subtree` ([#4295](https://github.com/helix-editor/helix/pull/4295), [#4606](https://github.com/helix-editor/helix/pull/4606))
754−- Allow specifying suffixes for file-type detection ([#2455](https://github.com/helix-editor/helix/pull/2455), [#4414](https://github.com/helix-editor/helix/pull/4414))
755−- Fix multi-byte auto-pairs ([#4024](https://github.com/helix-editor/helix/pull/4024))
756−- Improve sort scoring for LSP code-actions and completions ([#4134](https://github.com/helix-editor/helix/pull/4134))
757−- Fix the handling of quotes within shellwords ([#4098](https://github.com/helix-editor/helix/pull/4098))
758−- Fix `delete_word_backward` and `delete_word_forward` on newlines ([#4392](https://github.com/helix-editor/helix/pull/4392))
759−- Fix 'no entry found for key' crash on `:write-all` ([#4384](https://github.com/helix-editor/helix/pull/4384))
760−- Remove lowercase requirement for tree-sitter grammars ([#4346](https://github.com/helix-editor/helix/pull/4346))
761−- Resolve LSP completion items on idle-timeout ([#4406](https://github.com/helix-editor/helix/pull/4406), [#4797](https://github.com/helix-editor/helix/pull/4797))
762−- Render diagnostics in the file picker preview ([#4324](https://github.com/helix-editor/helix/pull/4324))
763−- Fix terminal freezing on `shell_insert_output` ([#4156](https://github.com/helix-editor/helix/pull/4156))
764−- Allow use of the count in the repeat operator (`.`) ([#4450](https://github.com/helix-editor/helix/pull/4450))
765−- Show the current theme name on `:theme` with no arguments ([#3740](https://github.com/helix-editor/helix/pull/3740))
766−- Fix rendering in very large terminals ([#4318](https://github.com/helix-editor/helix/pull/4318))
767−- Sort LSP preselected items to the top of the completion menu ([#4480](https://github.com/helix-editor/helix/pull/4480))
768−- Trim braces and quotes from paths in goto-file ([#4370](https://github.com/helix-editor/helix/pull/4370))
769−- Prevent automatic signature help outside of insert mode ([#4456](https://github.com/helix-editor/helix/pull/4456))
770−- Fix freezes with external programs that process stdin and stdout concurrently ([#4180](https://github.com/helix-editor/helix/pull/4180))
771−- Make `scroll` aware of tabs and wide characters ([#4519](https://github.com/helix-editor/helix/pull/4519))
772−- Correctly handle escaping in `command_mode` completion ([#4316](https://github.com/helix-editor/helix/pull/4316), [#4587](https://github.com/helix-editor/helix/pull/4587), [#4632](https://github.com/helix-editor/helix/pull/4632))
773−- Fix `delete_char_backward` for paired characters ([#4558](https://github.com/helix-editor/helix/pull/4558))
774−- Fix crash from two windows editing the same document ([#4570](https://github.com/helix-editor/helix/pull/4570))
775−- Fix pasting from the blackhole register ([#4497](https://github.com/helix-editor/helix/pull/4497))
776−- Support LSP insertReplace completion items ([1312682](https://github.com/helix-editor/helix/commit/1312682))
777−- Dynamically resize the line number gutter width ([#3469](https://github.com/helix-editor/helix/pull/3469))
778−- Fix crash for unknown completion item kinds ([#4658](https://github.com/helix-editor/helix/pull/4658))
779−- Re-enable `format_selections` for single selection ranges ([d4f5cab](https://github.com/helix-editor/helix/commit/d4f5cab))
780−- Limit the number of in-progress tree-sitter query matches ([#4707](https://github.com/helix-editor/helix/pull/4707), [#4830](https://github.com/helix-editor/helix/pull/4830))
781−- Use the special `#` register with `increment`/`decrement` to change by range number ([#4418](https://github.com/helix-editor/helix/pull/4418))
782−- Add a statusline element to show number of selected chars ([#4682](https://github.com/helix-editor/helix/pull/4682))
783−- Add a statusline element showing global LSP diagnostic warning and error counts ([#4569](https://github.com/helix-editor/helix/pull/4569))
784−- Add a scrollbar to popups ([#4449](https://github.com/helix-editor/helix/pull/4449))
785−- Prefer shorter matches in fuzzy matcher scoring ([#4698](https://github.com/helix-editor/helix/pull/4698))
786−- Use key-sequence format for command palette keybinds ([#4712](https://github.com/helix-editor/helix/pull/4712))
787−- Remove prefix filtering from autocompletion menu ([#4578](https://github.com/helix-editor/helix/pull/4578))
788−- Focus on the parent buffer when closing a split ([#4766](https://github.com/helix-editor/helix/pull/4766))
789−- Handle language server termination ([#4797](https://github.com/helix-editor/helix/pull/4797), [#4852](https://github.com/helix-editor/helix/pull/4852))
790−- Allow `r`/`t`/`f` to work on tab characters ([#4817](https://github.com/helix-editor/helix/pull/4817))
791−- Show a preview for scratch buffers in the buffer picker ([#3454](https://github.com/helix-editor/helix/pull/3454))
792−- Set a limit of entries in the jumplist ([#4750](https://github.com/helix-editor/helix/pull/4750))
793−- Re-use shell outputs when inserting or appending shell output ([#3465](https://github.com/helix-editor/helix/pull/3465))
794−- Check LSP server provider capabilities ([#3554](https://github.com/helix-editor/helix/pull/3554))
795−- Improve tree-sitter parsing performance on files with many language layers ([#4716](https://github.com/helix-editor/helix/pull/4716))
796−- Move indentation to the next line when using `<ret>` on a line with only whitespace ([#4854](https://github.com/helix-editor/helix/pull/4854))
797−- Remove selections for closed views from all documents ([#4888](https://github.com/helix-editor/helix/pull/4888))
798−- Improve performance of the `:reload` command ([#4457](https://github.com/helix-editor/helix/pull/4457))
799−- Properly handle media keys ([#4887](https://github.com/helix-editor/helix/pull/4887))
800−- Support LSP diagnostic data field ([#4935](https://github.com/helix-editor/helix/pull/4935))
801−- Handle C-i keycode as tab ([#4961](https://github.com/helix-editor/helix/pull/4961))
802−- Fix view alignment for jumplist picker jumps ([#3743](https://github.com/helix-editor/helix/pull/3743))
803−- Use OSC52 for tmux clipboard provider ([#5027](https://github.com/helix-editor/helix/pull/5027))
804−
805−Themes:
806−
807−- Add `varua` ([#3610](https://github.com/helix-editor/helix/pull/3610), [#4964](https://github.com/helix-editor/helix/pull/4964))
808−- Update `boo_berry` ([#3653](https://github.com/helix-editor/helix/pull/3653))
809−- Add `rasmus` ([#3728](https://github.com/helix-editor/helix/pull/3728))
810−- Add `papercolor_dark` ([#3742](https://github.com/helix-editor/helix/pull/3742))
811−- Update `monokai_pro_spectrum` ([#3814](https://github.com/helix-editor/helix/pull/3814))
812−- Update `nord` ([#3792](https://github.com/helix-editor/helix/pull/3792))
813−- Update `fleetish` ([#3844](https://github.com/helix-editor/helix/pull/3844), [#4487](https://github.com/helix-editor/helix/pull/4487), [#4813](https://github.com/helix-editor/helix/pull/4813))
814−- Update `flatwhite` ([#3843](https://github.com/helix-editor/helix/pull/3843))
815−- Add `darcula` ([#3739](https://github.com/helix-editor/helix/pull/3739))
816−- Update `papercolor` ([#3938](https://github.com/helix-editor/helix/pull/3938), [#4317](https://github.com/helix-editor/helix/pull/4317))
817−- Add bufferline colors to multiple themes ([#3881](https://github.com/helix-editor/helix/pull/3881))
818−- Add `gruvbox_dark_hard` ([#3948](https://github.com/helix-editor/helix/pull/3948))
819−- Add `onedarker` ([#3980](https://github.com/helix-editor/helix/pull/3980), [#4060](https://github.com/helix-editor/helix/pull/4060))
820−- Add `dark_high_contrast` ([#3312](https://github.com/helix-editor/helix/pull/3312))
821−- Update `bogster` ([#4121](https://github.com/helix-editor/helix/pull/4121), [#4264](https://github.com/helix-editor/helix/pull/4264))
822−- Update `sonokai` ([#4089](https://github.com/helix-editor/helix/pull/4089))
823−- Update `ayu_*` themes ([#4140](https://github.com/helix-editor/helix/pull/4140), [#4109](https://github.com/helix-editor/helix/pull/4109), [#4662](https://github.com/helix-editor/helix/pull/4662), [#4764](https://github.com/helix-editor/helix/pull/4764))
824−- Update `everforest` ([#3998](https://github.com/helix-editor/helix/pull/3998))
825−- Update `monokai_pro_octagon` ([#4247](https://github.com/helix-editor/helix/pull/4247))
826−- Add `heisenberg` ([#4209](https://github.com/helix-editor/helix/pull/4209))
827−- Add `bogster_light` ([#4265](https://github.com/helix-editor/helix/pull/4265))
828−- Update `pop-dark` ([#4323](https://github.com/helix-editor/helix/pull/4323))
829−- Update `rose_pine` ([#4221](https://github.com/helix-editor/helix/pull/4221))
830−- Add `kanagawa` ([#4300](https://github.com/helix-editor/helix/pull/4300))
831−- Add `hex_steel`, `hex_toxic` and `hex_lavendar` ([#4367](https://github.com/helix-editor/helix/pull/4367), [#4990](https://github.com/helix-editor/helix/pull/4990))
832−- Update `tokyonight` and `tokyonight_storm` ([#4415](https://github.com/helix-editor/helix/pull/4415))
833−- Update `gruvbox` ([#4626](https://github.com/helix-editor/helix/pull/4626))
834−- Update `dark_plus` ([#4661](https://github.com/helix-editor/helix/pull/4661), [#4678](https://github.com/helix-editor/helix/pull/4678))
835−- Add `zenburn` ([#4613](https://github.com/helix-editor/helix/pull/4613), [#4977](https://github.com/helix-editor/helix/pull/4977))
836−- Update `monokai_pro` ([#4789](https://github.com/helix-editor/helix/pull/4789))
837−- Add `mellow` ([#4770](https://github.com/helix-editor/helix/pull/4770))
838−- Add `nightfox` ([#4769](https://github.com/helix-editor/helix/pull/4769), [#4966](https://github.com/helix-editor/helix/pull/4966))
839−- Update `doom_acario_dark` ([#4979](https://github.com/helix-editor/helix/pull/4979))
840−- Update `autumn` ([#4996](https://github.com/helix-editor/helix/pull/4996))
841−- Update `acme` ([#4999](https://github.com/helix-editor/helix/pull/4999))
842−- Update `nord_light` ([#4999](https://github.com/helix-editor/helix/pull/4999))
843−- Update `serika_*` ([#5015](https://github.com/helix-editor/helix/pull/5015))
844−
845−LSP configurations:
846−
847−- Switch to `openscad-lsp` for OpenScad ([#3750](https://github.com/helix-editor/helix/pull/3750))
848−- Support Jsonnet ([#3748](https://github.com/helix-editor/helix/pull/3748))
849−- Support Markdown ([#3499](https://github.com/helix-editor/helix/pull/3499))
850−- Support Bass ([#3771](https://github.com/helix-editor/helix/pull/3771))
851−- Set roots configuration for Elixir and HEEx ([#3917](https://github.com/helix-editor/helix/pull/3917), [#3959](https://github.com/helix-editor/helix/pull/3959))
852−- Support Purescript ([#4242](https://github.com/helix-editor/helix/pull/4242))
853−- Set roots configuration for Julia ([#4361](https://github.com/helix-editor/helix/pull/4361))
854−- Support D ([#4372](https://github.com/helix-editor/helix/pull/4372))
855−- Increase default language server timeout for Julia ([#4575](https://github.com/helix-editor/helix/pull/4575))
856−- Use ElixirLS for HEEx ([#4679](https://github.com/helix-editor/helix/pull/4679))
857−- Support Bicep ([#4403](https://github.com/helix-editor/helix/pull/4403))
858−- Switch to `nil` for Nix ([433ccef](https://github.com/helix-editor/helix/commit/433ccef))
859−- Support QML ([#4842](https://github.com/helix-editor/helix/pull/4842))
860−- Enable auto-format for CSS ([#4987](https://github.com/helix-editor/helix/pull/4987))
861−- Support CommonLisp ([4176769](https://github.com/helix-editor/helix/commit/4176769))
862−
863−New languages:
864−
865−- SML ([#3692](https://github.com/helix-editor/helix/pull/3692))
866−- Jsonnet ([#3714](https://github.com/helix-editor/helix/pull/3714))
867−- Godot resource ([#3759](https://github.com/helix-editor/helix/pull/3759))
868−- Astro ([#3829](https://github.com/helix-editor/helix/pull/3829))
869−- SSH config ([#2455](https://github.com/helix-editor/helix/pull/2455), [#4538](https://github.com/helix-editor/helix/pull/4538))
870−- Bass ([#3771](https://github.com/helix-editor/helix/pull/3771))
871−- WAT (WebAssembly text format) ([#4040](https://github.com/helix-editor/helix/pull/4040), [#4542](https://github.com/helix-editor/helix/pull/4542))
872−- Purescript ([#4242](https://github.com/helix-editor/helix/pull/4242))
873−- D ([#4372](https://github.com/helix-editor/helix/pull/4372), [#4562](https://github.com/helix-editor/helix/pull/4562))
874−- VHS ([#4486](https://github.com/helix-editor/helix/pull/4486))
875−- KDL ([#4481](https://github.com/helix-editor/helix/pull/4481))
876−- XML ([#4518](https://github.com/helix-editor/helix/pull/4518))
877−- WIT ([#4525](https://github.com/helix-editor/helix/pull/4525))
878−- ENV ([#4536](https://github.com/helix-editor/helix/pull/4536))
879−- INI ([#4538](https://github.com/helix-editor/helix/pull/4538))
880−- Bicep ([#4403](https://github.com/helix-editor/helix/pull/4403), [#4751](https://github.com/helix-editor/helix/pull/4751))
881−- QML ([#4842](https://github.com/helix-editor/helix/pull/4842))
882−- CommonLisp ([4176769](https://github.com/helix-editor/helix/commit/4176769))
883−
884−Updated languages and queries:
885−
886−- Zig ([#3621](https://github.com/helix-editor/helix/pull/3621), [#4745](https://github.com/helix-editor/helix/pull/4745))
887−- Rust ([#3647](https://github.com/helix-editor/helix/pull/3647), [#3729](https://github.com/helix-editor/helix/pull/3729), [#3927](https://github.com/helix-editor/helix/pull/3927), [#4073](https://github.com/helix-editor/helix/pull/4073), [#4510](https://github.com/helix-editor/helix/pull/4510), [#4659](https://github.com/helix-editor/helix/pull/4659), [#4717](https://github.com/helix-editor/helix/pull/4717))
888−- Solidity ([20ed8c2](https://github.com/helix-editor/helix/commit/20ed8c2))
889−- Fish ([#3704](https://github.com/helix-editor/helix/pull/3704))
890−- Elixir ([#3645](https://github.com/helix-editor/helix/pull/3645), [#4333](https://github.com/helix-editor/helix/pull/4333), [#4821](https://github.com/helix-editor/helix/pull/4821))
891−- Diff ([#3708](https://github.com/helix-editor/helix/pull/3708))
892−- Nix ([665e27f](https://github.com/helix-editor/helix/commit/665e27f), [1fe3273](https://github.com/helix-editor/helix/commit/1fe3273))
893−- Markdown ([#3749](https://github.com/helix-editor/helix/pull/3749), [#4078](https://github.com/helix-editor/helix/pull/4078), [#4483](https://github.com/helix-editor/helix/pull/4483), [#4478](https://github.com/helix-editor/helix/pull/4478))
894−- GDScript ([#3760](https://github.com/helix-editor/helix/pull/3760))
895−- JSX and TSX ([#3853](https://github.com/helix-editor/helix/pull/3853), [#3973](https://github.com/helix-editor/helix/pull/3973))
896−- Ruby ([#3976](https://github.com/helix-editor/helix/pull/3976), [#4601](https://github.com/helix-editor/helix/pull/4601))
897−- R ([#4031](https://github.com/helix-editor/helix/pull/4031))
898−- WGSL ([#3996](https://github.com/helix-editor/helix/pull/3996), [#4079](https://github.com/helix-editor/helix/pull/4079))
899−- C# ([#4118](https://github.com/helix-editor/helix/pull/4118), [#4281](https://github.com/helix-editor/helix/pull/4281), [#4213](https://github.com/helix-editor/helix/pull/4213))
900−- Twig ([#4176](https://github.com/helix-editor/helix/pull/4176))
901−- Lua ([#3552](https://github.com/helix-editor/helix/pull/3552))
902−- C/C++ ([#4079](https://github.com/helix-editor/helix/pull/4079), [#4278](https://github.com/helix-editor/helix/pull/4278), [#4282](https://github.com/helix-editor/helix/pull/4282))
903−- Cairo ([17488f1](https://github.com/helix-editor/helix/commit/17488f1), [431f9c1](https://github.com/helix-editor/helix/commit/431f9c1), [09a6df1](https://github.com/helix-editor/helix/commit/09a6df1))
904−- Rescript ([#4356](https://github.com/helix-editor/helix/pull/4356))
905−- Zig ([#4409](https://github.com/helix-editor/helix/pull/4409))
906−- Scala ([#4353](https://github.com/helix-editor/helix/pull/4353), [#4697](https://github.com/helix-editor/helix/pull/4697), [#4701](https://github.com/helix-editor/helix/pull/4701))
907−- LaTeX ([#4528](https://github.com/helix-editor/helix/pull/4528), [#4922](https://github.com/helix-editor/helix/pull/4922))
908−- SQL ([#4529](https://github.com/helix-editor/helix/pull/4529))
909−- Python ([#4560](https://github.com/helix-editor/helix/pull/4560))
910−- Bash/Zsh ([#4582](https://github.com/helix-editor/helix/pull/4582))
911−- Nu ([#4583](https://github.com/helix-editor/helix/pull/4583))
912−- Julia ([#4588](https://github.com/helix-editor/helix/pull/4588))
913−- Typescript ([#4703](https://github.com/helix-editor/helix/pull/4703))
914−- Meson ([#4572](https://github.com/helix-editor/helix/pull/4572))
915−- Haskell ([#4800](https://github.com/helix-editor/helix/pull/4800))
916−- CMake ([#4809](https://github.com/helix-editor/helix/pull/4809))
917−- HTML ([#4829](https://github.com/helix-editor/helix/pull/4829), [#4881](https://github.com/helix-editor/helix/pull/4881))
918−- Java ([#4886](https://github.com/helix-editor/helix/pull/4886))
919−- Go ([#4906](https://github.com/helix-editor/helix/pull/4906), [#4969](https://github.com/helix-editor/helix/pull/4969), [#5010](https://github.com/helix-editor/helix/pull/5010))
920−- CSS ([#4882](https://github.com/helix-editor/helix/pull/4882))
921−- Racket ([#4915](https://github.com/helix-editor/helix/pull/4915))
922−- SCSS ([#5003](https://github.com/helix-editor/helix/pull/5003))
923−
924−Packaging:
925−
926−- Filter relevant source files in the Nix flake ([#3657](https://github.com/helix-editor/helix/pull/3657))
927−- Build a binary for `aarch64-linux` in the release CI ([038a91d](https://github.com/helix-editor/helix/commit/038a91d))
928−- Build an AppImage for `aarch64-linux` in the release CI ([b738031](https://github.com/helix-editor/helix/commit/b738031))
929−- Enable CI builds for `riscv64-linux` ([#3685](https://github.com/helix-editor/helix/pull/3685))
930−- Support preview releases in CI ([0090a2d](https://github.com/helix-editor/helix/commit/0090a2d))
931−- Strip binaries built in CI ([#3780](https://github.com/helix-editor/helix/pull/3780))
932−- Fix the development shell for the Nix Flake on `aarch64-darwin` ([#3810](https://github.com/helix-editor/helix/pull/3810))
933−- Raise the MSRV and create an MSRV policy ([#3896](https://github.com/helix-editor/helix/pull/3896), [#3913](https://github.com/helix-editor/helix/pull/3913), [#3961](https://github.com/helix-editor/helix/pull/3961))
934−- Fix Fish completions for `--config` and `--log` flags ([#3912](https://github.com/helix-editor/helix/pull/3912))
935−- Use builtin filenames option in Bash completion ([#4648](https://github.com/helix-editor/helix/pull/4648))
936−
937−# 22.08.1 (2022-09-01)
938−
939−This is a patch release that fixes a panic caused by closing splits or buffers. ([#3633](https://github.com/helix-editor/helix/pull/3633))
940−
941−# 22.08 (2022-08-31)
942−
943−A big _thank you_ to our contributors! This release had 87 contributors.
944−
945−As usual, the following is a summary of each of the changes since the last release.
946−For the full log, check out the [git log](https://github.com/helix-editor/helix/compare/22.05..22.08).
947−
948−Breaking changes:
949−
950−- Special keymap names for `+`, `;` and `%` have been replaced with those literal characters ([#2677](https://github.com/helix-editor/helix/pull/2677), [#3556](https://github.com/helix-editor/helix/pull/3556))
951−- `A-Left` and `A-Right` have become `C-Left` and `C-Right` for word-wise motion ([#2500](https://github.com/helix-editor/helix/pull/2500))
952−- The `catppuccin` theme's name has been corrected from `catpuccin` ([#2713](https://github.com/helix-editor/helix/pull/2713))
953−- `catppuccin` has been replaced by its variants, `catppuccin_frappe`, `catppuccin_latte`, `catppuccin_macchiato`, `catppuccin_mocha` ([#3281](https://github.com/helix-editor/helix/pull/3281))
954−- `C-n` and `C-p` have been removed from the default insert mode keymap ([#3340](https://github.com/helix-editor/helix/pull/3340))
955−- The `extend_line` command has been replaced with `extend_line_below` and a new `extend_line` command now exists ([#3046](https://github.com/helix-editor/helix/pull/3046))
956−
957−Features:
958−
959−- Add an integration testing harness ([#2359](https://github.com/helix-editor/helix/pull/2359))
960−- Indent guides ([#1796](https://github.com/helix-editor/helix/pull/1796), [906259c](https://github.com/helix-editor/helix/commit/906259c))
961−- Cursorline ([#2170](https://github.com/helix-editor/helix/pull/2170), [fde9e03](https://github.com/helix-editor/helix/commit/fde9e03))
962−- Select all instances of the symbol under the cursor (`<space>h`) ([#2738](https://github.com/helix-editor/helix/pull/2738))
963−- A picker for document and workspace LSP diagnostics (`<space>g`/`<space>G`) ([#2013](https://github.com/helix-editor/helix/pull/2013), [#2984](https://github.com/helix-editor/helix/pull/2984))
964−- Allow styling the mode indicator per-mode ([#2676](https://github.com/helix-editor/helix/pull/2676))
965−- Live preview for the theme picker ([#1798](https://github.com/helix-editor/helix/pull/1798))
966−- Configurable statusline ([#2434](https://github.com/helix-editor/helix/pull/2434))
967−- LSP SignatureHelp ([#1755](https://github.com/helix-editor/helix/pull/1755), [a8b123f](https://github.com/helix-editor/helix/commit/a8b123f))
968−- A picker for the jumplist ([#3033](https://github.com/helix-editor/helix/pull/3033))
969−- Configurable external formatter binaries ([#2942](https://github.com/helix-editor/helix/pull/2942))
970−- Bracketed paste support ([#3233](https://github.com/helix-editor/helix/pull/3233), [12ddd03](https://github.com/helix-editor/helix/commit/12ddd03))
971−
972−Commands:
973−
974−- `:insert-output` and `:append-output` which insert/append output from a shell command ([#2589](https://github.com/helix-editor/helix/pull/2589))
975−- The `t` textobject (`]t`/`[t`/`mit`/`mat`) for navigating tests ([#2807](https://github.com/helix-editor/helix/pull/2807))
976−- `C-Backspace` and `C-Delete` for word-wise deletion in prompts and pickers ([#2500](https://github.com/helix-editor/helix/pull/2500))
977−- `A-Delete` for forward word-wise deletion in insert mode ([#2500](https://github.com/helix-editor/helix/pull/2500))
978−- `C-t` for toggling the preview pane in pickers ([#3021](https://github.com/helix-editor/helix/pull/3021))
979−- `extend_line` now extends in the direction of the cursor ([#3046](https://github.com/helix-editor/helix/pull/3046))
980−
981−Usability improvements and fixes:
982−
983−- Fix tree-sitter parser builds on illumos ([#2602](https://github.com/helix-editor/helix/pull/2602))
984−- Remove empty stratch buffer from jumplists when removing ([5ed6223](https://github.com/helix-editor/helix/commit/5ed6223))
985−- Fix panic on undo after `shell_append_output` ([#2625](https://github.com/helix-editor/helix/pull/2625))
986−- Sort LSP edits by start range ([3d91c99](https://github.com/helix-editor/helix/commit/3d91c99))
987−- Be more defensive about LSP URI conversions ([6de6a3e](https://github.com/helix-editor/helix/commit/6de6a3e), [378f438](https://github.com/helix-editor/helix/commit/378f438))
988−- Ignore SendErrors when grammar builds fail ([#2641](https://github.com/helix-editor/helix/pull/2641))
989−- Append `set_line_ending` to document history ([#2649](https://github.com/helix-editor/helix/pull/2649))
990−- Use last prompt entry when empty ([b14c258](https://github.com/helix-editor/helix/commit/b14c258), [#2870](https://github.com/helix-editor/helix/pull/2870))
991−- Do not add extra line breaks in markdown lists ([#2689](https://github.com/helix-editor/helix/pull/2689))
992−- Disable dialyzer by default for ElixirLS ([#2710](https://github.com/helix-editor/helix/pull/2710))
993−- Refactor textobject node capture ([#2741](https://github.com/helix-editor/helix/pull/2741))
994−- Prevent re-selecting the same range with `expand_selection` ([#2760](https://github.com/helix-editor/helix/pull/2760))
995−- Introduce `keyword.storage` highlight scope ([#2731](https://github.com/helix-editor/helix/pull/2731))
996−- Handle symlinks more consistently ([#2718](https://github.com/helix-editor/helix/pull/2718))
997−- Improve markdown list rendering ([#2687](https://github.com/helix-editor/helix/pull/2687))
998−- Update auto-pairs and idle-timout settings when the config is reloaded ([#2736](https://github.com/helix-editor/helix/pull/2736))
999−- Fix panic on closing last buffer ([#2658](https://github.com/helix-editor/helix/pull/2658))
1000−- Prevent modifying jumplist until jumping to a reference ([#2670](https://github.com/helix-editor/helix/pull/2670))
1001−- Ensure `:quit` and `:quit!` take no arguments ([#2654](https://github.com/helix-editor/helix/pull/2654))
1002−- Fix crash due to cycles when replaying macros ([#2647](https://github.com/helix-editor/helix/pull/2647))
1003−- Pass LSP FormattingOptions ([#2635](https://github.com/helix-editor/helix/pull/2635))
1004−- Prevent showing colors when the health-check is piped ([#2836](https://github.com/helix-editor/helix/pull/2836))
1005−- Use character indexing for mouse selection ([#2839](https://github.com/helix-editor/helix/pull/2839))
1006−- Display the highest severity diagnostic for a line in the gutter ([#2835](https://github.com/helix-editor/helix/pull/2835))
1007−- Default the ruler color to red background ([#2669](https://github.com/helix-editor/helix/pull/2669))
1008−- Make `move_vertically` aware of tabs and wide characters ([#2620](https://github.com/helix-editor/helix/pull/2620))
1009−- Enable shellwords for Windows ([#2767](https://github.com/helix-editor/helix/pull/2767))
1010−- Add history suggestions to global search ([#2717](https://github.com/helix-editor/helix/pull/2717))
1011−- Fix the scrollbar's length proportional to total menu items ([#2860](https://github.com/helix-editor/helix/pull/2860))
1012−- Reset terminal modifiers for diagnostic text ([#2861](https://github.com/helix-editor/helix/pull/2861), [#2900](https://github.com/helix-editor/helix/pull/2900))
1013−- Redetect indents and line-endings after a Language Server replaces the document ([#2778](https://github.com/helix-editor/helix/pull/2778))
1014−- Check selection's visible width when copying on mouse click ([#2711](https://github.com/helix-editor/helix/pull/2711))
1015−- Fix edge-case in tree-sitter `expand_selection` command ([#2877](https://github.com/helix-editor/helix/pull/2877))
1016−- Add a single-width left margin for the completion popup ([#2728](https://github.com/helix-editor/helix/pull/2728))
1017−- Right-align the scrollbar in the completion popup ([#2754](https://github.com/helix-editor/helix/pull/2754))
1018−- Fix recursive macro crash and empty macro lockout ([#2902](https://github.com/helix-editor/helix/pull/2902))
1019−- Fix backwards character deletion on other whitespaces ([#2855](https://github.com/helix-editor/helix/pull/2855))
1020−- Add search and space/backspace bindings to view modes ([#2803](https://github.com/helix-editor/helix/pull/2803))
1021−- Add `--vsplit` and `--hsplit` CLI arguments for opening in splits ([#2773](https://github.com/helix-editor/helix/pull/2773), [#3073](https://github.com/helix-editor/helix/pull/3073))
1022−- Sort themes, languages and files inputs by score and name ([#2675](https://github.com/helix-editor/helix/pull/2675))
1023−- Highlight entire rows in ([#2939](https://github.com/helix-editor/helix/pull/2939))
1024−- Fix backwards selection duplication widening bug ([#2945](https://github.com/helix-editor/helix/pull/2945), [#3024](https://github.com/helix-editor/helix/pull/3024))
1025−- Skip serializing Option type DAP fields ([44f5963](https://github.com/helix-editor/helix/commit/44f5963))
1026−- Fix required `cwd` field in DAP `RunTerminalArguments` type ([85411be](https://github.com/helix-editor/helix/commit/85411be), [#3240](https://github.com/helix-editor/helix/pull/3240))
1027−- Add LSP `workspace/applyEdit` to client capabilities ([#3012](https://github.com/helix-editor/helix/pull/3012))
1028−- Respect count for repeating motion ([#3057](https://github.com/helix-editor/helix/pull/3057))
1029−- Respect count for selecting next/previous match ([#3056](https://github.com/helix-editor/helix/pull/3056))
1030−- Respect count for tree-sitter motions ([#3058](https://github.com/helix-editor/helix/pull/3058))
1031−- Make gutters padding optional ([#2996](https://github.com/helix-editor/helix/pull/2996))
1032−- Support pre-filling prompts ([#2459](https://github.com/helix-editor/helix/pull/2459), [#3259](https://github.com/helix-editor/helix/pull/3259))
1033−- Add statusline element to display file line-endings ([#3113](https://github.com/helix-editor/helix/pull/3113))
1034−- Keep jump and file history when using `:split` ([#3031](https://github.com/helix-editor/helix/pull/3031), [#3160](https://github.com/helix-editor/helix/pull/3160))
1035−- Make tree-sitter query `; inherits <language>` feature imperative ([#2470](https://github.com/helix-editor/helix/pull/2470))
1036−- Indent with tabs by default ([#3095](https://github.com/helix-editor/helix/pull/3095))
1037−- Fix non-msvc grammar compilation on Windows ([#3190](https://github.com/helix-editor/helix/pull/3190))
1038−- Add spacer element to the statusline ([#3165](https://github.com/helix-editor/helix/pull/3165), [255c173](https://github.com/helix-editor/helix/commit/255c173))
1039−- Make gutters padding automatic ([#3163](https://github.com/helix-editor/helix/pull/3163))
1040−- Add `code` for LSP `Diagnostic` type ([#3096](https://github.com/helix-editor/helix/pull/3096))
1041−- Add position percentage to the statusline ([#3168](https://github.com/helix-editor/helix/pull/3168))
1042−- Add a configurable and themable statusline separator string ([#3175](https://github.com/helix-editor/helix/pull/3175))
1043−- Use OR of all selections when `search_selection` acts on multiple selections ([#3138](https://github.com/helix-editor/helix/pull/3138))
1044−- Add clipboard information to logs and the healthcheck ([#3271](https://github.com/helix-editor/helix/pull/3271))
1045−- Fix align selection behavior on tabs ([#3276](https://github.com/helix-editor/helix/pull/3276))
1046−- Fix terminal cursor shape reset ([#3289](https://github.com/helix-editor/helix/pull/3289))
1047−- Add an `injection.include-unnamed-children` predicate to injections queries ([#3129](https://github.com/helix-editor/helix/pull/3129))
1048−- Add a `-c`/`--config` CLI flag for specifying config file location ([#2666](https://github.com/helix-editor/helix/pull/2666))
1049−- Detect indent-style in `:set-language` command ([#3330](https://github.com/helix-editor/helix/pull/3330))
1050−- Fix non-deterministic highlighting ([#3275](https://github.com/helix-editor/helix/pull/3275))
1051−- Avoid setting the stdin handle when not necessary ([#3248](https://github.com/helix-editor/helix/pull/3248), [#3379](https://github.com/helix-editor/helix/pull/3379))
1052−- Fix indent guide styling ([#3324](https://github.com/helix-editor/helix/pull/3324))
1053−- Fix tab highlight when tab is partially visible ([#3313](https://github.com/helix-editor/helix/pull/3313))
1054−- Add completion for nested settings ([#3183](https://github.com/helix-editor/helix/pull/3183))
1055−- Advertise WorkspaceSymbolClientCapabilities LSP client capability ([#3361](https://github.com/helix-editor/helix/pull/3361))
1056−- Remove duplicate entries from the theme picker ([#3439](https://github.com/helix-editor/helix/pull/3439))
1057−- Shorted output for grammar fetching and building ([#3396](https://github.com/helix-editor/helix/pull/3396))
1058−- Add a `tabpad` option for visible tab padding whitespace characters ([#3458](https://github.com/helix-editor/helix/pull/3458))
1059−- Make DAP external terminal provider configurable ([cb7615e](https://github.com/helix-editor/helix/commit/cb7615e))
1060−- Use health checkmark character with shorter width ([#3505](https://github.com/helix-editor/helix/pull/3505))
1061−- Reset document mode to normal on view focus loss ([e4c9d40](https://github.com/helix-editor/helix/commit/e4c9d40))
1062−- Render indented code-blocks in markdown ([#3503](https://github.com/helix-editor/helix/pull/3503))
1063−- Add WezTerm to DAP terminal provider defaults ([#3588](https://github.com/helix-editor/helix/pull/3588))
1064−- Derive `Document` language name from `languages.toml` `name` key ([#3338](https://github.com/helix-editor/helix/pull/3338))
1065−- Fix process spawning error handling ([#3349](https://github.com/helix-editor/helix/pull/3349))
1066−- Don't resolve links for `:o` completion ([8a4fbf6](https://github.com/helix-editor/helix/commit/8a4fbf6))
1067−- Recalculate completion after pasting into prompt ([e77b7d1](https://github.com/helix-editor/helix/commit/e77b7d1))
1068−- Fix extra selections with regex anchors ([#3598](https://github.com/helix-editor/helix/pull/3598))
1069−- Move mode transition logic to `handle_keymap_event` ([#2634](https://github.com/helix-editor/helix/pull/2634))
1070−- Add documents to view history when using the jumplist ([#3593](https://github.com/helix-editor/helix/pull/3593))
1071−- Prevent panic when loading tree-sitter queries ([fa1dc7e](https://github.com/helix-editor/helix/commit/fa1dc7e))
1072−- Discard LSP publishDiagnostic when LS is not initialized ([#3403](https://github.com/helix-editor/helix/pull/3403))
1073−- Refactor tree-sitter textobject motions as repeatable motions ([#3264](https://github.com/helix-editor/helix/pull/3264))
1074−- Avoid command execution hooks on closed docs ([#3613](https://github.com/helix-editor/helix/pull/3613))
1075−- Share `restore_term` code between panic and normal exits ([#2612](https://github.com/helix-editor/helix/pull/2612))
1076−- Show clipboard info in `--health` output ([#2947](https://github.com/helix-editor/helix/pull/2947))
1077−- Recalculate completion when going through prompt history ([#3193](https://github.com/helix-editor/helix/pull/3193))
1078−
1079−Themes:
1080−
1081−- Update `tokyonight` and `tokyonight_storm` themes ([#2606](https://github.com/helix-editor/helix/pull/2606))
1082−- Update `solarized_light` themes ([#2626](https://github.com/helix-editor/helix/pull/2626))
1083−- Fix `catpuccin` `ui.popup` theme ([#2644](https://github.com/helix-editor/helix/pull/2644))
1084−- Update selection style of `night_owl` ([#2668](https://github.com/helix-editor/helix/pull/2668))
1085−- Fix spelling of `catppuccin` theme ([#2713](https://github.com/helix-editor/helix/pull/2713))
1086−- Update `base16_default`'s `ui.menu` ([#2794](https://github.com/helix-editor/helix/pull/2794))
1087−- Add `noctis_bordo` ([#2830](https://github.com/helix-editor/helix/pull/2830))
1088−- Add `acme` ([#2876](https://github.com/helix-editor/helix/pull/2876))
1089−- Add `meliora` ([#2884](https://github.com/helix-editor/helix/pull/2884), [#2890](https://github.com/helix-editor/helix/pull/2890))
1090−- Add cursorline scopes to various themes ([33d287a](https://github.com/helix-editor/helix/commit/33d287a), [#2892](https://github.com/helix-editor/helix/pull/2892), [#2915](https://github.com/helix-editor/helix/pull/2915), [#2916](https://github.com/helix-editor/helix/pull/2916), [#2918](https://github.com/helix-editor/helix/pull/2918), [#2927](https://github.com/helix-editor/helix/pull/2927), [#2925](https://github.com/helix-editor/helix/pull/2925), [#2938](https://github.com/helix-editor/helix/pull/2938), [#2962](https://github.com/helix-editor/helix/pull/2962), [#3054](https://github.com/helix-editor/helix/pull/3054))
1091−- Add mode colors to various themes ([#2926](https://github.com/helix-editor/helix/pull/2926), [#2933](https://github.com/helix-editor/helix/pull/2933), [#2929](https://github.com/helix-editor/helix/pull/2929), [#3098](https://github.com/helix-editor/helix/pull/3098), [#3104](https://github.com/helix-editor/helix/pull/3104), [#3128](https://github.com/helix-editor/helix/pull/3128), [#3135](https://github.com/helix-editor/helix/pull/3135), [#3200](https://github.com/helix-editor/helix/pull/3200))
1092−- Add `nord_light` ([#2908](https://github.com/helix-editor/helix/pull/2908))
1093−- Update `night_owl` ([#2929](https://github.com/helix-editor/helix/pull/2929))
1094−- Update `autumn` ([2e70985](https://github.com/helix-editor/helix/commit/2e70985), [936ed3a](https://github.com/helix-editor/helix/commit/936ed3a))
1095−- Update `one_dark` ([#3011](https://github.com/helix-editor/helix/pull/3011))
1096−- Add `noctis` ([#3043](https://github.com/helix-editor/helix/pull/3043), [#3128](https://github.com/helix-editor/helix/pull/3128))
1097−- Update `boo_berry` ([#3191](https://github.com/helix-editor/helix/pull/3191))
1098−- Update `monokai` ([#3131](https://github.com/helix-editor/helix/pull/3131))
1099−- Add `ayu_dark`, `ayu_light`, `ayu_mirage` ([#3184](https://github.com/helix-editor/helix/pull/3184))
1100−- Update `onelight` ([#3226](https://github.com/helix-editor/helix/pull/3226))
1101−- Add `base16_transparent` ([#3216](https://github.com/helix-editor/helix/pull/3216), [b565fff](https://github.com/helix-editor/helix/commit/b565fff))
1102−- Add `flatwhite` ([#3236](https://github.com/helix-editor/helix/pull/3236))
1103−- Update `dark_plus` ([#3302](https://github.com/helix-editor/helix/pull/3302))
1104−- Add `doom_acario_dark` ([#3308](https://github.com/helix-editor/helix/pull/3308), [#3539](https://github.com/helix-editor/helix/pull/3539))
1105−- Add `rose_pine_moon` ([#3229](https://github.com/helix-editor/helix/pull/3229))
1106−- Update `spacebones_light` ([#3342](https://github.com/helix-editor/helix/pull/3342))
1107−- Fix typos in themes ([8deaebd](https://github.com/helix-editor/helix/commit/8deaebd), [#3412](https://github.com/helix-editor/helix/pull/3412))
1108−- Add `emacs` ([#3410](https://github.com/helix-editor/helix/pull/3410))
1109−- Add `papercolor-light` ([#3426](https://github.com/helix-editor/helix/pull/3426), [#3470](https://github.com/helix-editor/helix/pull/3470), [#3585](https://github.com/helix-editor/helix/pull/3585))
1110−- Add `penumbra+` ([#3398](https://github.com/helix-editor/helix/pull/3398))
1111−- Add `fleetish` ([#3591](https://github.com/helix-editor/helix/pull/3591), [#3607](https://github.com/helix-editor/helix/pull/3607))
1112−- Add `sonokai` ([#3595](https://github.com/helix-editor/helix/pull/3595))
1113−- Update all themes for theme lints ([#3587](https://github.com/helix-editor/helix/pull/3587))
1114−
1115−LSP:
1116−
1117−- V ([#2526](https://github.com/helix-editor/helix/pull/2526))
1118−- Prisma ([#2703](https://github.com/helix-editor/helix/pull/2703))
1119−- Clojure ([#2780](https://github.com/helix-editor/helix/pull/2780))
1120−- WGSL ([#2872](https://github.com/helix-editor/helix/pull/2872))
1121−- Elvish ([#2948](https://github.com/helix-editor/helix/pull/2948))
1122−- Idris ([#2971](https://github.com/helix-editor/helix/pull/2971))
1123−- Fortran ([#3025](https://github.com/helix-editor/helix/pull/3025))
1124−- Gleam ([#3139](https://github.com/helix-editor/helix/pull/3139))
1125−- Odin ([#3214](https://github.com/helix-editor/helix/pull/3214))
1126−
1127−New languages:
1128−
1129−- V ([#2526](https://github.com/helix-editor/helix/pull/2526))
1130−- EDoc ([#2640](https://github.com/helix-editor/helix/pull/2640))
1131−- JSDoc ([#2650](https://github.com/helix-editor/helix/pull/2650))
1132−- OpenSCAD ([#2680](https://github.com/helix-editor/helix/pull/2680))
1133−- Prisma ([#2703](https://github.com/helix-editor/helix/pull/2703))
1134−- Clojure ([#2780](https://github.com/helix-editor/helix/pull/2780))
1135−- Starlark ([#2903](https://github.com/helix-editor/helix/pull/2903))
1136−- Elvish ([#2948](https://github.com/helix-editor/helix/pull/2948))
1137−- Fortran ([#3025](https://github.com/helix-editor/helix/pull/3025))
1138−- Ungrammar ([#3048](https://github.com/helix-editor/helix/pull/3048))
1139−- SCSS ([#3074](https://github.com/helix-editor/helix/pull/3074))
1140−- Go Template ([#3091](https://github.com/helix-editor/helix/pull/3091))
1141−- Graphviz dot ([#3241](https://github.com/helix-editor/helix/pull/3241))
1142−- Cue ([#3262](https://github.com/helix-editor/helix/pull/3262))
1143−- Slint ([#3355](https://github.com/helix-editor/helix/pull/3355))
1144−- Beancount ([#3297](https://github.com/helix-editor/helix/pull/3297))
1145−- Taskwarrior ([#3468](https://github.com/helix-editor/helix/pull/3468))
1146−- xit ([#3521](https://github.com/helix-editor/helix/pull/3521))
1147−- ESDL ([#3526](https://github.com/helix-editor/helix/pull/3526))
1148−- Awk ([#3528](https://github.com/helix-editor/helix/pull/3528), [#3535](https://github.com/helix-editor/helix/pull/3535))
1149−- Pascal ([#3542](https://github.com/helix-editor/helix/pull/3542))
1150−
1151−Updated languages and queries:
1152−
1153−- Nix ([#2472](https://github.com/helix-editor/helix/pull/2472))
1154−- Elixir ([#2619](https://github.com/helix-editor/helix/pull/2619))
1155−- CPON ([#2643](https://github.com/helix-editor/helix/pull/2643))
1156−- Textobjects queries for Erlang, Elixir, Gleam ([#2661](https://github.com/helix-editor/helix/pull/2661))
1157−- Capture rust closures as function textobjects ([4a27e2d](https://github.com/helix-editor/helix/commit/4a27e2d))
1158−- Heex ([#2800](https://github.com/helix-editor/helix/pull/2800), [#3170](https://github.com/helix-editor/helix/pull/3170))
1159−- Add `<<=` operator highlighting for Rust ([#2805](https://github.com/helix-editor/helix/pull/2805))
1160−- Fix comment injection in JavaScript/TypeScript ([#2763](https://github.com/helix-editor/helix/pull/2763))
1161−- Nickel ([#2859](https://github.com/helix-editor/helix/pull/2859))
1162−- Add `Rakefile` and `Gemfile` to Ruby file-types ([#2875](https://github.com/helix-editor/helix/pull/2875))
1163−- Erlang ([#2910](https://github.com/helix-editor/helix/pull/2910), [ac669ad](https://github.com/helix-editor/helix/commit/ac669ad))
1164−- Markdown ([#2910](https://github.com/helix-editor/helix/pull/2910), [#3108](https://github.com/helix-editor/helix/pull/3108), [#3400](https://github.com/helix-editor/helix/pull/3400))
1165−- Bash ([#2910](https://github.com/helix-editor/helix/pull/2910))
1166−- Rust ([#2910](https://github.com/helix-editor/helix/pull/2910), [#3397](https://github.com/helix-editor/helix/pull/3397))
1167−- Edoc ([#2910](https://github.com/helix-editor/helix/pull/2910))
1168−- HTML ([#2910](https://github.com/helix-editor/helix/pull/2910))
1169−- Make ([#2910](https://github.com/helix-editor/helix/pull/2910))
1170−- TSQ ([#2910](https://github.com/helix-editor/helix/pull/2910), [#2960](https://github.com/helix-editor/helix/pull/2960))
1171−- git-commit ([#2910](https://github.com/helix-editor/helix/pull/2910))
1172−- Use default fallback for Python indents ([9ae70cc](https://github.com/helix-editor/helix/commit/9ae70cc))
1173−- Add Haskell LSP roots ([#2954](https://github.com/helix-editor/helix/pull/2954))
1174−- Ledger ([#2936](https://github.com/helix-editor/helix/pull/2936), [#2988](https://github.com/helix-editor/helix/pull/2988))
1175−- Nickel ([#2987](https://github.com/helix-editor/helix/pull/2987))
1176−- JavaScript/TypeScript ([#2961](https://github.com/helix-editor/helix/pull/2961), [#3219](https://github.com/helix-editor/helix/pull/3219), [#3213](https://github.com/helix-editor/helix/pull/3213), [#3280](https://github.com/helix-editor/helix/pull/3280), [#3301](https://github.com/helix-editor/helix/pull/3301))
1177−- GLSL ([#3051](https://github.com/helix-editor/helix/pull/3051))
1178−- Fix locals tracking in Rust ([#3027](https://github.com/helix-editor/helix/pull/3027), [#3212](https://github.com/helix-editor/helix/pull/3212), [#3345](https://github.com/helix-editor/helix/pull/3345))
1179−- Verilog ([#3158](https://github.com/helix-editor/helix/pull/3158))
1180−- Ruby ([#3173](https://github.com/helix-editor/helix/pull/3173), [#3527](https://github.com/helix-editor/helix/pull/3527))
1181−- Svelte ([#3147](https://github.com/helix-editor/helix/pull/3147))
1182−- Add Elixir and HEEx comment textobjects ([#3179](https://github.com/helix-editor/helix/pull/3179))
1183−- Python ([#3103](https://github.com/helix-editor/helix/pull/3103), [#3201](https://github.com/helix-editor/helix/pull/3201), [#3284](https://github.com/helix-editor/helix/pull/3284))
1184−- PHP ([#3317](https://github.com/helix-editor/helix/pull/3317))
1185−- Latex ([#3370](https://github.com/helix-editor/helix/pull/3370))
1186−- Clojure ([#3387](https://github.com/helix-editor/helix/pull/3387))
1187−- Swift ([#3461](https://github.com/helix-editor/helix/pull/3461))
1188−- C# ([#3480](https://github.com/helix-editor/helix/pull/3480), [#3494](https://github.com/helix-editor/helix/pull/3494))
1189−- Org ([#3489](https://github.com/helix-editor/helix/pull/3489))
1190−- Elm ([#3497](https://github.com/helix-editor/helix/pull/3497))
1191−- Dart ([#3419](https://github.com/helix-editor/helix/pull/3419))
1192−- Julia ([#3507](https://github.com/helix-editor/helix/pull/3507))
1193−- Fix Rust textobjects ([#3590](https://github.com/helix-editor/helix/pull/3590))
1194−- C ([00d88e5](https://github.com/helix-editor/helix/commit/00d88e5))
1195−- Update Rust ([0ef0ef9](https://github.com/helix-editor/helix/commit/0ef0ef9))
1196−
1197−Packaging:
1198−
1199−- Add `rust-analyzer` to Nix flake devShell ([#2739](https://github.com/helix-editor/helix/pull/2739))
1200−- Add cachix information to the Nix flake ([#2999](https://github.com/helix-editor/helix/pull/2999))
1201−- Pass makeWrapperArgs to wrapProgram in the Nix flake ([#3003](https://github.com/helix-editor/helix/pull/3003))
1202−- Add a way to override which grammars are built by Nix ([#3141](https://github.com/helix-editor/helix/pull/3141))
1203−- Add a GitHub actions release for `aarch64-macos` ([#3137](https://github.com/helix-editor/helix/pull/3137))
1204−- Add shell auto-completions for Elvish ([#3331](https://github.com/helix-editor/helix/pull/3331))
1205−
1206−# 22.05 (2022-05-28)
1207−
1208−An even bigger shout out than usual to all the contributors - we had a whopping
1209−110 contributors in this release! That's more than double the number of
1210−contributors as last release!
1211−
1212−Check out some of the highlights in the [news section](https://helix-editor.com/news/release-22-05-highlights/).
1213−
1214−As usual, the following is a summary of each of the changes since the last release.
1215−For the full log, check out the [git log](https://github.com/helix-editor/helix/compare/22.03..22.05).
1216−
1217−Breaking Changes:
1218−
1219−- Removed `C-j`, `C-k` bindings from file picker ([#1792](https://github.com/helix-editor/helix/pull/1792))
1220−- Replaced `C-f` with `C-d` and `C-b` with `C-u` bindings in file picker ([#1792](https://github.com/helix-editor/helix/pull/1792))
1221−- `A-hjkl` bindings have been moved to `A-pion` ([#2205](https://github.com/helix-editor/helix/pull/2205))
1222−- `A-Left`/`A-Right` have been moved to `C-Left`/`C-Right` ([#2193](https://github.com/helix-editor/helix/pull/2193))
1223−
1224−Features:
1225−
1226−- The indentation mechanism has been reworked ([#1562](https://github.com/helix-editor/helix/pull/1562), [#1908](https://github.com/helix-editor/helix/pull/1908))
1227−- Configurable gutters ([#1967](https://github.com/helix-editor/helix/pull/1967))
1228−- Support for local language configuration ([#1249](https://github.com/helix-editor/helix/pull/1249))
1229−- Configurable themed rulers ([#2060](https://github.com/helix-editor/helix/pull/2060))
1230−- Render visible whitespace ([e6b865e](https://github.com/helix-editor/helix/commit/e6b865e), [#2322](https://github.com/helix-editor/helix/pull/2322), [#2331](https://github.com/helix-editor/helix/pull/2331))
1231−
1232−Commands:
1233−
1234−- Paragraph motion and textobject (`]p`, `[p`) ([#1627](https://github.com/helix-editor/helix/pull/1627), [#1956](https://github.com/helix-editor/helix/pull/1956), [#1969](https://github.com/helix-editor/helix/pull/1969), [#1992](https://github.com/helix-editor/helix/pull/1992), [#2226](https://github.com/helix-editor/helix/pull/2226))
1235−- `:buffer-next`, `:buffer-previous` ([#1940](https://github.com/helix-editor/helix/pull/1940))
1236−- `:set-language` to set the buffers language ([#1866](https://github.com/helix-editor/helix/pull/1866), [#1996](https://github.com/helix-editor/helix/pull/1996))
1237−- Command for picking files from the current working directory (`Space-F`) ([#1600](https://github.com/helix-editor/helix/pull/1600), [#2308](https://github.com/helix-editor/helix/pull/2308))
1238−- `:write!` which creates non-existent subdirectories ([#1839](https://github.com/helix-editor/helix/pull/1839))
1239−- Add `m` textobject that selects closest surrounding pair ([de15d70](https://github.com/helix-editor/helix/commit/de15d70), [76175db](https://github.com/helix-editor/helix/commit/76175db))
1240−- `:pipe` typable command for piping selections ([#1972](https://github.com/helix-editor/helix/pull/1972))
1241−- `extend_line_above` which extends to previous lines ([#2117](https://github.com/helix-editor/helix/pull/2117))
1242−- `set_line_ending` which replaces line endings ([#1871](https://github.com/helix-editor/helix/pull/1871))
1243−- `:get-option` for getting the current value of an option (`:get`) ([#2231](https://github.com/helix-editor/helix/pull/2231))
1244−- `:run-shell-command` which does not interact with selections ([#1682](https://github.com/helix-editor/helix/pull/1682))
1245−- `:reflow` which hard-wraps selected text ([#2128](https://github.com/helix-editor/helix/pull/2128))
1246−- `commit_undo_checkpoint` which adds an undo checkpoint ([#2115](https://github.com/helix-editor/helix/pull/2115))
1247−- `:log-open` which opens the log file ([#2422](https://github.com/helix-editor/helix/pull/2422))
1248−- `transpose_view` which transposes window splits ([#2461](https://github.com/helix-editor/helix/pull/2461))
1249−- View-swapping: `swap_view_right`, `swap_view_left`, `swap_view_up`, `swap_view_down` ([#2445](https://github.com/helix-editor/helix/pull/2445))
1250−- `shrink_to_line_bounds` which shrinks selections to line-bounds ([#2450](https://github.com/helix-editor/helix/pull/2450))
1251−
1252−Usability improvements and fixes:
1253−
1254−- Handle broken pipes when piping `hx --health` through `head` ([#1876](https://github.com/helix-editor/helix/pull/1876))
1255−- Fix for `copy_selection` on newlines ([ab7885e](https://github.com/helix-editor/helix/commit/ab7885e), [236c6b7](https://github.com/helix-editor/helix/commit/236c6b7))
1256−- Use `win32yank` clipboard provider on WSL2 ([#1912](https://github.com/helix-editor/helix/pull/1912))
1257−- Jump to the next number on the line before incrementing ([#1778](https://github.com/helix-editor/helix/pull/1778))
1258−- Fix start position of next search ([#1904](https://github.com/helix-editor/helix/pull/1904))
1259−- Use check and X marks for health check output ([#1918](https://github.com/helix-editor/helix/pull/1918))
1260−- Clear terminal after switching to alternate screens ([#1944](https://github.com/helix-editor/helix/pull/1944))
1261−- Fix `toggle_comments` command on multiple selections ([#1882](https://github.com/helix-editor/helix/pull/1882))
1262−- Apply `ui.gutter` theming to empty gutter spans ([#2032](https://github.com/helix-editor/helix/pull/2032))
1263−- Use checkboxes in `hx --health` output ([#1947](https://github.com/helix-editor/helix/pull/1947))
1264−- Pass unmapped keys through prompt regardless of modifiers ([764adbd](https://github.com/helix-editor/helix/commit/764adbd))
1265−- LSP: pull formatting options from config ([c18de0e](https://github.com/helix-editor/helix/commit/c18de0e))
1266−- LSP: provide `rootPath` ([84e799f](https://github.com/helix-editor/helix/commit/84e799f))
1267−- LSP: implement `workspace_folders` ([8adf0c1](https://github.com/helix-editor/helix/commit/8adf0c1))
1268−- LSP: fix auto-import ([#2088](https://github.com/helix-editor/helix/pull/2088))
1269−- Send active diagnostic to LSP when requesting code actions ([#2005](https://github.com/helix-editor/helix/pull/2005))
1270−- Prevent panic when parsing malformed LSP `PublishDiagnostic` ([#2160](https://github.com/helix-editor/helix/pull/2160))
1271−- Restore document state on completion cancel ([#2096](https://github.com/helix-editor/helix/pull/2096))
1272−- Only merge top-level array when merging `languages.toml` ([#2145](https://github.com/helix-editor/helix/pull/2145), [#2215](https://github.com/helix-editor/helix/pull/2215))
1273−- Fix open on multiline selection ([#2161](https://github.com/helix-editor/helix/pull/2161))
1274−- Allow re-binding `0` if it is not used in a count ([#2174](https://github.com/helix-editor/helix/pull/2174))
1275−- Fix `ctrl-u` behavior in insert mode ([#1957](https://github.com/helix-editor/helix/pull/1957))
1276−- Check LSP rename capabilities before sending rename action ([#2203](https://github.com/helix-editor/helix/pull/2203))
1277−- Register the `publish_diagnostics` LSP capability ([#2241](https://github.com/helix-editor/helix/pull/2241))
1278−- Fix paste direction for typed paste commands ([#2288](https://github.com/helix-editor/helix/pull/2288))
1279−- Improve handling of buffer-close ([#1397](https://github.com/helix-editor/helix/pull/1397))
1280−- Extend the tutor file ([#2133](https://github.com/helix-editor/helix/pull/2133))
1281−- Treat slashes as word separators in prompts ([#2315](https://github.com/helix-editor/helix/pull/2315))
1282−- Auto-complete directory members ([#1682](https://github.com/helix-editor/helix/pull/1682))
1283−- Allow disabling format-on-save as a global editor setting ([#2321](https://github.com/helix-editor/helix/pull/2321))
1284−- Wrap command palette in overlay ([#2378](https://github.com/helix-editor/helix/pull/2378))
1285−- Prevent selections from collapsing when inserting newlines ([#2414](https://github.com/helix-editor/helix/pull/2414))
1286−- Allow configuration of LSP request timeout ([#2405](https://github.com/helix-editor/helix/pull/2405))
1287−- Use debug console on Windows for DAP terminal ([#2294](https://github.com/helix-editor/helix/pull/2294))
1288−- Exclude cursor when deleting with `C-w` in insert mode ([#2431](https://github.com/helix-editor/helix/pull/2431))
1289−- Prevent panics from LSP parsing errors ([7ae6cad](https://github.com/helix-editor/helix/commit/7ae6cad))
1290−- Prevent panics from LSP responses without requests ([#2475](https://github.com/helix-editor/helix/pull/2475))
1291−- Fix scroll rate for documentation popups ([#2497](https://github.com/helix-editor/helix/pull/2497))
1292−- Support inserting into prompts from registers ([#2458](https://github.com/helix-editor/helix/pull/2458))
1293−- Separate theme scopes for diagnostic types ([#2437](https://github.com/helix-editor/helix/pull/2437))
1294−- Use `ui.menu` instead of `ui.statusline` for command completion menu theming ([82fb217](https://github.com/helix-editor/helix/commit/82fb217))
1295−- Panic when reloading a shrunk file ([#2506](https://github.com/helix-editor/helix/pull/2506))
1296−- Add theme key for picker separator ([#2523](https://github.com/helix-editor/helix/pull/2523))
1297−
1298−Themes:
1299−
1300−- Remove `ui.text` background from dark_plus ([#1950](https://github.com/helix-editor/helix/pull/1950))
1301−- Add `boo_berry` ([#1962](https://github.com/helix-editor/helix/pull/1962))
1302−- Update `dark_plus` markup colors ([#1989](https://github.com/helix-editor/helix/pull/1989))
1303−- Update `dark_plus` `tag` and `ui.menu.selected` colors ([#2014](https://github.com/helix-editor/helix/pull/2014))
1304−- Add `dracula_at_night` ([#2008](https://github.com/helix-editor/helix/pull/2008))
1305−- Improve `dracula` selection theming ([#2077](https://github.com/helix-editor/helix/pull/2077))
1306−- Remove dim attribute on `onedark` line-number gutter ([#2155](https://github.com/helix-editor/helix/pull/2155))
1307−- Add `tokyonight` ([#2162](https://github.com/helix-editor/helix/pull/2162))
1308−- Use border colors from the original `dark_plus` theme ([#2186](https://github.com/helix-editor/helix/pull/2186))
1309−- Add `autumn` ([#2212](https://github.com/helix-editor/helix/pull/2212), [#2270](https://github.com/helix-editor/helix/pull/2270), [#2531](https://github.com/helix-editor/helix/pull/2531))
1310−- Add `tokyonight_storm` ([#2240](https://github.com/helix-editor/helix/pull/2240))
1311−- Add `pop-dark` ([#2189](https://github.com/helix-editor/helix/pull/2189))
1312−- Fix `base16_terminal` theme using incorrect ansi-color ([#2279](https://github.com/helix-editor/helix/pull/2279))
1313−- Add `onelight` ([#2287](https://github.com/helix-editor/helix/pull/2287), [#2323](https://github.com/helix-editor/helix/pull/2323))
1314−- Add `ui.virtual` scopes to `onedark` theme ([3626e38](https://github.com/helix-editor/helix/commit/3626e38))
1315−- Add `night_owl` ([#2330](https://github.com/helix-editor/helix/pull/2330))
1316−- Use yellow foreground and red background for `monokai_pro_spectrum` ([#2433](https://github.com/helix-editor/helix/pull/2433))
1317−- Add `snazzy` ([#2473](https://github.com/helix-editor/helix/pull/2473))
1318−- Update `dark_plus` constructor color ([8e8d4ba](https://github.com/helix-editor/helix/commit/8e8d4ba))
1319−- Add `ui.menu` to the default theme ([e7e13dc](https://github.com/helix-editor/helix/commit/e7e13dc))
1320−- Add `ui.menu` to any themes missing the key ([9be810f](https://github.com/helix-editor/helix/commit/9be810f))
1321−- Add `catppuccin` ([#2546](https://github.com/helix-editor/helix/pull/2546), [7160e74](https://github.com/helix-editor/helix/commit/7160e74))
1322−
1323−LSP:
1324−
1325−- Use texlab for latex ([#1922](https://github.com/helix-editor/helix/pull/1922))
1326−- HTML ([#2018](https://github.com/helix-editor/helix/pull/2018))
1327−- JSON ([#2024](https://github.com/helix-editor/helix/pull/2024))
1328−- CSS ([#2025](https://github.com/helix-editor/helix/pull/2025))
1329−- PHP ([#2031](https://github.com/helix-editor/helix/pull/2031))
1330−- Swift ([#2033](https://github.com/helix-editor/helix/pull/2033))
1331−- OCaml ([#2035](https://github.com/helix-editor/helix/pull/2035))
1332−- Vue ([#2043](https://github.com/helix-editor/helix/pull/2043))
1333−- Yaml ([#2234](https://github.com/helix-editor/helix/pull/2234))
1334−- Vala ([#2243](https://github.com/helix-editor/helix/pull/2243))
1335−- TOML ([#2302](https://github.com/helix-editor/helix/pull/2302))
1336−- Java ([#2511](https://github.com/helix-editor/helix/pull/2511))
1337−- Lua ([#2560](https://github.com/helix-editor/helix/pull/2560))
1338−- Verilog ([#2552](https://github.com/helix-editor/helix/pull/2552))
1339−
1340−New Languages:
1341−
1342−- JSX ([#1906](https://github.com/helix-editor/helix/pull/1906), [a24fb17](https://github.com/helix-editor/helix/commit/a24fb17), [855e438](https://github.com/helix-editor/helix/commit/855e438), [#1921](https://github.com/helix-editor/helix/pull/1921))
1343−- Rust Object Notation (RON) ([#1925](https://github.com/helix-editor/helix/pull/1925))
1344−- R and R Markdown ([#1998](https://github.com/helix-editor/helix/pull/1998))
1345−- Swift ([#2033](https://github.com/helix-editor/helix/pull/2033))
1346−- EJS and ERB ([#2055](https://github.com/helix-editor/helix/pull/2055))
1347−- EEx ([9d095e0](https://github.com/helix-editor/helix/commit/9d095e0))
1348−- HEEx ([4836bb3](https://github.com/helix-editor/helix/commit/4836bb3), [#2149](https://github.com/helix-editor/helix/pull/2149))
1349−- SQL ([#2097](https://github.com/helix-editor/helix/pull/2097))
1350−- GDScript ([#1985](https://github.com/helix-editor/helix/pull/1985))
1351−- Nickel ([#2173](https://github.com/helix-editor/helix/pull/2173), [#2320](https://github.com/helix-editor/helix/pull/2320))
1352−- `go.mod` and `go.work` ([#2197](https://github.com/helix-editor/helix/pull/2197))
1353−- Nushell ([#2225](https://github.com/helix-editor/helix/pull/2225))
1354−- Vala ([#2243](https://github.com/helix-editor/helix/pull/2243))
1355−- Hare ([#2289](https://github.com/helix-editor/helix/pull/2289), [#2480](https://github.com/helix-editor/helix/pull/2480))
1356−- DeviceTree ([#2329](https://github.com/helix-editor/helix/pull/2329))
1357−- Cairo ([7387905](https://github.com/helix-editor/helix/commit/7387905))
1358−- CPON ([#2355](https://github.com/helix-editor/helix/pull/2355), [#2424](https://github.com/helix-editor/helix/pull/2424))
1359−- git-ignore ([#2397](https://github.com/helix-editor/helix/pull/2397))
1360−- git-attributes ([#2397](https://github.com/helix-editor/helix/pull/2397))
1361−- Odin ([#2399](https://github.com/helix-editor/helix/pull/2399), [#2464](https://github.com/helix-editor/helix/pull/2464))
1362−- Meson ([#2314](https://github.com/helix-editor/helix/pull/2314))
1363−- SSH Client Config ([#2498](https://github.com/helix-editor/helix/pull/2498))
1364−- Scheme ([d25bae8](https://github.com/helix-editor/helix/commit/d25bae8))
1365−- Verilog ([#2552](https://github.com/helix-editor/helix/pull/2552))
1366−
1367−Updated Languages and Queries:
1368−
1369−- Erlang ([e2a5071](https://github.com/helix-editor/helix/commit/e2a5071), [#2149](https://github.com/helix-editor/helix/pull/2149), [82da9bd](https://github.com/helix-editor/helix/commit/82da9bd))
1370−- Elixir ([1819478](https://github.com/helix-editor/helix/commit/1819478), [8c3c901](https://github.com/helix-editor/helix/commit/8c3c901), [4ac94a5](https://github.com/helix-editor/helix/commit/4ac94a5))
1371−- Gleam ([7cd6050](https://github.com/helix-editor/helix/commit/7cd6050), [45dd540](https://github.com/helix-editor/helix/commit/45dd540))
1372−- Bash ([#1917](https://github.com/helix-editor/helix/pull/1917))
1373−- JavaScript ([#2140](https://github.com/helix-editor/helix/pull/2140))
1374−- Ruby textobject queries ([#2143](https://github.com/helix-editor/helix/pull/2143))
1375−- Fix Golang textobject queries ([#2153](https://github.com/helix-editor/helix/pull/2153))
1376−- Add more bash and HCL file extensions ([#2201](https://github.com/helix-editor/helix/pull/2201))
1377−- Divide HCL and tfvars into separate languages ([#2244](https://github.com/helix-editor/helix/pull/2244))
1378−- Use JavaScript for `cjs` files ([#2387](https://github.com/helix-editor/helix/pull/2387))
1379−- Use Perl for `t` files ([#2395](https://github.com/helix-editor/helix/pull/2395))
1380−- Use `markup.list` scopes for lists ([#2401](https://github.com/helix-editor/helix/pull/2401))
1381−- Use PHP for `inc` files ([#2440](https://github.com/helix-editor/helix/pull/2440))
1382−- Improve Rust textobjects ([#2494](https://github.com/helix-editor/helix/pull/2494), [10463fe](https://github.com/helix-editor/helix/commit/10463fe))
1383−- Python ([#2451](https://github.com/helix-editor/helix/pull/2451))
1384−
1385−Packaging:
1386−
1387−- Use `builtins.fromTOML` in Nix Flake on Nix 2.6+ ([#1892](https://github.com/helix-editor/helix/pull/1892))
1388−- Shell auto-completion files are now available ([#2022](https://github.com/helix-editor/helix/pull/2022))
1389−- Create an AppImage on release ([#2089](https://github.com/helix-editor/helix/pull/2089))
1390−
1391−# 22.03 (2022-03-28)
1392−
1393−A big shout out to all the contributors! We had 51 contributors in this release.
1394−
1395−This release is particularly large and featureful. Check out some of the
1396−highlights in the [news section](https://helix-editor.com/news/release-22-03-highlights/).
1397−
1398−As usual, the following is a summary of each of the changes since the last release.
1399−For the full log, check out the [git log](https://github.com/helix-editor/helix/compare/v0.6.0..22.03).
1400−
1401−Breaking changes:
1402−
1403−- LSP config now lives under `editor.lsp` ([#1868](https://github.com/helix-editor/helix/pull/1868))
1404−- Expand-selection was moved from `]o` to `Alt-h` ([#1495](https://github.com/helix-editor/helix/pull/1495))
1405−
1406−Features:
1407−
1408−- Experimental Debug Adapter Protocol (DAP) support ([#574](https://github.com/helix-editor/helix/pull/574))
1409−- Primary cursor shape may now be customized per mode ([#1154](https://github.com/helix-editor/helix/pull/1154))
1410−- Overhaul incremental highlights and enable combined injections ([`6728344..4080341`](https://github.com/helix-editor/helix/compare/6728344..4080341))
1411−- Allow specifying file start position ([#445](https://github.com/helix-editor/helix/pull/445), [#1676](https://github.com/helix-editor/helix/pull/1676))
1412−- Dynamic line numbers ([#1522](https://github.com/helix-editor/helix/pull/1522))
1413−- Show an info box with the contents of registers ([#980](https://github.com/helix-editor/helix/pull/980))
1414−- Wrap-around behavior during search is now configurable ([#1516](https://github.com/helix-editor/helix/pull/1516))
1415−- Tree-sitter textobjects motions for classes, functions, and parameters ([#1619](https://github.com/helix-editor/helix/pull/1619), [#1708](https://github.com/helix-editor/helix/pull/1708), [#1805](https://github.com/helix-editor/helix/pull/1805))
1416−- Command palette: a picker for available commands ([#1400](https://github.com/helix-editor/helix/pull/1400))
1417−- LSP `workspace/configuration` and `workspace/didChangeConfiguration` support ([#1684](https://github.com/helix-editor/helix/pull/1684))
1418−- `hx --health [LANG]` command ([#1669](https://github.com/helix-editor/helix/pull/1669))
1419−- Refactor of the tree-sitter grammar system ([#1659](https://github.com/helix-editor/helix/pull/1659))
1420− - All submodules have been removed
1421− - New `hx --grammar {fetch|build}` flags for fetching and building tree-sitter grammars
1422− - A custom grammar selection may now be declared with the `use-grammars` key in `languages.toml`
1423−
1424−Commands:
1425−
1426−- `:cquit!` - quit forcefully with a non-zero exit-code ([#1414](https://github.com/helix-editor/helix/pull/1414))
1427−- `shrink_selection` - shrink the selection to a child tree-sitter node (`Alt-j`, [#1340](https://github.com/helix-editor/helix/pull/1340))
1428−- `:tree-sitter-subtree` - show the tree-sitter subtree under the primary selection ([#1453](https://github.com/helix-editor/helix/pull/1453), [#1524](https://github.com/helix-editor/helix/pull/1524))
1429−- Add `Alt-Backspace`, `Alt-<`, `Alt->`, and `Ctrl-j` to insert mode ([#1441](https://github.com/helix-editor/helix/pull/1441))
1430−- `select_next_sibling`, `select_prev_sibling` - select next and previous tree-sitter nodes (`Alt-l` and `Alt-h`, [#1495](https://github.com/helix-editor/helix/pull/1495))
1431−- `:buffer-close-all`, `:buffer-close-all!`, `:buffer-close-others`, and `:buffer-close-others!` ([#1677](https://github.com/helix-editor/helix/pull/1677))
1432−- `:vsplit-new` and `:hsplit-new` - open vertical and horizontal splits with new scratch buffers ([#1763](https://github.com/helix-editor/helix/pull/1763))
1433−- `:open-config` to open the config file and `:refresh-config` to refresh config after changes ([#1771](https://github.com/helix-editor/helix/pull/1771), [#1803](https://github.com/helix-editor/helix/pull/1803))
1434−
1435−Usability improvements and fixes:
1436−
1437−- Prevent `:cquit` from ignoring unsaved changes ([#1414](https://github.com/helix-editor/helix/pull/1414))
1438−- Scrolling view keeps selections ([#1420](https://github.com/helix-editor/helix/pull/1420))
1439−- Only use shellwords parsing on unix platforms ([`7767703`](https://github.com/helix-editor/helix/commit/7767703))
1440−- Fix slash in search selector status message ([#1449](https://github.com/helix-editor/helix/pull/1449))
1441−- Use `std::path::MAIN_SEPARATOR` to determine completion ([`3e4f815`](https://github.com/helix-editor/helix/commit/3e4f815))
1442−- Expand to current node with `expand_selection` when the node has no children ([#1454](https://github.com/helix-editor/helix/pull/1454))
1443−- Add vertical and horizontal splits to the buffer picker ([#1502](https://github.com/helix-editor/helix/pull/1502))
1444−- Use the correct language ID for JavaScript & TypeScript LSP ([#1466](https://github.com/helix-editor/helix/pull/1466))
1445−- Run format command for all buffers being written ([#1444](https://github.com/helix-editor/helix/pull/1444))
1446−- Fix panics during resizing ([#1408](https://github.com/helix-editor/helix/pull/1408))
1447−- Fix auto-pairs with CRLF ([#1470](https://github.com/helix-editor/helix/pull/1470))
1448−- Fix picker scrolling when the bottom is reached ([#1567](https://github.com/helix-editor/helix/pull/1567))
1449−- Use markup themes for the markdown component ([#1363](https://github.com/helix-editor/helix/pull/1363))
1450−- Automatically commit changes to history if not in insert mode ([`2a7ae96`](https://github.com/helix-editor/helix/commit/2a7ae96))
1451−- Render code-actions as a menu and add padding to popup ([`094a0aa`](https://github.com/helix-editor/helix/commit/094a0aa))
1452−- Only render menu scrollbar if the menu doesn't fit ([`f10a06f`](https://github.com/helix-editor/helix/commit/f10a06f), [`36b975c`](https://github.com/helix-editor/helix/commit/36b975c))
1453−- Parse git revision instead of tag for version ([`d3221b0`](https://github.com/helix-editor/helix/commit/d3221b0), [#1674](https://github.com/helix-editor/helix/pull/1674))
1454−- Fix incorrect last modified buffer ([#1621](https://github.com/helix-editor/helix/pull/1621))
1455−- Add `PageUp`, `PageDown`, `Ctrl-u`, `Ctrl-d`, `Home`, `End` bindings to the file picker ([#1612](https://github.com/helix-editor/helix/pull/1612))
1456−- Display buffer IDs in the buffer picker ([#1134](https://github.com/helix-editor/helix/pull/1134))
1457−- Allow multi-line prompt documentation ([`2af0432`](https://github.com/helix-editor/helix/commit/2af0432))
1458−- Ignore the `.git` directory from the file picker ([#1604](https://github.com/helix-editor/helix/pull/1604))
1459−- Allow separate styling for markup heading levels ([#1618](https://github.com/helix-editor/helix/pull/1618))
1460−- Automatically close popups ([#1285](https://github.com/helix-editor/helix/pull/1285))
1461−- Allow auto-pairs tokens to be configured ([#1624](https://github.com/helix-editor/helix/pull/1624))
1462−- Don't indent empty lines in `indent` command ([#1653](https://github.com/helix-editor/helix/pull/1653))
1463−- Ignore `Enter` keypress when a menu has no selection ([#1704](https://github.com/helix-editor/helix/pull/1704))
1464−- Show errors when surround deletions and replacements fail ([#1709](https://github.com/helix-editor/helix/pull/1709))
1465−- Show infobox hints for `mi` and `ma` ([#1686](https://github.com/helix-editor/helix/pull/1686))
1466−- Highlight matching text in file picker suggestions ([#1635](https://github.com/helix-editor/helix/pull/1635))
1467−- Allow capturing multiple nodes in textobject queries ([#1611](https://github.com/helix-editor/helix/pull/1611))
1468−- Make repeat operator work with completion edits ([#1640](https://github.com/helix-editor/helix/pull/1640))
1469−- Save to the jumplist when searching ([#1718](https://github.com/helix-editor/helix/pull/1718))
1470−- Fix bug with auto-replacement of components in compositor ([#1711](https://github.com/helix-editor/helix/pull/1711))
1471−- Use Kakoune logic for `align_selection` ([#1675](https://github.com/helix-editor/helix/pull/1675))
1472−- Fix `follows` for `nixpkgs` in `flake.nix` ([#1729](https://github.com/helix-editor/helix/pull/1729))
1473−- Performance improvements for the picker ([`78fba86`](https://github.com/helix-editor/helix/commit/78fba86))
1474−- Rename infobox theme scopes ([#1741](https://github.com/helix-editor/helix/pull/1741))
1475−- Fallback to broader scopes if a theme scope is not found ([#1714](https://github.com/helix-editor/helix/pull/1714))
1476−- Add arrow-keys bindings for tree-sitter sibling selection commands ([#1724](https://github.com/helix-editor/helix/pull/1724))
1477−- Fix a bug in LSP when creating a file in a folder that does not exist ([#1775](https://github.com/helix-editor/helix/pull/1775))
1478−- Use `^` and `$` regex location assertions for search ([#1793](https://github.com/helix-editor/helix/pull/1793))
1479−- Fix register names in `insert_register` command ([#1751](https://github.com/helix-editor/helix/pull/1751))
1480−- Perform extend line for all selections ([#1804](https://github.com/helix-editor/helix/pull/1804))
1481−- Prevent panic when moving in an empty picker ([#1786](https://github.com/helix-editor/helix/pull/1786))
1482−- Fix line number calculations for non CR/CRLF line breaks ([`b4a282f`](https://github.com/helix-editor/helix/commit/b4a282f), [`0b96201`](https://github.com/helix-editor/helix/commit/0b96201))
1483−- Deploy documentation for `master` builds separately from release docs ([#1783](https://github.com/helix-editor/helix/pull/1783))
1484−
1485−Themes:
1486−
1487−- Add everforest_light ([#1412](https://github.com/helix-editor/helix/pull/1412))
1488−- Add gruvbox_light ([#1509](https://github.com/helix-editor/helix/pull/1509))
1489−- Add modified background to dracula popup ([#1434](https://github.com/helix-editor/helix/pull/1434))
1490−- Markup support for monokai pro themes ([#1553](https://github.com/helix-editor/helix/pull/1553))
1491−- Markup support for dracula theme ([#1554](https://github.com/helix-editor/helix/pull/1554))
1492−- Add `tag` to gruvbox theme ([#1555](https://github.com/helix-editor/helix/pull/1555))
1493−- Markup support for remaining themes ([#1525](https://github.com/helix-editor/helix/pull/1525))
1494−- Serika light and dark ([#1566](https://github.com/helix-editor/helix/pull/1566))
1495−- Fix rose_pine and rose_pine_dawn popup background color ([#1606](https://github.com/helix-editor/helix/pull/1606))
1496−- Fix hover menu item text color in base16 themes ([#1668](https://github.com/helix-editor/helix/pull/1668))
1497−- Update markup heading styles for everforest ([#1687](https://github.com/helix-editor/helix/pull/1687))
1498−- Update markup heading styles for rose_pine themes ([#1706](https://github.com/helix-editor/helix/pull/1706))
1499−- Style bogster cursors ([`6a6a9ab`](https://github.com/helix-editor/helix/commit/6a6a9ab))
1500−- Fix `ui.selection` in rose_pine themes ([#1716](https://github.com/helix-editor/helix/pull/1716))
1501−- Use distinct colors for cursor and matched pair in gruvbox ([#1791](https://github.com/helix-editor/helix/pull/1791))
1502−- Improve colors for `ui.cursor.match` capture in some themes ([#1862](https://github.com/helix-editor/helix/pull/1862))
1503−
1504−LSP:
1505−
1506−- Add default language server for JavaScript ([#1457](https://github.com/helix-editor/helix/pull/1457))
1507−- Add `pom.xml` as maven root directory marker ([#1496](https://github.com/helix-editor/helix/pull/1496))
1508−- Haskell LSP ([#1556](https://github.com/helix-editor/helix/pull/1556))
1509−- C-sharp LSP support ([#1788](https://github.com/helix-editor/helix/pull/1788))
1510−- Clean up Julia LSP config ([#1811](https://github.com/helix-editor/helix/pull/1811))
1511−
1512−New Languages:
1513−
1514−- llvm-mir ([#1398](https://github.com/helix-editor/helix/pull/1398))
1515−- regex ([#1362](https://github.com/helix-editor/helix/pull/1362))
1516−- Make ([#1433](https://github.com/helix-editor/helix/pull/1433), [#1661](https://github.com/helix-editor/helix/pull/1661))
1517−- git-config ([#1426](https://github.com/helix-editor/helix/pull/1426))
1518−- Lean ([#1422](https://github.com/helix-editor/helix/pull/1422))
1519−- Elm ([#1514](https://github.com/helix-editor/helix/pull/1514))
1520−- GraphQL ([#1515](https://github.com/helix-editor/helix/pull/1515))
1521−- Twig ([#1602](https://github.com/helix-editor/helix/pull/1602))
1522−- Rescript ([#1616](https://github.com/helix-editor/helix/pull/1616), [#1863](https://github.com/helix-editor/helix/pull/1863))
1523−- Erlang ([#1657](https://github.com/helix-editor/helix/pull/1657))
1524−- Kotlin ([#1689](https://github.com/helix-editor/helix/pull/1689))
1525−- HCL ([#1705](https://github.com/helix-editor/helix/pull/1705), [#1726](https://github.com/helix-editor/helix/pull/1726))
1526−- Org ([#1845](https://github.com/helix-editor/helix/pull/1845))
1527−- Solidity ([#1848](https://github.com/helix-editor/helix/pull/1848), [#1854](https://github.com/helix-editor/helix/pull/1854))
1528−
1529−Updated Languages and Queries:
1530−
1531−- Textobject and indent queries for c and cpp ([#1293](https://github.com/helix-editor/helix/pull/1293))
1532−- Fix null and boolean constant highlights for nix ([#1428](https://github.com/helix-editor/helix/pull/1428))
1533−- Capture markdown link text as `markup.link.text` ([#1456](https://github.com/helix-editor/helix/pull/1456))
1534−- Update and re-enable Haskell ([#1417](https://github.com/helix-editor/helix/pull/1417), [#1520](https://github.com/helix-editor/helix/pull/1520))
1535−- Update Go with generics support ([`ddbf036`](https://github.com/helix-editor/helix/commit/ddbf036))
1536−- Use `tree-sitter-css` for SCSS files ([#1507](https://github.com/helix-editor/helix/pull/1507))
1537−- Update Zig ([#1501](https://github.com/helix-editor/helix/pull/1501))
1538−- Update PHP ([#1521](https://github.com/helix-editor/helix/pull/1521))
1539−- Expand language support for comment injections ([#1527](https://github.com/helix-editor/helix/pull/1527))
1540−- Use tree-sitter-bash for `.zshrc` and `.bashrc` ([`7d51042`](https://github.com/helix-editor/helix/commit/7d51042))
1541−- Use tree-sitter-bash for `.bash_profile` ([#1571](https://github.com/helix-editor/helix/pull/1571))
1542−- Use tree-sitter-bash for `.zshenv` and ZSH files ([#1574](https://github.com/helix-editor/helix/pull/1574))
1543−- IEx ([#1576](https://github.com/helix-editor/helix/pull/1576))
1544−- Textobject queries for PHP ([#1601](https://github.com/helix-editor/helix/pull/1601))
1545−- C-sharp highlight query improvements ([#1795](https://github.com/helix-editor/helix/pull/1795))
1546−- Git commit performance has been improved on large verbose commits ([#1838](https://github.com/helix-editor/helix/pull/1838))
1547−
1548−Packaging:
1549−
1550−- The submodules system has been replaced with command-line flags for fetching and building tree-sitter grammars ([#1659](https://github.com/helix-editor/helix/pull/1659))
1551−- Flake outputs are pushed to Cachix on each push to `master` ([#1721](https://github.com/helix-editor/helix/pull/1721))
1552−- Update flake's `nix-cargo-integration` to depend on `dream2nix` ([#1758](https://github.com/helix-editor/helix/pull/1758))
1553−
1554−# 0.6.0 (2022-01-04)
1555−
1556−Happy new year and a big shout out to all the contributors! We had 55 contributors in this release.
1557−
1558−Helix has popped up in DPorts and Fedora Linux via COPR ([#1270](https://github.com/helix-editor/helix/pull/1270))
1559−
1560−As usual the following is a brief summary, refer to the git history for a full log:
1561−
1562−Breaking changes:
1563−
1564−- fix: Normalize backtab into shift-tab
1565−
1566−Features:
1567−
1568−- Macros ([#1234](https://github.com/helix-editor/helix/pull/1234))
1569−- Add reverse search functionality ([#958](https://github.com/helix-editor/helix/pull/958))
1570−- Allow keys to be mapped to sequences of commands ([#589](https://github.com/helix-editor/helix/pull/589))
1571−- Make it possible to keybind TypableCommands ([#1169](https://github.com/helix-editor/helix/pull/1169))
1572−- Detect workspace root using language markers ([#1370](https://github.com/helix-editor/helix/pull/1370))
1573−- Add WORD textobject ([#991](https://github.com/helix-editor/helix/pull/991))
1574−- Add LSP rename_symbol (`space-r`) ([#1011](https://github.com/helix-editor/helix/pull/1011))
1575−- Added workspace_symbol_picker ([#1041](https://github.com/helix-editor/helix/pull/1041))
1576−- Detect filetype from shebang line ([#1001](https://github.com/helix-editor/helix/pull/1001))
1577−- Allow piping from stdin into a buffer on startup ([#996](https://github.com/helix-editor/helix/pull/996))
1578−- Add auto pairs for same-char pairs ([#1219](https://github.com/helix-editor/helix/pull/1219))
1579−- Update settings at runtime ([#798](https://github.com/helix-editor/helix/pull/798))
1580−- Enable thin LTO ([`cccc194`](https://github.com/helix-editor/helix/commit/cccc194))
1581−
1582−Commands:
1583−
1584−- `:wonly` -- window only ([#1057](https://github.com/helix-editor/helix/pull/1057))
1585−- buffer-close (`:bc`, `:bclose`) ([#1035](https://github.com/helix-editor/helix/pull/1035))
1586−- Add `:<line>` and `:goto <line>` commands ([#1128](https://github.com/helix-editor/helix/pull/1128))
1587−- `:sort` command ([#1288](https://github.com/helix-editor/helix/pull/1288))
1588−- Add m textobject for pair under cursor ([#961](https://github.com/helix-editor/helix/pull/961))
1589−- Implement "Goto next buffer / Goto previous buffer" commands ([#950](https://github.com/helix-editor/helix/pull/950))
1590−- Implement "Goto last modification" command ([#1067](https://github.com/helix-editor/helix/pull/1067))
1591−- Add trim_selections command ([#1092](https://github.com/helix-editor/helix/pull/1092))
1592−- Add movement shortcut for history ([#1088](https://github.com/helix-editor/helix/pull/1088))
1593−- Add command to inc/dec number under cursor ([#1027](https://github.com/helix-editor/helix/pull/1027))
1594− - Add support for dates for increment/decrement
1595−- Align selections (`&`) ([#1101](https://github.com/helix-editor/helix/pull/1101))
1596−- Implement no-yank delete/change ([#1099](https://github.com/helix-editor/helix/pull/1099))
1597−- Implement black hole register ([#1165](https://github.com/helix-editor/helix/pull/1165))
1598−- `gf` as goto_file (`gf`) ([#1102](https://github.com/helix-editor/helix/pull/1102))
1599−- Add last modified file (`gm`) ([#1093](https://github.com/helix-editor/helix/pull/1093))
1600−- ensure_selections_forward ([#1393](https://github.com/helix-editor/helix/pull/1393))
1601−- Readline style insert mode ([#1039](https://github.com/helix-editor/helix/pull/1039))
1602−
1603−Usability improvements and fixes:
1604−
1605−- Detect filetype on `:write` ([#1141](https://github.com/helix-editor/helix/pull/1141))
1606−- Add single and double quotes to matching pairs ([#995](https://github.com/helix-editor/helix/pull/995))
1607−- Launch with defaults upon invalid config/theme (rather than panicking) ([#982](https://github.com/helix-editor/helix/pull/982))
1608−- If switching away from an empty scratch buffer, remove it ([#935](https://github.com/helix-editor/helix/pull/935))
1609−- Truncate the starts of file paths instead of the ends in picker ([#951](https://github.com/helix-editor/helix/pull/951))
1610−- Truncate the start of file paths in the StatusLine ([#1351](https://github.com/helix-editor/helix/pull/1351))
1611−- Prevent picker from previewing binaries or large file ([#939](https://github.com/helix-editor/helix/pull/939))
1612−- Inform when reaching undo/redo bounds ([#981](https://github.com/helix-editor/helix/pull/981))
1613−- search_impl will only align cursor center when it isn't in view ([#959](https://github.com/helix-editor/helix/pull/959))
1614−- Add `<C-h>`, `<C-u>`, `<C-d>`, Delete in prompt mode ([#1034](https://github.com/helix-editor/helix/pull/1034))
1615−- Restore screen position when aborting search ([#1047](https://github.com/helix-editor/helix/pull/1047))
1616−- Buffer picker: show is_modifier flag ([#1020](https://github.com/helix-editor/helix/pull/1020))
1617−- Add commit hash to version info, if present ([#957](https://github.com/helix-editor/helix/pull/957))
1618−- Implement indent-aware delete ([#1120](https://github.com/helix-editor/helix/pull/1120))
1619−- Jump to end char of surrounding pair from any cursor pos ([#1121](https://github.com/helix-editor/helix/pull/1121))
1620−- File picker configuration ([#988](https://github.com/helix-editor/helix/pull/988))
1621−- Fix surround cursor position calculation ([#1183](https://github.com/helix-editor/helix/pull/1183))
1622−- Accept count for goto_window ([#1033](https://github.com/helix-editor/helix/pull/1033))
1623−- Make kill_to_line_end behave like Emacs ([#1235](https://github.com/helix-editor/helix/pull/1235))
1624−- Only use a single documentation popup ([#1241](https://github.com/helix-editor/helix/pull/1241))
1625−- ui: popup: Don't allow scrolling past the end of content ([`3307f44c`](https://github.com/helix-editor/helix/commit/3307f44c))
1626−- Open files with spaces in filename, allow opening multiple files ([#1231](https://github.com/helix-editor/helix/pull/1231))
1627−- Allow paste commands to take a count ([#1261](https://github.com/helix-editor/helix/pull/1261))
1628−- Auto pairs selection ([#1254](https://github.com/helix-editor/helix/pull/1254))
1629−- Use a fuzzy matcher for commands ([#1386](https://github.com/helix-editor/helix/pull/1386))
1630−- Add `<C-s>` to pick word under doc cursor to prompt line & search completion ([#831](https://github.com/helix-editor/helix/pull/831))
1631−- Fix `:earlier`/`:later` missing changeset update ([#1069](https://github.com/helix-editor/helix/pull/1069))
1632−- Support extend for multiple goto ([#909](https://github.com/helix-editor/helix/pull/909))
1633−- Add arrow-key bindings for window switching ([#933](https://github.com/helix-editor/helix/pull/933))
1634−- Implement key ordering for info box ([#952](https://github.com/helix-editor/helix/pull/952))
1635−
1636−LSP:
1637−- Implement MarkedString rendering ([`e128a8702`](https://github.com/helix-editor/helix/commit/e128a8702))
1638−- Don't panic if init fails ([`d31bef7`](https://github.com/helix-editor/helix/commit/d31bef7))
1639−- Configurable diagnostic severity ([#1325](https://github.com/helix-editor/helix/pull/1325))
1640−- Resolve completion item ([#1315](https://github.com/helix-editor/helix/pull/1315))
1641−- Code action command support ([#1304](https://github.com/helix-editor/helix/pull/1304))
1642−
1643−Grammars:
1644−
1645−- Adds mint language server ([#974](https://github.com/helix-editor/helix/pull/974))
1646−- Perl ([#978](https://github.com/helix-editor/helix/pull/978)) ([#1280](https://github.com/helix-editor/helix/pull/1280))
1647−- GLSL ([#993](https://github.com/helix-editor/helix/pull/993))
1648−- Racket ([#1143](https://github.com/helix-editor/helix/pull/1143))
1649−- WGSL ([#1166](https://github.com/helix-editor/helix/pull/1166))
1650−- LLVM ([#1167](https://github.com/helix-editor/helix/pull/1167)) ([#1388](https://github.com/helix-editor/helix/pull/1388)) ([#1409](https://github.com/helix-editor/helix/pull/1409)) ([#1398](https://github.com/helix-editor/helix/pull/1398))
1651−- Markdown ([`49e06787`](https://github.com/helix-editor/helix/commit/49e06787))
1652−- Scala ([#1278](https://github.com/helix-editor/helix/pull/1278))
1653−- Dart ([#1250](https://github.com/helix-editor/helix/pull/1250))
1654−- Fish ([#1308](https://github.com/helix-editor/helix/pull/1308))
1655−- Dockerfile ([#1303](https://github.com/helix-editor/helix/pull/1303))
1656−- Git (commit, rebase, diff) ([#1338](https://github.com/helix-editor/helix/pull/1338)) ([#1402](https://github.com/helix-editor/helix/pull/1402)) ([#1373](https://github.com/helix-editor/helix/pull/1373))
1657−- tree-sitter-comment ([#1300](https://github.com/helix-editor/helix/pull/1300))
1658−- Highlight comments in c, cpp, cmake and llvm ([#1309](https://github.com/helix-editor/helix/pull/1309))
1659−- Improve yaml syntax highlighting highlighting ([#1294](https://github.com/helix-editor/helix/pull/1294))
1660−- Improve rust syntax highlighting ([#1295](https://github.com/helix-editor/helix/pull/1295))
1661−- Add textobjects and indents to cmake ([#1307](https://github.com/helix-editor/helix/pull/1307))
1662−- Add textobjects and indents to c and cpp ([#1293](https://github.com/helix-editor/helix/pull/1293))
1663−
1664−New themes:
1665−
1666−- Solarized dark ([#999](https://github.com/helix-editor/helix/pull/999))
1667−- Solarized light ([#1010](https://github.com/helix-editor/helix/pull/1010))
1668−- Spacebones light ([#1131](https://github.com/helix-editor/helix/pull/1131))
1669−- Monokai Pro ([#1206](https://github.com/helix-editor/helix/pull/1206))
1670−- Base16 Light and Terminal ([#1078](https://github.com/helix-editor/helix/pull/1078))
1671− - and a default 16 color theme, truecolor detection
1672−- Dracula ([#1258](https://github.com/helix-editor/helix/pull/1258))
1673
1
1674# 0.5.0 (2021-10-28)
2# 0.5.0 (2021-10-28)
1675
3
@@ -1695,19 +23,19 @@ Features:
1695- LSP compatibility greatly improved for some implementations (Julia, Python, Typescript)
23- LSP compatibility greatly improved for some implementations (Julia, Python, Typescript)
1696- Autocompletion! Completion now triggers automatically after a set idle timeout
24- Autocompletion! Completion now triggers automatically after a set idle timeout
1697- Completion documentation is now displayed next to the popup ([#691](https://github.com/helix-editor/helix/pull/691))
25- Completion documentation is now displayed next to the popup ([#691](https://github.com/helix-editor/helix/pull/691))
1698−- Treesitter textobjects (select a function via `mf`, class via `mc`) ([#728](https://github.com/helix-editor/helix/pull/728))
26+- Treesitter textobjects (select a function via `mf`, class via `mc`) ([#728](https://github.com/helix-editor/helix/pull/728))
1699−- Global search across entire workspace `space+/` ([#651](https://github.com/helix-editor/helix/pull/651))
27+- Global search across entire workspace `space+/` ([#651](https://github.com/helix-editor/helix/pull/651))
1700- Relative line number support ([#485](https://github.com/helix-editor/helix/pull/485))
28- Relative line number support ([#485](https://github.com/helix-editor/helix/pull/485))
1701−- Prompts now store a history ([`72cf86e`](https://github.com/helix-editor/helix/commit/72cf86e))
29+- Prompts now store a history (72cf86e)
1702- `:vsplit` and `:hsplit` commands ([#639](https://github.com/helix-editor/helix/pull/639))
30- `:vsplit` and `:hsplit` commands ([#639](https://github.com/helix-editor/helix/pull/639))
1703- `C-w h/j/k/l` can now be used to navigate between splits ([#860](https://github.com/helix-editor/helix/pull/860))
31- `C-w h/j/k/l` can now be used to navigate between splits ([#860](https://github.com/helix-editor/helix/pull/860))
1704- `C-j` and `C-k` are now alternative keybindings to `C-n` and `C-p` in the UI ([#876](https://github.com/helix-editor/helix/pull/876))
32- `C-j` and `C-k` are now alternative keybindings to `C-n` and `C-p` in the UI ([#876](https://github.com/helix-editor/helix/pull/876))
1705- Shell commands (shell-pipe, pipe-to, shell-insert-output, shell-append-output, keep-pipe) ([#547](https://github.com/helix-editor/helix/pull/547))
33- Shell commands (shell-pipe, pipe-to, shell-insert-output, shell-append-output, keep-pipe) ([#547](https://github.com/helix-editor/helix/pull/547))
1706- Searching now defaults to smart case search (case insensitive unless uppercase is used) ([#761](https://github.com/helix-editor/helix/pull/761))
34- Searching now defaults to smart case search (case insensitive unless uppercase is used) ([#761](https://github.com/helix-editor/helix/pull/761))
1707- The preview pane was improved to highlight and center line ranges
35- The preview pane was improved to highlight and center line ranges
1708−- The user `languages.toml` is now merged into defaults, no longer need to copy the entire file ([`dc57f8dc`](https://github.com/helix-editor/helix/commit/dc57f8dc))
36+- The user `languages.toml` is now merged into defaults, no longer need to copy the entire file (dc57f8dc)
1709- Show hidden files in completions ([#648](https://github.com/helix-editor/helix/pull/648))
37- Show hidden files in completions ([#648](https://github.com/helix-editor/helix/pull/648))
1710−- Grammar injections are now properly handled ([`dd0b15e`](https://github.com/helix-editor/helix/commit/dd0b15e))
38+- Grammar injections are now properly handled (dd0b15e)
1711- `v` in select mode now switches back to normal mode ([#660](https://github.com/helix-editor/helix/pull/660))
39- `v` in select mode now switches back to normal mode ([#660](https://github.com/helix-editor/helix/pull/660))
1712- View mode can now be triggered as a "sticky" mode ([#719](https://github.com/helix-editor/helix/pull/719))
40- View mode can now be triggered as a "sticky" mode ([#719](https://github.com/helix-editor/helix/pull/719))
1713- `f`/`t` and object selection motions can now be repeated via `Alt-.` ([#891](https://github.com/helix-editor/helix/pull/891))
41- `f`/`t` and object selection motions can now be repeated via `Alt-.` ([#891](https://github.com/helix-editor/helix/pull/891))
@@ -1725,7 +53,7 @@ New grammars:
1725- Vue ([#787](https://github.com/helix-editor/helix/pull/787))
53- Vue ([#787](https://github.com/helix-editor/helix/pull/787))
1726- Tree-sitter queries ([#845](https://github.com/helix-editor/helix/pull/845))
54- Tree-sitter queries ([#845](https://github.com/helix-editor/helix/pull/845))
1727- CMake ([#888](https://github.com/helix-editor/helix/pull/888))
55- CMake ([#888](https://github.com/helix-editor/helix/pull/888))
1728−- Elixir (we switched over to the official grammar) ([`6c0786e`](https://github.com/helix-editor/helix/commit/6c0786e))
56+- Elixir (we switched over to the official grammar) (6c0786e)
1729- Language server definitions for Nix and Elixir ([#725](https://github.com/helix-editor/helix/pull/725))
57- Language server definitions for Nix and Elixir ([#725](https://github.com/helix-editor/helix/pull/725))
1730- Python now uses `pylsp` instead of `pyls`
58- Python now uses `pylsp` instead of `pyls`
1731- Python now supports indentation
59- Python now supports indentation
@@ -1742,22 +70,21 @@ Fixes:
1742
70
1743- Fix crash on empty rust file ([#592](https://github.com/helix-editor/helix/pull/592))
71- Fix crash on empty rust file ([#592](https://github.com/helix-editor/helix/pull/592))
1744- Exit select mode after toggle comment ([#598](https://github.com/helix-editor/helix/pull/598))
72- Exit select mode after toggle comment ([#598](https://github.com/helix-editor/helix/pull/598))
1745−- Pin popups with no positioning to the initial position ([`12ea3888`](https://github.com/helix-editor/helix/commit/12ea3888))
73+- Pin popups with no positioning to the initial position (12ea3888)
1746−- xsel copy should not freeze the editor ([`6dd7dc4`](https://github.com/helix-editor/helix/commit/6dd7dc4))
74+- xsel copy should not freeze the editor (6dd7dc4)
1747−- `*` now only sets the search register and doesn't jump to the next occurrence ([`3426285`](https://github.com/helix-editor/helix/commit/3426285))
75+- `*` now only sets the search register and doesn't jump to the next occurrence (3426285)
1748- Goto line start/end commands extend when in select mode ([#739](https://github.com/helix-editor/helix/pull/739))
76- Goto line start/end commands extend when in select mode ([#739](https://github.com/helix-editor/helix/pull/739))
1749−- Fix documentation popups sometimes not getting fully highlighted ([`066367c`](https://github.com/helix-editor/helix/commit/066367c))
77+- Fix documentation popups sometimes not getting fully highlighted (066367c)
1750−- Refactor apply_workspace_edit to remove assert ([`b02d872`](https://github.com/helix-editor/helix/commit/b02d872))
78+- Refactor apply_workspace_edit to remove assert (b02d872)
1751−- Wrap around the top of the picker menu when scrolling ([`c7d6e44`](https://github.com/helix-editor/helix/commit/c7d6e44))
79+- Wrap around the top of the picker menu when scrolling (c7d6e44)
1752−- Don't allow closing the last split if there's unsaved changes ([`3ff5b00`](https://github.com/helix-editor/helix/commit/3ff5b00))
80+- Don't allow closing the last split if there's unsaved changes (3ff5b00)
1753−- Indentation used different default on hx vs hx new_file.txt ([`c913bad`](https://github.com/helix-editor/helix/commit/c913bad))
81+- Indentation used different default on hx vs hx new_file.txt (c913bad)
1754
82
1755# 0.4.1 (2021-08-14)
83# 0.4.1 (2021-08-14)
1756
84
1757A minor release that includes:
85A minor release that includes:
1758−
1759- A fix for rendering glitches that would occur after editing with multiple selections.
86- A fix for rendering glitches that would occur after editing with multiple selections.
1760−- CI fix for grammars not being cross-compiled for aarch64
87+- CI fix for grammars not being cross-compiled for aarch64
1761
88
1762# 0.4.0 (2021-08-13)
89# 0.4.0 (2021-08-13)
1763
90
@@ -1777,10 +104,10 @@ selections in the future as well as resolves many bugs and edge cases.
1777- Autoinfo: `whichkey`-like popups which show available sub-mode shortcuts ([#316](https://github.com/helix-editor/helix/pull/316))
104- Autoinfo: `whichkey`-like popups which show available sub-mode shortcuts ([#316](https://github.com/helix-editor/helix/pull/316))
1778- Added WORD movements (W/B/E) ([#390](https://github.com/helix-editor/helix/pull/390))
105- Added WORD movements (W/B/E) ([#390](https://github.com/helix-editor/helix/pull/390))
1779- Vertical selections (repeat selection above/below) ([#462](https://github.com/helix-editor/helix/pull/462))
106- Vertical selections (repeat selection above/below) ([#462](https://github.com/helix-editor/helix/pull/462))
1780−- Selection rotation via `(` and `)` ([`66a90130`](https://github.com/helix-editor/helix/commit/66a90130a5f99d769e9f6034025297f78ecaa3ec))
107+- Selection rotation via `(` and `)` ([66a90130](https://github.com/helix-editor/helix/commit/66a90130a5f99d769e9f6034025297f78ecaa3ec))
1781−- Selection contents rotation via `Alt-(` and `Alt-)` ([`02cba2a`](https://github.com/helix-editor/helix/commit/02cba2a7f403f48eccb18100fb751f7b42373dba))
108+- Selection contents rotation via `Alt-(` and `Alt-)` ([02cba2a](https://github.com/helix-editor/helix/commit/02cba2a7f403f48eccb18100fb751f7b42373dba))
1782−- Completion behavior improvements ([`f917b5a4`](https://github.com/helix-editor/helix/commit/f917b5a441ff3ae582358b6939ffbf889f4aa530), [`627b899`](https://github.com/helix-editor/helix/commit/627b89931576f7af86166ae8d5cbc55537877473))
109+- Completion behavior improvements ([f917b5a4](https://github.com/helix-editor/helix/commit/f917b5a441ff3ae582358b6939ffbf889f4aa530), [627b899](https://github.com/helix-editor/helix/commit/627b89931576f7af86166ae8d5cbc55537877473))
1783−- Fixed a language server crash ([`385a6b5a`](https://github.com/helix-editor/helix/commit/385a6b5a1adddfc26e917982641530e1a7c7aa81))
110+- Fixed a language server crash ([385a6b5a](https://github.com/helix-editor/helix/commit/385a6b5a1adddfc26e917982641530e1a7c7aa81))
1784- Case change commands (`` ` ``, `~`, ``<a-`>``) ([#441](https://github.com/helix-editor/helix/pull/441))
111- Case change commands (`` ` ``, `~`, ``<a-`>``) ([#441](https://github.com/helix-editor/helix/pull/441))
1785- File pickers (including goto) now provide a preview! ([#534](https://github.com/helix-editor/helix/pull/534))
112- File pickers (including goto) now provide a preview! ([#534](https://github.com/helix-editor/helix/pull/534))
1786- Injection query support. Rust macro calls and embedded languages are now properly highlighted ([#430](https://github.com/helix-editor/helix/pull/430))
113- Injection query support. Rust macro calls and embedded languages are now properly highlighted ([#430](https://github.com/helix-editor/helix/pull/430))
@@ -1796,7 +123,7 @@ selections in the future as well as resolves many bugs and edge cases.
1796- Comment toggling now uses a language specific comment token ([#463](https://github.com/helix-editor/helix/pull/463))
123- Comment toggling now uses a language specific comment token ([#463](https://github.com/helix-editor/helix/pull/463))
1797- Julia support ([#413](https://github.com/helix-editor/helix/pull/413))
124- Julia support ([#413](https://github.com/helix-editor/helix/pull/413))
1798- Java support ([#448](https://github.com/helix-editor/helix/pull/448))
125- Java support ([#448](https://github.com/helix-editor/helix/pull/448))
1799−- Prompts have an (in-memory) history ([`63e54e30`](https://github.com/helix-editor/helix/commit/63e54e30a74bb0d1d782877ddbbcf95f2817d061))
126+- Prompts have an (in-memory) history ([63e54e30](https://github.com/helix-editor/helix/commit/63e54e30a74bb0d1d782877ddbbcf95f2817d061))
1800
127
1801# 0.3.0 (2021-06-27)
128# 0.3.0 (2021-06-27)
1802
129
@@ -1810,7 +137,7 @@ Highlights:
1810- Support for other line endings (CRLF). Significantly improved Windows support. ([#224](https://github.com/helix-editor/helix/pull/224))
137- Support for other line endings (CRLF). Significantly improved Windows support. ([#224](https://github.com/helix-editor/helix/pull/224))
1811- Encodings other than UTF-8 are now supported! ([#228](https://github.com/helix-editor/helix/pull/228))
138- Encodings other than UTF-8 are now supported! ([#228](https://github.com/helix-editor/helix/pull/228))
1812- Key bindings can now be configured via a `config.toml` file ([#268](https://github.com/helix-editor/helix/pull/268))
139- Key bindings can now be configured via a `config.toml` file ([#268](https://github.com/helix-editor/helix/pull/268))
1813−- Theme can now be configured and changed at runtime. ([Please feel free to contribute more themes!](https://github.com/helix-editor/helix/tree/master/runtime/themes)) ([#267](https://github.com/helix-editor/helix/pull/267))
140+- Theme can now be configured and changed at runtime ([please feel free to contribute more themes!](https://github.com/helix-editor/helix/tree/master/runtime/themes)) ([#267](https://github.com/helix-editor/helix/pull/267))
1814- System clipboard yank/paste is now supported! ([#310](https://github.com/helix-editor/helix/pull/310))
141- System clipboard yank/paste is now supported! ([#310](https://github.com/helix-editor/helix/pull/310))
1815- Surround commands were implemented ([#320](https://github.com/helix-editor/helix/pull/320))
142- Surround commands were implemented ([#320](https://github.com/helix-editor/helix/pull/320))
1816
143
@@ -1827,7 +154,7 @@ Features:
1827- Code is being migrated from helix-term to helix-view (prerequisite for
154- Code is being migrated from helix-term to helix-view (prerequisite for
1828 alternative frontends) ([#366](https://github.com/helix-editor/helix/pull/366))
155 alternative frontends) ([#366](https://github.com/helix-editor/helix/pull/366))
1829- `x` and `X` merged
156- `x` and `X` merged
1830− ([`f41688d9`](https://github.com/helix-editor/helix/commit/f41688d960ef89c29c4a51c872b8406fb8f81a85))
157+ ([f41688d9](https://github.com/helix-editor/helix/commit/f41688d960ef89c29c4a51c872b8406fb8f81a85))
1831
158
1832Fixes:
159Fixes:
1833
160
@@ -1835,12 +162,12 @@ Fixes:
1835- A bunch of bugs regarding `o`/`O` behavior ([#281](https://github.com/helix-editor/helix/pull/281))
162- A bunch of bugs regarding `o`/`O` behavior ([#281](https://github.com/helix-editor/helix/pull/281))
1836- `~` expansion now works in file completion ([#284](https://github.com/helix-editor/helix/pull/284))
163- `~` expansion now works in file completion ([#284](https://github.com/helix-editor/helix/pull/284))
1837- Several UI related overflow crashes ([#318](https://github.com/helix-editor/helix/pull/318))
164- Several UI related overflow crashes ([#318](https://github.com/helix-editor/helix/pull/318))
1838−- Fix a test failure occurring only on `test --release` ([`4f108ab1`](https://github.com/helix-editor/helix/commit/4f108ab1b2197809506bd7305ad903a3525eabfa))
165+- Fix a test failure occuring only on `test --release` ([4f108ab1](https://github.com/helix-editor/helix/commit/4f108ab1b2197809506bd7305ad903a3525eabfa))
1839- Prompts now support unicode input ([#295](https://github.com/helix-editor/helix/pull/295))
166- Prompts now support unicode input ([#295](https://github.com/helix-editor/helix/pull/295))
1840- Completion documentation no longer overlaps the popup ([#322](https://github.com/helix-editor/helix/pull/322))
167- Completion documentation no longer overlaps the popup ([#322](https://github.com/helix-editor/helix/pull/322))
1841−- Fix a crash when trying to select `^` ([`9c534614`](https://github.com/helix-editor/helix/commit/9c53461429a3e72e3b1fb87d7ca490e168d7dee2))
168+- Fix a crash when trying to select `^` ([9c534614](https://github.com/helix-editor/helix/commit/9c53461429a3e72e3b1fb87d7ca490e168d7dee2))
1842−- Prompt completions are now paginated ([`39dc09e6`](https://github.com/helix-editor/helix/commit/39dc09e6c4172299bc79de4c1c52288d3f624bd7))
169+- Prompt completions are now paginated ([39dc09e6](https://github.com/helix-editor/helix/commit/39dc09e6c4172299bc79de4c1c52288d3f624bd7))
1843−- Goto did not work on Windows ([`503ca112`](https://github.com/helix-editor/helix/commit/503ca112ae57ebdf3ea323baf8940346204b46d2))
170+- Goto did not work on Windows ([503ca112](https://github.com/helix-editor/helix/commit/503ca112ae57ebdf3ea323baf8940346204b46d2))
1844
171
1845# 0.2.1
172# 0.2.1
1846
173
@@ -1856,9 +183,9 @@ to distinguish it in bug reports..
1856
183
1857- The `runtime/` directory is now properly detected on binary releases and
184- The `runtime/` directory is now properly detected on binary releases and
1858 on cargo run. `~/.config/helix/runtime` can also be used.
185 on cargo run. `~/.config/helix/runtime` can also be used.
1859−- Registers can now be selected via " (for example, `"ay`)
186+- Registers can now be selected via " (for example `"ay`)
1860- Support for Nix files was added
187- Support for Nix files was added
1861−- Movement is now fully tested and matches Kakoune implementation
188+- Movement is now fully tested and matches kakoune implementation
1862- A per-file LSP symbol picker was added to space+s
189- A per-file LSP symbol picker was added to space+s
1863- Selection can be replaced with yanked text via R
190- Selection can be replaced with yanked text via R
1864
191
@@ -1882,7 +209,7 @@ Keymaps:
1882- The runtime/ can now optionally be embedded in the binary
209- The runtime/ can now optionally be embedded in the binary
1883- Haskell syntax added
210- Haskell syntax added
1884- Window mode (ctrl-w) added
211- Window mode (ctrl-w) added
1885−- Show matching bracket (Vim's matchbrackets)
212+- Show matching bracket (vim's matchbrackets)
1886- Themes now support style modifiers
213- Themes now support style modifiers
1887- First user contributed theme
214- First user contributed theme
1888- Create a document if it doesn't exist yet on save
215- Create a document if it doesn't exist yet on save
Cargo.lock+656−2038
@@ -2,96 +2,32 @@
2# It is not intended for manual editing.
2# It is not intended for manual editing.
3version = 3
3version = 3
4
4
5−[[package]]
6−name = "addr2line"
7−version = "0.20.0"
8−source = "registry+https://github.com/rust-lang/crates.io-index"
9−checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
10−dependencies = [
11− "gimli",
12−]
13−
14−[[package]]
15−name = "adler"
16−version = "1.0.2"
17−source = "registry+https://github.com/rust-lang/crates.io-index"
18−checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
19−
20−[[package]]
21−name = "ahash"
22−version = "0.8.6"
23−source = "registry+https://github.com/rust-lang/crates.io-index"
24−checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
25−dependencies = [
26− "cfg-if",
27− "getrandom",
28− "once_cell",
29− "version_check",
30− "zerocopy",
31−]
32−
33[[package]]
5[[package]]
34name = "aho-corasick"
6name = "aho-corasick"
35−version = "1.1.2"
7+version = "0.7.18"
36source = "registry+https://github.com/rust-lang/crates.io-index"
8source = "registry+https://github.com/rust-lang/crates.io-index"
37−checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
9+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
38dependencies = [
10dependencies = [
39 "memchr",
11 "memchr",
40]
12]
41
13
42−[[package]]
43−name = "allocator-api2"
44−version = "0.2.14"
45−source = "registry+https://github.com/rust-lang/crates.io-index"
46−checksum = "c4f263788a35611fba42eb41ff811c5d0360c58b97402570312a350736e2542e"
47−
48−[[package]]
49−name = "android-tzdata"
50−version = "0.1.1"
51−source = "registry+https://github.com/rust-lang/crates.io-index"
52−checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
53−
54−[[package]]
55−name = "android_system_properties"
56−version = "0.1.5"
57−source = "registry+https://github.com/rust-lang/crates.io-index"
58−checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
59−dependencies = [
60− "libc",
61−]
62−
63[[package]]
14[[package]]
64name = "anyhow"
15name = "anyhow"
65−version = "1.0.76"
16+version = "1.0.52"
66source = "registry+https://github.com/rust-lang/crates.io-index"
17source = "registry+https://github.com/rust-lang/crates.io-index"
67−checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355"
18+checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
68
19
69[[package]]
20[[package]]
70name = "arc-swap"
21name = "arc-swap"
71−version = "1.6.0"
22+version = "1.5.0"
72source = "registry+https://github.com/rust-lang/crates.io-index"
23source = "registry+https://github.com/rust-lang/crates.io-index"
73−checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
24+checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f"
74
25
75[[package]]
26[[package]]
76name = "autocfg"
27name = "autocfg"
77−version = "1.1.0"
28+version = "1.0.1"
78−source = "registry+https://github.com/rust-lang/crates.io-index"
79−checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
80−
81−[[package]]
82−name = "backtrace"
83−version = "0.3.68"
84source = "registry+https://github.com/rust-lang/crates.io-index"
29source = "registry+https://github.com/rust-lang/crates.io-index"
85−checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
30+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
86−dependencies = [
87− "addr2line",
88− "cc",
89− "cfg-if",
90− "libc",
91− "miniz_oxide",
92− "object",
93− "rustc-demangle",
94−]
95
31
96[[package]]
32[[package]]
97name = "bitflags"
33name = "bitflags"
@@ -99,43 +35,28 @@ version = "1.3.2"
99source = "registry+https://github.com/rust-lang/crates.io-index"
35source = "registry+https://github.com/rust-lang/crates.io-index"
100checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
36checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
101
37
102−[[package]]
103−name = "bitflags"
104−version = "2.4.1"
105−source = "registry+https://github.com/rust-lang/crates.io-index"
106−checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
107−
108[[package]]
38[[package]]
109name = "bstr"
39name = "bstr"
110−version = "1.8.0"
40+version = "0.2.17"
111source = "registry+https://github.com/rust-lang/crates.io-index"
41source = "registry+https://github.com/rust-lang/crates.io-index"
112−checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
42+checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
113dependencies = [
43dependencies = [
44+ "lazy_static",
114 "memchr",
45 "memchr",
115 "regex-automata",
46 "regex-automata",
116− "serde",
117−]
118−
119−[[package]]
120−name = "btoi"
121−version = "0.4.3"
122−source = "registry+https://github.com/rust-lang/crates.io-index"
123−checksum = "9dd6407f73a9b8b6162d8a2ef999fe6afd7cc15902ebf42c5cd296addf17e0ad"
124−dependencies = [
125− "num-traits",
126]
47]
127
48
128[[package]]
49[[package]]
129−name = "bumpalo"
50+name = "bytecount"
130−version = "3.12.0"
51+version = "0.6.2"
131source = "registry+https://github.com/rust-lang/crates.io-index"
52source = "registry+https://github.com/rust-lang/crates.io-index"
132−checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
53+checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e"
133
54
134[[package]]
55[[package]]
135name = "bytes"
56name = "bytes"
136−version = "1.4.0"
57+version = "1.1.0"
137source = "registry+https://github.com/rust-lang/crates.io-index"
58source = "registry+https://github.com/rust-lang/crates.io-index"
138−checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
59+checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
139
60
140[[package]]
61[[package]]
141name = "cassowary"
62name = "cassowary"
@@ -145,12 +66,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
145
66
146[[package]]
67[[package]]
147name = "cc"
68name = "cc"
148−version = "1.0.84"
69+version = "1.0.72"
149source = "registry+https://github.com/rust-lang/crates.io-index"
70source = "registry+https://github.com/rust-lang/crates.io-index"
150−checksum = "0f8e7c90afad890484a21653d08b6e209ae34770fb5ee298f9c699fcc1e5c856"
71+checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
151−dependencies = [
152− "libc",
153−]
154
72
155[[package]]
73[[package]]
156name = "cfg-if"
74name = "cfg-if"
@@ -171,39 +89,25 @@ dependencies = [
171
89
172[[package]]
90[[package]]
173name = "chrono"
91name = "chrono"
174−version = "0.4.31"
92+version = "0.4.19"
175source = "registry+https://github.com/rust-lang/crates.io-index"
93source = "registry+https://github.com/rust-lang/crates.io-index"
176−checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
94+checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
177dependencies = [
95dependencies = [
178− "android-tzdata",
96+ "libc",
179− "iana-time-zone",
97+ "num-integer",
180 "num-traits",
98 "num-traits",
181− "windows-targets 0.48.0",
99+ "winapi",
182]
100]
183
101
184[[package]]
102[[package]]
185name = "clipboard-win"
103name = "clipboard-win"
186−version = "5.0.0"
104+version = "4.2.2"
187source = "registry+https://github.com/rust-lang/crates.io-index"
105source = "registry+https://github.com/rust-lang/crates.io-index"
188−checksum = "c57002a5d9be777c1ef967e33674dac9ebd310d8893e4e3437b14d5f0f6372cc"
106+checksum = "3db8340083d28acb43451166543b98c838299b7e0863621be53a338adceea0ed"
189dependencies = [
107dependencies = [
190 "error-code",
108 "error-code",
191−]
109+ "str-buf",
192−
110+ "winapi",
193−[[package]]
194−name = "clru"
195−version = "0.6.1"
196−source = "registry+https://github.com/rust-lang/crates.io-index"
197−checksum = "b8191fa7302e03607ff0e237d4246cc043ff5b3cb9409d995172ba3bea16b807"
198−
199−[[package]]
200−name = "codespan-reporting"
201−version = "0.11.1"
202−source = "registry+https://github.com/rust-lang/crates.io-index"
203−checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
204−dependencies = [
205− "termcolor",
206− "unicode-width",
207]
111]
208
112
209[[package]]
113[[package]]
@@ -215,79 +119,24 @@ dependencies = [
215 "memchr",
119 "memchr",
216]
120]
217
121
218−[[package]]
219−name = "core-foundation-sys"
220−version = "0.8.4"
221−source = "registry+https://github.com/rust-lang/crates.io-index"
222−checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
223−
224−[[package]]
225−name = "cov-mark"
226−version = "1.1.0"
227−source = "registry+https://github.com/rust-lang/crates.io-index"
228−checksum = "9ffa3d3e0138386cd4361f63537765cac7ee40698028844635a54495a92f67f3"
229−
230−[[package]]
231−name = "crc32fast"
232−version = "1.3.2"
233−source = "registry+https://github.com/rust-lang/crates.io-index"
234−checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
235−dependencies = [
236− "cfg-if",
237−]
238−
239−[[package]]
240−name = "crossbeam-channel"
241−version = "0.5.8"
242−source = "registry+https://github.com/rust-lang/crates.io-index"
243−checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
244−dependencies = [
245− "cfg-if",
246− "crossbeam-utils",
247−]
248−
249−[[package]]
250−name = "crossbeam-deque"
251−version = "0.8.3"
252−source = "registry+https://github.com/rust-lang/crates.io-index"
253−checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
254−dependencies = [
255− "cfg-if",
256− "crossbeam-epoch",
257− "crossbeam-utils",
258−]
259−
260−[[package]]
261−name = "crossbeam-epoch"
262−version = "0.9.15"
263−source = "registry+https://github.com/rust-lang/crates.io-index"
264−checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
265−dependencies = [
266− "autocfg",
267− "cfg-if",
268− "crossbeam-utils",
269− "memoffset",
270− "scopeguard",
271−]
272−
273[[package]]
122[[package]]
274name = "crossbeam-utils"
123name = "crossbeam-utils"
275−version = "0.8.16"
124+version = "0.8.5"
276source = "registry+https://github.com/rust-lang/crates.io-index"
125source = "registry+https://github.com/rust-lang/crates.io-index"
277−checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
126+checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
278dependencies = [
127dependencies = [
279 "cfg-if",
128 "cfg-if",
129+ "lazy_static",
280]
130]
281
131
282[[package]]
132[[package]]
283name = "crossterm"
133name = "crossterm"
284−version = "0.27.0"
134+version = "0.22.1"
285source = "registry+https://github.com/rust-lang/crates.io-index"
135source = "registry+https://github.com/rust-lang/crates.io-index"
286−checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
136+checksum = "c85525306c4291d1b73ce93c8acf9c339f9b213aef6c1d85c3830cbf1c16325c"
287dependencies = [
137dependencies = [
288− "bitflags 2.4.1",
138+ "bitflags",
289 "crossterm_winapi",
139 "crossterm_winapi",
290− "filedescriptor",
291 "futures-core",
140 "futures-core",
292 "libc",
141 "libc",
293 "mio",
142 "mio",
@@ -299,74 +148,45 @@ dependencies = [
299
148
300[[package]]
149[[package]]
301name = "crossterm_winapi"
150name = "crossterm_winapi"
302−version = "0.9.1"
151+version = "0.9.0"
303source = "registry+https://github.com/rust-lang/crates.io-index"
152source = "registry+https://github.com/rust-lang/crates.io-index"
304−checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
153+checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
305dependencies = [
154dependencies = [
306 "winapi",
155 "winapi",
307]
156]
308
157
309[[package]]
158[[package]]
310−name = "cxx"
159+name = "dirs-next"
311−version = "1.0.94"
312−source = "registry+https://github.com/rust-lang/crates.io-index"
313−checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93"
314−dependencies = [
315− "cc",
316− "cxxbridge-flags",
317− "cxxbridge-macro",
318− "link-cplusplus",
319−]
320−
321−[[package]]
322−name = "cxx-build"
323−version = "1.0.94"
160+version = "2.0.0"
324source = "registry+https://github.com/rust-lang/crates.io-index"
161source = "registry+https://github.com/rust-lang/crates.io-index"
325−checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b"
162+checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
326dependencies = [
163dependencies = [
327− "cc",
164+ "cfg-if",
328− "codespan-reporting",
165+ "dirs-sys-next",
329− "once_cell",
330− "proc-macro2",
331− "quote",
332− "scratch",
333− "syn 2.0.38",
334]
166]
335
167
336[[package]]
168[[package]]
337−name = "cxxbridge-flags"
169+name = "dirs-sys-next"
338−version = "1.0.94"
170+version = "0.1.2"
339−source = "registry+https://github.com/rust-lang/crates.io-index"
340−checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb"
341−
342−[[package]]
343−name = "cxxbridge-macro"
344−version = "1.0.94"
345source = "registry+https://github.com/rust-lang/crates.io-index"
171source = "registry+https://github.com/rust-lang/crates.io-index"
346−checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5"
172+checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
347dependencies = [
173dependencies = [
348− "proc-macro2",
174+ "libc",
349− "quote",
175+ "redox_users",
350− "syn 2.0.38",
176+ "winapi",
351]
177]
352
178
353−[[package]]
354−name = "dunce"
355−version = "1.0.4"
356−source = "registry+https://github.com/rust-lang/crates.io-index"
357−checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
358−
359[[package]]
179[[package]]
360name = "either"
180name = "either"
361−version = "1.8.1"
181+version = "1.6.1"
362source = "registry+https://github.com/rust-lang/crates.io-index"
182source = "registry+https://github.com/rust-lang/crates.io-index"
363−checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
183+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
364
184
365[[package]]
185[[package]]
366name = "encoding_rs"
186name = "encoding_rs"
367−version = "0.8.33"
187+version = "0.8.30"
368source = "registry+https://github.com/rust-lang/crates.io-index"
188source = "registry+https://github.com/rust-lang/crates.io-index"
369−checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
189+checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df"
370dependencies = [
190dependencies = [
371 "cfg-if",
191 "cfg-if",
372]
192]
@@ -381,103 +201,72 @@ dependencies = [
381]
201]
382
202
383[[package]]
203[[package]]
384−name = "equivalent"
204+name = "error-code"
385−version = "1.0.0"
386−source = "registry+https://github.com/rust-lang/crates.io-index"
387−checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1"
388−
389−[[package]]
390−name = "errno"
391−version = "0.3.8"
205+version = "2.3.0"
392source = "registry+https://github.com/rust-lang/crates.io-index"
206source = "registry+https://github.com/rust-lang/crates.io-index"
393−checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
207+checksum = "b5115567ac25674e0043e472be13d14e537f37ea8aa4bdc4aef0c89add1db1ff"
394dependencies = [
208dependencies = [
395 "libc",
209 "libc",
396− "windows-sys 0.52.0",
210+ "str-buf",
397]
211]
398
212
399−[[package]]
400−name = "error-code"
401−version = "3.0.0"
402−source = "registry+https://github.com/rust-lang/crates.io-index"
403−checksum = "281e452d3bad4005426416cdba5ccfd4f5c1280e10099e21db27f7c1c28347fc"
404−
405[[package]]
213[[package]]
406name = "etcetera"
214name = "etcetera"
407−version = "0.8.0"
215+version = "0.3.2"
408source = "registry+https://github.com/rust-lang/crates.io-index"
216source = "registry+https://github.com/rust-lang/crates.io-index"
409−checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943"
217+checksum = "016b04fd1e94fb833d432634245c9bb61cf1c7409668a0e7d4c3ab00c5172dec"
410dependencies = [
218dependencies = [
411 "cfg-if",
219 "cfg-if",
412− "home",
220+ "dirs-next",
413− "windows-sys 0.48.0",
221+ "thiserror",
414−]
415−
416−[[package]]
417−name = "faster-hex"
418−version = "0.9.0"
419−source = "registry+https://github.com/rust-lang/crates.io-index"
420−checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183"
421−dependencies = [
422− "serde",
423]
222]
424
223
425−[[package]]
426−name = "fastrand"
427−version = "2.0.0"
428−source = "registry+https://github.com/rust-lang/crates.io-index"
429−checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
430−
431[[package]]
224[[package]]
432name = "fern"
225name = "fern"
433−version = "0.6.2"
226+version = "0.6.0"
434source = "registry+https://github.com/rust-lang/crates.io-index"
227source = "registry+https://github.com/rust-lang/crates.io-index"
435−checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee"
228+checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065"
436dependencies = [
229dependencies = [
437 "log",
230 "log",
438]
231]
439
232
440[[package]]
233[[package]]
441−name = "filedescriptor"
234+name = "fnv"
442−version = "0.8.2"
235+version = "1.0.7"
443source = "registry+https://github.com/rust-lang/crates.io-index"
236source = "registry+https://github.com/rust-lang/crates.io-index"
444−checksum = "7199d965852c3bac31f779ef99cbb4537f80e952e2d6aa0ffeb30cce00f4f46e"
237+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
445−dependencies = [
446− "libc",
447− "thiserror",
448− "winapi",
449−]
450
238
451[[package]]
239[[package]]
452−name = "flate2"
240+name = "form_urlencoded"
453−version = "1.0.27"
241+version = "1.0.1"
454source = "registry+https://github.com/rust-lang/crates.io-index"
242source = "registry+https://github.com/rust-lang/crates.io-index"
455−checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010"
243+checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
456dependencies = [
244dependencies = [
457− "crc32fast",
245+ "matches",
458− "miniz_oxide",
246+ "percent-encoding",
459]
247]
460
248
461[[package]]
249[[package]]
462−name = "form_urlencoded"
250+name = "futf"
463−version = "1.2.1"
251+version = "0.1.4"
464source = "registry+https://github.com/rust-lang/crates.io-index"
252source = "registry+https://github.com/rust-lang/crates.io-index"
465−checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
253+checksum = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b"
466dependencies = [
254dependencies = [
467− "percent-encoding",
255+ "mac",
256+ "new_debug_unreachable",
468]
257]
469
258
470[[package]]
259[[package]]
471name = "futures-core"
260name = "futures-core"
472−version = "0.3.30"
261+version = "0.3.19"
473source = "registry+https://github.com/rust-lang/crates.io-index"
262source = "registry+https://github.com/rust-lang/crates.io-index"
474−checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
263+checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
475
264
476[[package]]
265[[package]]
477name = "futures-executor"
266name = "futures-executor"
478−version = "0.3.29"
267+version = "0.3.19"
479source = "registry+https://github.com/rust-lang/crates.io-index"
268source = "registry+https://github.com/rust-lang/crates.io-index"
480−checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
269+checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a"
481dependencies = [
270dependencies = [
482 "futures-core",
271 "futures-core",
483 "futures-task",
272 "futures-task",
@@ -486,15 +275,15 @@ dependencies = [
486
275
487[[package]]
276[[package]]
488name = "futures-task"
277name = "futures-task"
489−version = "0.3.30"
278+version = "0.3.19"
490source = "registry+https://github.com/rust-lang/crates.io-index"
279source = "registry+https://github.com/rust-lang/crates.io-index"
491−checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
280+checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
492
281
493[[package]]
282[[package]]
494name = "futures-util"
283name = "futures-util"
495−version = "0.3.30"
284+version = "0.3.19"
496source = "registry+https://github.com/rust-lang/crates.io-index"
285source = "registry+https://github.com/rust-lang/crates.io-index"
497−checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
286+checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
498dependencies = [
287dependencies = [
499 "futures-core",
288 "futures-core",
500 "futures-task",
289 "futures-task",
@@ -503,11 +292,20 @@ dependencies = [
503 "slab",
292 "slab",
504]
293]
505
294
295+[[package]]
296+name = "fuzzy-matcher"
297+version = "0.3.7"
298+source = "registry+https://github.com/rust-lang/crates.io-index"
299+checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
300+dependencies = [
301+ "thread_local",
302+]
303+
506[[package]]
304[[package]]
507name = "getrandom"
305name = "getrandom"
508−version = "0.2.9"
306+version = "0.2.3"
509source = "registry+https://github.com/rust-lang/crates.io-index"
307source = "registry+https://github.com/rust-lang/crates.io-index"
510−checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
308+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
511dependencies = [
309dependencies = [
512 "cfg-if",
310 "cfg-if",
513 "libc",
311 "libc",
@@ -515,2137 +313,957 @@ dependencies = [
515]
313]
516
314
517[[package]]
315[[package]]
518−name = "gimli"
316+name = "globset"
519−version = "0.27.3"
520−source = "registry+https://github.com/rust-lang/crates.io-index"
521−checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
522−
523−[[package]]
524−name = "gix"
525−version = "0.57.0"
317+version = "0.4.8"
526−source = "registry+https://github.com/rust-lang/crates.io-index"
318+source = "registry+https://github.com/rust-lang/crates.io-index"
527−checksum = "721c7497ab24b665ed5a1eb2b3526936aa60068e61ba260651f7e77c52feec69"
319+checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd"
528−dependencies = [
320+dependencies = [
529− "gix-actor",
321+ "aho-corasick",
530− "gix-commitgraph",
322+ "bstr",
531− "gix-config",
323+ "fnv",
532− "gix-date",
324+ "log",
533− "gix-diff",
325+ "regex",
534− "gix-discover",
535− "gix-features",
536− "gix-fs",
537− "gix-glob",
538− "gix-hash",
539− "gix-hashtable",
540− "gix-lock",
541− "gix-macros",
542− "gix-object",
543− "gix-odb",
544− "gix-pack",
545− "gix-path",
546− "gix-ref",
547− "gix-refspec",
548− "gix-revision",
549− "gix-revwalk",
550− "gix-sec",
551− "gix-tempfile",
552− "gix-trace",
553− "gix-traverse",
554− "gix-url",
555− "gix-utils",
556− "gix-validate",
557− "once_cell",
558− "parking_lot",
559− "smallvec",
560− "thiserror",
561− "unicode-normalization",
562]
326]
563
327
564[[package]]
328[[package]]
565−name = "gix-actor"
329+name = "grep-matcher"
566−version = "0.29.0"
330+version = "0.1.5"
567source = "registry+https://github.com/rust-lang/crates.io-index"
331source = "registry+https://github.com/rust-lang/crates.io-index"
568−checksum = "886014c4865b93ce268f1d3eddd4fd3261242c3f3ee61eb36009f913016a9059"
332+checksum = "6d27563c33062cd33003b166ade2bb4fd82db1fd6a86db764dfdad132d46c1cc"
569dependencies = [
333dependencies = [
570− "bstr",
334+ "memchr",
571− "btoi",
572− "gix-date",
573− "itoa",
574− "thiserror",
575− "winnow 0.5.28",
576]
335]
577
336
578[[package]]
337[[package]]
579−name = "gix-chunk"
338+name = "grep-regex"
580−version = "0.4.6"
339+version = "0.1.9"
581source = "registry+https://github.com/rust-lang/crates.io-index"
340source = "registry+https://github.com/rust-lang/crates.io-index"
582−checksum = "2ade37ef69870de0ed966b97c57a3a947a22ff3482a52c3b99b205f77bcb08fb"
341+checksum = "121553c9768c363839b92fc2d7cdbbad44a3b70e8d6e7b1b72b05c977527bd06"
583dependencies = [
342dependencies = [
584− "thiserror",
343+ "aho-corasick",
344+ "bstr",
345+ "grep-matcher",
346+ "log",
347+ "regex",
348+ "regex-syntax",
349+ "thread_local",
585]
350]
586
351
587[[package]]
352[[package]]
588−name = "gix-commitgraph"
353+name = "grep-searcher"
589−version = "0.23.0"
354+version = "0.1.8"
590source = "registry+https://github.com/rust-lang/crates.io-index"
355source = "registry+https://github.com/rust-lang/crates.io-index"
591−checksum = "e7559ea9cefee188cd88b05afcc8e3ef7a3cb4a5c647bccf06b981e591b02b77"
356+checksum = "7fbdbde90ba52adc240d2deef7b6ad1f99f53142d074b771fe9b7bede6c4c23d"
592dependencies = [
357dependencies = [
593 "bstr",
358 "bstr",
594− "gix-chunk",
359+ "bytecount",
595− "gix-features",
360+ "encoding_rs",
596− "gix-hash",
361+ "encoding_rs_io",
362+ "grep-matcher",
363+ "log",
597 "memmap2",
364 "memmap2",
598− "thiserror",
599]
365]
600
366
601[[package]]
367[[package]]
602−name = "gix-config"
368+name = "helix-core"
603−version = "0.33.0"
369+version = "0.5.0"
604−source = "registry+https://github.com/rust-lang/crates.io-index"
605−checksum = "9c35dc7f9c00a42bbc9cfa1ca2ec0a78ad1b76ff0736d3d35dfd612962244467"
606dependencies = [
370dependencies = [
607− "bstr",
371+ "arc-swap",
608− "gix-config-value",
372+ "chrono",
609− "gix-features",
373+ "encoding_rs",
610− "gix-glob",
374+ "etcetera",
611− "gix-path",
375+ "helix-syntax",
612− "gix-ref",
376+ "log",
613− "gix-sec",
614− "memchr",
615 "once_cell",
377 "once_cell",
378+ "quickcheck",
379+ "regex",
380+ "ropey",
381+ "serde",
382+ "serde_json",
383+ "similar",
616 "smallvec",
384 "smallvec",
617− "thiserror",
385+ "tendril",
386+ "toml",
387+ "tree-sitter",
618− "unicode-bom",
388+ "unicode-general-category",
619− "winnow 0.5.28",
389+ "unicode-segmentation",
390+ "unicode-width",
620]
391]
621
392
622[[package]]
393[[package]]
623−name = "gix-config-value"
394+name = "helix-lsp"
624−version = "0.14.2"
395+version = "0.5.0"
625−source = "registry+https://github.com/rust-lang/crates.io-index"
626−checksum = "39f388cb2396aee82d6f460a2e7770659bdf8854e9e5478f7d2b1324a9698284"
627dependencies = [
396dependencies = [
628− "bitflags 2.4.1",
397+ "anyhow",
629− "bstr",
398+ "futures-executor",
630− "gix-path",
399+ "futures-util",
631− "libc",
400+ "helix-core",
401+ "jsonrpc-core",
402+ "log",
403+ "lsp-types",
404+ "serde",
405+ "serde_json",
632 "thiserror",
406 "thiserror",
407+ "tokio",
408+ "tokio-stream",
633]
409]
634
410
635[[package]]
411[[package]]
636−name = "gix-date"
412+name = "helix-syntax"
637−version = "0.8.2"
413+version = "0.5.0"
638−source = "registry+https://github.com/rust-lang/crates.io-index"
639−checksum = "9d85f4a01e0d05c3de585e28bae514d4baf01655e3fc3f14ce6f30bf62405345"
640dependencies = [
414dependencies = [
641− "bstr",
415+ "anyhow",
642− "itoa",
416+ "cc",
643− "thiserror",
417+ "libloading",
644− "time",
418+ "threadpool",
645−]
419+ "tree-sitter",
646−
647−[[package]]
648−name = "gix-diff"
649−version = "0.39.0"
650−source = "registry+https://github.com/rust-lang/crates.io-index"
651−checksum = "ac0e75f5afd2f6c47c800b6b0a000a08045739d0450d20482e8faa42543f62d1"
652−dependencies = [
653− "bstr",
654− "gix-hash",
655− "gix-object",
656− "thiserror",
657−]
658−
659−[[package]]
660−name = "gix-discover"
661−version = "0.28.0"
662−source = "registry+https://github.com/rust-lang/crates.io-index"
663−checksum = "f0b63ce2ad81632ac1a84ac370f85a5e580c3261580bd85ea17ff35d3a0bba18"
664−dependencies = [
665− "bstr",
666− "dunce",
667− "gix-hash",
668− "gix-path",
669− "gix-ref",
670− "gix-sec",
671− "thiserror",
672−]
673−
674−[[package]]
675−name = "gix-features"
676−version = "0.37.0"
677−source = "registry+https://github.com/rust-lang/crates.io-index"
678−checksum = "befe7edea299a824504b5acc96d7a3a538125b38c42f3a8379f6912a29c90c81"
679−dependencies = [
680− "crc32fast",
681− "flate2",
682− "gix-hash",
683− "gix-trace",
684− "libc",
685− "once_cell",
686− "prodash",
687− "sha1_smol",
688− "thiserror",
689− "walkdir",
690−]
691−
692−[[package]]
693−name = "gix-fs"
694−version = "0.9.0"
695−source = "registry+https://github.com/rust-lang/crates.io-index"
696−checksum = "007017ce93b819ea52c0ec68306f7d72212a2d307c3d70f1548c7141c015d0a1"
697−dependencies = [
698− "gix-features",
699−]
700−
701−[[package]]
702−name = "gix-glob"
703−version = "0.15.0"
704−source = "registry+https://github.com/rust-lang/crates.io-index"
705−checksum = "61fb116c2516d3a1170e010118f639944a6389872c875a008960cdab2a44ac72"
706−dependencies = [
707− "bitflags 2.4.1",
708− "bstr",
709− "gix-features",
710− "gix-path",
711−]
712−
713−[[package]]
714−name = "gix-hash"
715−version = "0.14.0"
716−source = "registry+https://github.com/rust-lang/crates.io-index"
717−checksum = "c52c3170a17b6031833cd2eb4ad7bc23f2755d06e6e70f78dec21d42e8fe1b30"
718−dependencies = [
719− "faster-hex",
720− "thiserror",
721−]
722−
723−[[package]]
724−name = "gix-hashtable"
725−version = "0.5.0"
726−source = "registry+https://github.com/rust-lang/crates.io-index"
727−checksum = "40a838e6366a5e5b84668b6997ce0981b833136468e8ba949f424c0ef2927eba"
728−dependencies = [
729− "gix-hash",
730− "hashbrown 0.14.3",
731− "parking_lot",
732−]
733−
734−[[package]]
735−name = "gix-lock"
736−version = "12.0.0"
737−source = "registry+https://github.com/rust-lang/crates.io-index"
738−checksum = "6cf112ddee94223c119a8534dad027740dc3aba3365ac5edeef8a7f6660c74db"
739−dependencies = [
740− "gix-tempfile",
741− "gix-utils",
742− "thiserror",
743−]
744−
745−[[package]]
746−name = "gix-macros"
747−version = "0.1.2"
748−source = "registry+https://github.com/rust-lang/crates.io-index"
749−checksum = "fc207b64189cf71bcb17fc841ab99a5d63d0845546b611e2703ce467f659323a"
750−dependencies = [
751− "proc-macro2",
752− "quote",
753− "syn 2.0.38",
754−]
755−
756−[[package]]
757−name = "gix-object"
758−version = "0.40.0"
759−source = "registry+https://github.com/rust-lang/crates.io-index"
760−checksum = "e4c77e47ffba92127faf632a841fce23d19547e269bd8b88e68961a70eab4e93"
761−dependencies = [
762− "bstr",
763− "btoi",
764− "gix-actor",
765− "gix-date",
766− "gix-features",
767− "gix-hash",
768− "gix-validate",
769− "itoa",
770− "smallvec",
771− "thiserror",
772− "winnow 0.5.28",
773−]
774−
775−[[package]]
776−name = "gix-odb"
777−version = "0.56.0"
778−source = "registry+https://github.com/rust-lang/crates.io-index"
779−checksum = "a3254f2005cc7553ea78e85e816a09150c6f7a64e6b7627b8d1fdc56721bea73"
780−dependencies = [
781− "arc-swap",
782− "gix-date",
783− "gix-features",
784− "gix-hash",
785− "gix-object",
786− "gix-pack",
787− "gix-path",
788− "gix-quote",
789− "parking_lot",
790− "tempfile",
791− "thiserror",
792−]
793−
794−[[package]]
795−name = "gix-pack"
796−version = "0.46.0"
797−source = "registry+https://github.com/rust-lang/crates.io-index"
798−checksum = "02ebc8cd657eec207d82d8f876ca402361308ecd3c87a47935b0299506257b4f"
799−dependencies = [
800− "clru",
801− "gix-chunk",
802− "gix-features",
803− "gix-hash",
804− "gix-hashtable",
805− "gix-object",
806− "gix-path",
807− "gix-tempfile",
808− "memmap2",
809− "parking_lot",
810− "smallvec",
811− "thiserror",
812−]
813−
814−[[package]]
815−name = "gix-path"
816−version = "0.10.2"
817−source = "registry+https://github.com/rust-lang/crates.io-index"
818−checksum = "10931652a3da126990ac93bce1b1c600cc99d7c268d712b6360ed52174ce1b68"
819−dependencies = [
820− "bstr",
821− "gix-trace",
822− "home",
823− "once_cell",
824− "thiserror",
825−]
826−
827−[[package]]
828−name = "gix-quote"
829−version = "0.4.9"
830−source = "registry+https://github.com/rust-lang/crates.io-index"
831−checksum = "6c43530cb94a7759807e6f8d180e17ac9c65673b891645c6c433831dc0cf4342"
832−dependencies = [
833− "bstr",
834− "btoi",
835− "thiserror",
836−]
837−
838−[[package]]
839−name = "gix-ref"
840−version = "0.40.0"
841−source = "registry+https://github.com/rust-lang/crates.io-index"
842−checksum = "baa951b3b850d6d1be4f900768e49af20b76bf9505beac22af723d57249a2f1d"
843−dependencies = [
844− "gix-actor",
845− "gix-date",
846− "gix-features",
847− "gix-fs",
848− "gix-hash",
849− "gix-lock",
850− "gix-object",
851− "gix-path",
852− "gix-tempfile",
853− "gix-validate",
854− "memmap2",
855− "thiserror",
856− "winnow 0.5.28",
857−]
858−
859−[[package]]
860−name = "gix-refspec"
861−version = "0.21.0"
862−source = "registry+https://github.com/rust-lang/crates.io-index"
863−checksum = "88c61f849d58c06e3068a0b601cf10127d2a07cdad00a725ed66cf303f76f6b3"
864−dependencies = [
865− "bstr",
866− "gix-hash",
867− "gix-revision",
868− "gix-validate",
869− "smallvec",
870− "thiserror",
871−]
872−
873−[[package]]
874−name = "gix-revision"
875−version = "0.25.0"
876−source = "registry+https://github.com/rust-lang/crates.io-index"
877−checksum = "bcbbf91f4200c5c76802ef5f057b96f5a336827508881fe55a780be71a794d22"
878−dependencies = [
879− "bstr",
880− "gix-date",
881− "gix-hash",
882− "gix-hashtable",
883− "gix-object",
884− "gix-revwalk",
885− "gix-trace",
886− "thiserror",
887−]
888−
889−[[package]]
890−name = "gix-revwalk"
891−version = "0.11.0"
892−source = "registry+https://github.com/rust-lang/crates.io-index"
893−checksum = "33ab66354d83f70f2730391747d0c75f94ef3c3dd40ebde2e206db9faaf7a0a7"
894−dependencies = [
895− "gix-commitgraph",
896− "gix-date",
897− "gix-hash",
898− "gix-hashtable",
899− "gix-object",
900− "smallvec",
901− "thiserror",
902−]
903−
904−[[package]]
905−name = "gix-sec"
906−version = "0.10.2"
907−source = "registry+https://github.com/rust-lang/crates.io-index"
908−checksum = "a9963f38a42144253ed4d571882d7db5ef644c12e6726e4b75135597cc9d0e1a"
909−dependencies = [
910− "bitflags 2.4.1",
911− "gix-path",
912− "libc",
913− "windows 0.52.0",
914−]
915−
916−[[package]]
917−name = "gix-tempfile"
918−version = "12.0.0"
919−source = "registry+https://github.com/rust-lang/crates.io-index"
920−checksum = "e76a494bd530e1a1309188ff971825a24f159c76c2db0bf71fa5dfb469a2c915"
921−dependencies = [
922− "gix-fs",
923− "libc",
924− "once_cell",
925− "parking_lot",
926− "tempfile",
927−]
928−
929−[[package]]
930−name = "gix-trace"
931−version = "0.1.5"
932−source = "registry+https://github.com/rust-lang/crates.io-index"
933−checksum = "bda62acb44dd86a40c7c3762a5403cfc1ac789ea559df54085cedf79864f809e"
934−
935−[[package]]
936−name = "gix-traverse"
937−version = "0.36.0"
938−source = "registry+https://github.com/rust-lang/crates.io-index"
939−checksum = "8661fab39985c9214e56d81a63ceb5886ac948cec2fba76c39494d1e0e307ea8"
940−dependencies = [
941− "gix-commitgraph",
942− "gix-date",
943− "gix-hash",
944− "gix-hashtable",
945− "gix-object",
946− "gix-revwalk",
947− "smallvec",
948− "thiserror",
949−]
950−
951−[[package]]
952−name = "gix-url"
953−version = "0.26.0"
954−source = "registry+https://github.com/rust-lang/crates.io-index"
955−checksum = "10a0129c1e8b52736d7c5128300a4485dbc85863001371e2771ac1754bd89fd7"
956−dependencies = [
957− "bstr",
958− "gix-features",
959− "gix-path",
960− "home",
961− "thiserror",
962− "url",
963−]
964−
965−[[package]]
966−name = "gix-utils"
967−version = "0.1.7"
968−source = "registry+https://github.com/rust-lang/crates.io-index"
969−checksum = "ab9277a5e32e85d53f738096d872a4a9b76067ad471894ad31bd99c8fa2da1dc"
970−dependencies = [
971− "fastrand",
972−]
973−
974−[[package]]
975−name = "gix-validate"
976−version = "0.8.2"
977−source = "registry+https://github.com/rust-lang/crates.io-index"
978−checksum = "f805ebbdbaa4bfd98e2ee43e6d14099b8a4d9141f5d7b8202fea4d48e44263e7"
979−dependencies = [
980− "bstr",
981− "thiserror",
982−]
983−
984−[[package]]
985−name = "globset"
986−version = "0.4.14"
987−source = "registry+https://github.com/rust-lang/crates.io-index"
988−checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
989−dependencies = [
990− "aho-corasick",
991− "bstr",
992− "log",
993− "regex-automata",
994− "regex-syntax",
995−]
996−
997−[[package]]
998−name = "grep-matcher"
999−version = "0.1.7"
1000−source = "registry+https://github.com/rust-lang/crates.io-index"
1001−checksum = "47a3141a10a43acfedc7c98a60a834d7ba00dfe7bec9071cbfc19b55b292ac02"
1002−dependencies = [
1003− "memchr",
1004−]
1005−
1006−[[package]]
1007−name = "grep-regex"
1008−version = "0.1.12"
1009−source = "registry+https://github.com/rust-lang/crates.io-index"
1010−checksum = "f748bb135ca835da5cbc67ca0e6955f968db9c5df74ca4f56b18e1ddbc68230d"
1011−dependencies = [
1012− "bstr",
1013− "grep-matcher",
1014− "log",
1015− "regex-automata",
1016− "regex-syntax",
1017−]
1018−
1019−[[package]]
1020−name = "grep-searcher"
1021−version = "0.1.13"
1022−source = "registry+https://github.com/rust-lang/crates.io-index"
1023−checksum = "ba536ae4f69bec62d8839584dd3153d3028ef31bb229f04e09fb5a9e5a193c54"
1024−dependencies = [
1025− "bstr",
1026− "encoding_rs",
1027− "encoding_rs_io",
1028− "grep-matcher",
1029− "log",
1030− "memchr",
1031− "memmap2",
1032−]
1033−
1034−[[package]]
1035−name = "hashbrown"
1036−version = "0.12.3"
1037−source = "registry+https://github.com/rust-lang/crates.io-index"
1038−checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
1039−
1040−[[package]]
1041−name = "hashbrown"
1042−version = "0.14.3"
1043−source = "registry+https://github.com/rust-lang/crates.io-index"
1044−checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
1045−dependencies = [
1046− "ahash",
1047− "allocator-api2",
1048−]
1049−
1050−[[package]]
1051−name = "helix-core"
1052−version = "23.10.0"
1053−dependencies = [
1054− "ahash",
1055− "arc-swap",
1056− "bitflags 2.4.1",
1057− "chrono",
1058− "dunce",
1059− "encoding_rs",
1060− "etcetera",
1061− "hashbrown 0.14.3",
1062− "helix-loader",
1063− "imara-diff",
1064− "indoc",
1065− "log",
1066− "nucleo",
1067− "once_cell",
1068− "parking_lot",
1069− "quickcheck",
1070− "regex",
1071− "ropey",
1072− "serde",
1073− "serde_json",
1074− "slotmap",
1075− "smallvec",
1076− "smartstring",
1077− "textwrap",
1078− "toml",
1079− "tree-sitter",
1080− "unicode-general-category",
1081− "unicode-segmentation",
1082− "unicode-width",
1083−]
1084−
1085−[[package]]
1086−name = "helix-dap"
1087−version = "23.10.0"
1088−dependencies = [
1089− "anyhow",
1090− "fern",
1091− "helix-core",
1092− "log",
1093− "serde",
1094− "serde_json",
1095− "thiserror",
1096− "tokio",
1097− "which",
1098−]
1099−
1100−[[package]]
1101−name = "helix-event"
1102−version = "23.10.0"
1103−dependencies = [
1104− "parking_lot",
1105− "tokio",
1106−]
1107−
1108−[[package]]
1109−name = "helix-loader"
1110−version = "23.10.0"
1111−dependencies = [
1112− "anyhow",
1113− "cc",
1114− "dunce",
1115− "etcetera",
1116− "libloading",
1117− "log",
1118− "once_cell",
1119− "serde",
1120− "tempfile",
1121− "threadpool",
1122− "toml",
1123− "tree-sitter",
1124− "which",
1125−]
1126−
1127−[[package]]
1128−name = "helix-lsp"
1129−version = "23.10.0"
1130−dependencies = [
1131− "anyhow",
1132− "futures-executor",
1133− "futures-util",
1134− "globset",
1135− "helix-core",
1136− "helix-loader",
1137− "helix-parsec",
1138− "log",
1139− "lsp-types",
1140− "parking_lot",
1141− "serde",
1142− "serde_json",
1143− "thiserror",
1144− "tokio",
1145− "tokio-stream",
1146− "which",
1147−]
1148−
1149−[[package]]
1150−name = "helix-parsec"
1151−version = "23.10.0"
1152−
1153−[[package]]
1154−name = "helix-term"
1155−version = "23.10.0"
1156−dependencies = [
1157− "anyhow",
1158− "arc-swap",
1159− "chrono",
1160− "content_inspector",
1161− "crossterm",
1162− "fern",
1163− "futures-util",
1164− "grep-regex",
1165− "grep-searcher",
1166− "helix-core",
1167− "helix-dap",
1168− "helix-event",
1169− "helix-loader",
1170− "helix-lsp",
1171− "helix-tui",
1172− "helix-vcs",
1173− "helix-view",
1174− "ignore",
1175− "indoc",
1176− "libc",
1177− "log",
1178− "nucleo",
1179− "once_cell",
1180− "open",
1181− "pulldown-cmark",
1182− "serde",
1183− "serde_json",
1184− "signal-hook",
1185− "signal-hook-tokio",
1186− "smallvec",
1187− "tempfile",
1188− "tokio",
1189− "tokio-stream",
1190− "toml",
1191− "url",
1192− "which",
1193−]
1194−
1195−[[package]]
1196−name = "helix-tui"
1197−version = "23.10.0"
1198−dependencies = [
1199− "bitflags 2.4.1",
1200− "cassowary",
1201− "crossterm",
1202− "helix-core",
1203− "helix-view",
1204− "log",
1205− "once_cell",
1206− "serde",
1207− "termini",
1208− "unicode-segmentation",
1209−]
1210−
1211−[[package]]
1212−name = "helix-vcs"
1213−version = "23.10.0"
1214−dependencies = [
1215− "anyhow",
1216− "arc-swap",
1217− "gix",
1218− "helix-core",
1219− "helix-event",
1220− "imara-diff",
1221− "log",
1222− "parking_lot",
1223− "tempfile",
1224− "tokio",
1225−]
1226−
1227−[[package]]
1228−name = "helix-view"
1229−version = "23.10.0"
1230−dependencies = [
1231− "anyhow",
1232− "arc-swap",
1233− "bitflags 2.4.1",
1234− "chardetng",
1235− "clipboard-win",
1236− "crossterm",
1237− "futures-util",
1238− "helix-core",
1239− "helix-dap",
1240− "helix-event",
1241− "helix-loader",
1242− "helix-lsp",
1243− "helix-tui",
1244− "helix-vcs",
1245− "libc",
1246− "log",
1247− "once_cell",
1248− "parking_lot",
1249− "rustix",
1250− "serde",
1251− "serde_json",
1252− "slotmap",
1253− "tokio",
1254− "tokio-stream",
1255− "toml",
1256− "url",
1257− "which",
1258−]
1259−
1260−[[package]]
1261−name = "hermit-abi"
1262−version = "0.2.6"
1263−source = "registry+https://github.com/rust-lang/crates.io-index"
1264−checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
1265−dependencies = [
1266− "libc",
1267−]
1268−
1269−[[package]]
1270−name = "home"
1271−version = "0.5.5"
1272−source = "registry+https://github.com/rust-lang/crates.io-index"
1273−checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
1274−dependencies = [
1275− "windows-sys 0.48.0",
1276−]
1277−
1278−[[package]]
1279−name = "iana-time-zone"
1280−version = "0.1.56"
1281−source = "registry+https://github.com/rust-lang/crates.io-index"
1282−checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
1283−dependencies = [
1284− "android_system_properties",
1285− "core-foundation-sys",
1286− "iana-time-zone-haiku",
1287− "js-sys",
1288− "wasm-bindgen",
1289− "windows 0.48.0",
1290−]
1291−
1292−[[package]]
1293−name = "iana-time-zone-haiku"
1294−version = "0.1.1"
1295−source = "registry+https://github.com/rust-lang/crates.io-index"
1296−checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
1297−dependencies = [
1298− "cxx",
1299− "cxx-build",
1300−]
1301−
1302−[[package]]
1303−name = "idna"
1304−version = "0.5.0"
1305−source = "registry+https://github.com/rust-lang/crates.io-index"
1306−checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
1307−dependencies = [
1308− "unicode-bidi",
1309− "unicode-normalization",
1310−]
1311−
1312−[[package]]
1313−name = "ignore"
1314−version = "0.4.21"
1315−source = "registry+https://github.com/rust-lang/crates.io-index"
1316−checksum = "747ad1b4ae841a78e8aba0d63adbfbeaea26b517b63705d47856b73015d27060"
1317−dependencies = [
1318− "crossbeam-deque",
1319− "globset",
1320− "log",
1321− "memchr",
1322− "regex-automata",
1323− "same-file",
1324− "walkdir",
1325− "winapi-util",
1326−]
1327−
1328−[[package]]
1329−name = "imara-diff"
1330−version = "0.1.5"
1331−source = "registry+https://github.com/rust-lang/crates.io-index"
1332−checksum = "e98c1d0ad70fc91b8b9654b1f33db55e59579d3b3de2bffdced0fdb810570cb8"
1333−dependencies = [
1334− "ahash",
1335− "hashbrown 0.12.3",
1336−]
1337−
1338−[[package]]
1339−name = "indexmap"
1340−version = "2.0.0"
1341−source = "registry+https://github.com/rust-lang/crates.io-index"
1342−checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
1343−dependencies = [
1344− "equivalent",
1345− "hashbrown 0.14.3",
1346−]
1347−
1348−[[package]]
1349−name = "indoc"
1350−version = "2.0.4"
1351−source = "registry+https://github.com/rust-lang/crates.io-index"
1352−checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8"
1353−
1354−[[package]]
1355−name = "is-docker"
1356−version = "0.2.0"
1357−source = "registry+https://github.com/rust-lang/crates.io-index"
1358−checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
1359−dependencies = [
1360− "once_cell",
1361−]
1362−
1363−[[package]]
1364−name = "is-wsl"
1365−version = "0.4.0"
1366−source = "registry+https://github.com/rust-lang/crates.io-index"
1367−checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
1368−dependencies = [
1369− "is-docker",
1370− "once_cell",
1371−]
1372−
1373−[[package]]
1374−name = "itoa"
1375−version = "1.0.6"
1376−source = "registry+https://github.com/rust-lang/crates.io-index"
1377−checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
1378−
1379−[[package]]
1380−name = "js-sys"
1381−version = "0.3.61"
1382−source = "registry+https://github.com/rust-lang/crates.io-index"
1383−checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
1384−dependencies = [
1385− "wasm-bindgen",
1386−]
1387−
1388−[[package]]
1389−name = "libc"
1390−version = "0.2.151"
1391−source = "registry+https://github.com/rust-lang/crates.io-index"
1392−checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
1393−
1394−[[package]]
1395−name = "libloading"
1396−version = "0.8.1"
1397−source = "registry+https://github.com/rust-lang/crates.io-index"
1398−checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
1399−dependencies = [
1400− "cfg-if",
1401− "windows-sys 0.48.0",
1402−]
1403−
1404−[[package]]
1405−name = "link-cplusplus"
1406−version = "1.0.8"
1407−source = "registry+https://github.com/rust-lang/crates.io-index"
1408−checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
1409−dependencies = [
1410− "cc",
1411−]
1412−
1413−[[package]]
1414−name = "linux-raw-sys"
1415−version = "0.4.11"
1416−source = "registry+https://github.com/rust-lang/crates.io-index"
1417−checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
1418−
1419−[[package]]
1420−name = "lock_api"
1421−version = "0.4.9"
1422−source = "registry+https://github.com/rust-lang/crates.io-index"
1423−checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
1424−dependencies = [
1425− "autocfg",
1426− "scopeguard",
1427−]
1428−
1429−[[package]]
1430−name = "log"
1431−version = "0.4.20"
1432−source = "registry+https://github.com/rust-lang/crates.io-index"
1433−checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
1434−
1435−[[package]]
1436−name = "lsp-types"
1437−version = "0.95.0"
1438−source = "registry+https://github.com/rust-lang/crates.io-index"
1439−checksum = "158c1911354ef73e8fe42da6b10c0484cb65c7f1007f28022e847706c1ab6984"
1440−dependencies = [
1441− "bitflags 1.3.2",
1442− "serde",
1443− "serde_json",
1444− "serde_repr",
1445− "url",
1446−]
1447−
1448−[[package]]
1449−name = "memchr"
1450−version = "2.6.3"
1451−source = "registry+https://github.com/rust-lang/crates.io-index"
1452−checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
1453−
1454−[[package]]
1455−name = "memmap2"
1456−version = "0.9.0"
1457−source = "registry+https://github.com/rust-lang/crates.io-index"
1458−checksum = "deaba38d7abf1d4cca21cc89e932e542ba2b9258664d2a9ef0e61512039c9375"
1459−dependencies = [
1460− "libc",
1461−]
1462−
1463−[[package]]
1464−name = "memoffset"
1465−version = "0.9.0"
1466−source = "registry+https://github.com/rust-lang/crates.io-index"
1467−checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
1468−dependencies = [
1469− "autocfg",
1470−]
1471−
1472−[[package]]
1473−name = "miniz_oxide"
1474−version = "0.7.1"
1475−source = "registry+https://github.com/rust-lang/crates.io-index"
1476−checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
1477−dependencies = [
1478− "adler",
1479−]
1480−
1481−[[package]]
1482−name = "mio"
1483−version = "0.8.9"
1484−source = "registry+https://github.com/rust-lang/crates.io-index"
1485−checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
1486−dependencies = [
1487− "libc",
1488− "log",
1489− "wasi",
1490− "windows-sys 0.48.0",
1491−]
1492−
1493−[[package]]
1494−name = "nucleo"
1495−version = "0.2.1"
1496−source = "registry+https://github.com/rust-lang/crates.io-index"
1497−checksum = "ae5331f4bcce475cf28cb29c95366c3091af4b0aa7703f1a6bc858f29718fdf3"
1498−dependencies = [
1499− "nucleo-matcher",
1500− "parking_lot",
1501− "rayon",
1502−]
1503−
1504−[[package]]
1505−name = "nucleo-matcher"
1506−version = "0.2.0"
1507−source = "registry+https://github.com/rust-lang/crates.io-index"
1508−checksum = "1b702b402fe286162d1f00b552a046ce74365d2ac473a2607ff36ba650f9bd57"
1509−dependencies = [
1510− "cov-mark",
1511− "memchr",
1512− "unicode-segmentation",
1513−]
1514−
1515−[[package]]
1516−name = "num-traits"
1517−version = "0.2.15"
1518−source = "registry+https://github.com/rust-lang/crates.io-index"
1519−checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
1520−dependencies = [
1521− "autocfg",
1522−]
1523−
1524−[[package]]
1525−name = "num_cpus"
1526−version = "1.15.0"
1527−source = "registry+https://github.com/rust-lang/crates.io-index"
1528−checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
1529−dependencies = [
1530− "hermit-abi",
1531− "libc",
1532−]
1533−
1534−[[package]]
1535−name = "num_threads"
1536−version = "0.1.6"
1537−source = "registry+https://github.com/rust-lang/crates.io-index"
1538−checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
1539−dependencies = [
1540− "libc",
1541−]
1542−
1543−[[package]]
1544−name = "object"
1545−version = "0.31.1"
1546−source = "registry+https://github.com/rust-lang/crates.io-index"
1547−checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
1548−dependencies = [
1549− "memchr",
1550−]
1551−
1552−[[package]]
1553−name = "once_cell"
1554−version = "1.19.0"
1555−source = "registry+https://github.com/rust-lang/crates.io-index"
1556−checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
1557−
1558−[[package]]
1559−name = "open"
1560−version = "5.0.1"
1561−source = "registry+https://github.com/rust-lang/crates.io-index"
1562−checksum = "90878fb664448b54c4e592455ad02831e23a3f7e157374a8b95654731aac7349"
1563−dependencies = [
1564− "is-wsl",
1565− "libc",
1566− "pathdiff",
1567−]
1568−
1569−[[package]]
1570−name = "parking_lot"
1571−version = "0.12.1"
1572−source = "registry+https://github.com/rust-lang/crates.io-index"
1573−checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
1574−dependencies = [
1575− "lock_api",
1576− "parking_lot_core",
1577−]
1578−
1579−[[package]]
1580−name = "parking_lot_core"
1581−version = "0.9.7"
1582−source = "registry+https://github.com/rust-lang/crates.io-index"
1583−checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
1584−dependencies = [
1585− "cfg-if",
1586− "libc",
1587− "redox_syscall 0.2.16",
1588− "smallvec",
1589− "windows-sys 0.45.0",
1590−]
1591−
1592−[[package]]
1593−name = "pathdiff"
1594−version = "0.2.1"
1595−source = "registry+https://github.com/rust-lang/crates.io-index"
1596−checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
1597−
1598−[[package]]
1599−name = "percent-encoding"
1600−version = "2.3.1"
1601−source = "registry+https://github.com/rust-lang/crates.io-index"
1602−checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
1603−
1604−[[package]]
1605−name = "pin-project-lite"
1606−version = "0.2.12"
1607−source = "registry+https://github.com/rust-lang/crates.io-index"
1608−checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05"
1609−
1610−[[package]]
1611−name = "pin-utils"
1612−version = "0.1.0"
1613−source = "registry+https://github.com/rust-lang/crates.io-index"
1614−checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
1615−
1616−[[package]]
1617−name = "proc-macro2"
1618−version = "1.0.69"
1619−source = "registry+https://github.com/rust-lang/crates.io-index"
1620−checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
1621−dependencies = [
1622− "unicode-ident",
1623−]
1624−
1625−[[package]]
1626−name = "prodash"
1627−version = "28.0.0"
1628−source = "registry+https://github.com/rust-lang/crates.io-index"
1629−checksum = "744a264d26b88a6a7e37cbad97953fa233b94d585236310bcbc88474b4092d79"
1630−
1631−[[package]]
1632−name = "pulldown-cmark"
1633−version = "0.9.3"
1634−source = "registry+https://github.com/rust-lang/crates.io-index"
1635−checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998"
1636−dependencies = [
1637− "bitflags 1.3.2",
1638− "memchr",
1639− "unicase",
1640−]
1641−
1642−[[package]]
1643−name = "quickcheck"
1644−version = "1.0.3"
1645−source = "registry+https://github.com/rust-lang/crates.io-index"
1646−checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6"
1647−dependencies = [
1648− "rand",
1649−]
1650−
1651−[[package]]
1652−name = "quote"
1653−version = "1.0.29"
1654−source = "registry+https://github.com/rust-lang/crates.io-index"
1655−checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
1656−dependencies = [
1657− "proc-macro2",
1658−]
1659−
1660−[[package]]
1661−name = "rand"
1662−version = "0.8.5"
1663−source = "registry+https://github.com/rust-lang/crates.io-index"
1664−checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
1665−dependencies = [
1666− "rand_core",
1667−]
1668−
1669−[[package]]
1670−name = "rand_core"
1671−version = "0.6.4"
1672−source = "registry+https://github.com/rust-lang/crates.io-index"
1673−checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
1674−dependencies = [
1675− "getrandom",
1676−]
1677−
1678−[[package]]
1679−name = "rayon"
1680−version = "1.7.0"
1681−source = "registry+https://github.com/rust-lang/crates.io-index"
1682−checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
1683−dependencies = [
1684− "either",
1685− "rayon-core",
1686−]
1687−
1688−[[package]]
1689−name = "rayon-core"
1690−version = "1.11.0"
1691−source = "registry+https://github.com/rust-lang/crates.io-index"
1692−checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
1693−dependencies = [
1694− "crossbeam-channel",
1695− "crossbeam-deque",
1696− "crossbeam-utils",
1697− "num_cpus",
1698−]
1699−
1700−[[package]]
1701−name = "redox_syscall"
1702−version = "0.2.16"
1703−source = "registry+https://github.com/rust-lang/crates.io-index"
1704−checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
1705−dependencies = [
1706− "bitflags 1.3.2",
1707−]
1708−
1709−[[package]]
1710−name = "redox_syscall"
1711−version = "0.4.1"
1712−source = "registry+https://github.com/rust-lang/crates.io-index"
1713−checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
1714−dependencies = [
1715− "bitflags 1.3.2",
1716−]
1717−
1718−[[package]]
1719−name = "regex"
1720−version = "1.10.2"
1721−source = "registry+https://github.com/rust-lang/crates.io-index"
1722−checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
1723−dependencies = [
1724− "aho-corasick",
1725− "memchr",
1726− "regex-automata",
1727− "regex-syntax",
1728−]
1729−
1730−[[package]]
1731−name = "regex-automata"
1732−version = "0.4.3"
1733−source = "registry+https://github.com/rust-lang/crates.io-index"
1734−checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
1735−dependencies = [
1736− "aho-corasick",
1737− "memchr",
1738− "regex-syntax",
1739−]
1740−
1741−[[package]]
1742−name = "regex-syntax"
1743−version = "0.8.2"
1744−source = "registry+https://github.com/rust-lang/crates.io-index"
1745−checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
1746−
1747−[[package]]
1748−name = "ropey"
1749−version = "1.6.1"
1750−source = "registry+https://github.com/rust-lang/crates.io-index"
1751−checksum = "93411e420bcd1a75ddd1dc3caf18c23155eda2c090631a85af21ba19e97093b5"
1752−dependencies = [
1753− "smallvec",
1754− "str_indices",
1755−]
1756−
1757−[[package]]
1758−name = "rustc-demangle"
1759−version = "0.1.23"
1760−source = "registry+https://github.com/rust-lang/crates.io-index"
1761−checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
1762−
1763−[[package]]
1764−name = "rustix"
1765−version = "0.38.28"
1766−source = "registry+https://github.com/rust-lang/crates.io-index"
1767−checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
1768−dependencies = [
1769− "bitflags 2.4.1",
1770− "errno",
1771− "libc",
1772− "linux-raw-sys",
1773− "windows-sys 0.52.0",
1774−]
1775−
1776−[[package]]
1777−name = "ryu"
1778−version = "1.0.13"
1779−source = "registry+https://github.com/rust-lang/crates.io-index"
1780−checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
1781−
1782−[[package]]
1783−name = "same-file"
1784−version = "1.0.6"
1785−source = "registry+https://github.com/rust-lang/crates.io-index"
1786−checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
1787−dependencies = [
1788− "winapi-util",
1789−]
1790−
1791−[[package]]
1792−name = "scopeguard"
1793−version = "1.1.0"
1794−source = "registry+https://github.com/rust-lang/crates.io-index"
1795−checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
1796−
1797−[[package]]
1798−name = "scratch"
1799−version = "1.0.5"
1800−source = "registry+https://github.com/rust-lang/crates.io-index"
1801−checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1"
1802−
1803−[[package]]
1804−name = "serde"
1805−version = "1.0.193"
1806−source = "registry+https://github.com/rust-lang/crates.io-index"
1807−checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
1808−dependencies = [
1809− "serde_derive",
1810−]
1811−
1812−[[package]]
1813−name = "serde_derive"
1814−version = "1.0.193"
1815−source = "registry+https://github.com/rust-lang/crates.io-index"
1816−checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
1817−dependencies = [
1818− "proc-macro2",
1819− "quote",
1820− "syn 2.0.38",
1821−]
1822−
1823−[[package]]
1824−name = "serde_json"
1825−version = "1.0.108"
1826−source = "registry+https://github.com/rust-lang/crates.io-index"
1827−checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
1828−dependencies = [
1829− "itoa",
1830− "ryu",
1831− "serde",
1832−]
1833−
1834−[[package]]
1835−name = "serde_repr"
1836−version = "0.1.12"
1837−source = "registry+https://github.com/rust-lang/crates.io-index"
1838−checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
1839−dependencies = [
1840− "proc-macro2",
1841− "quote",
1842− "syn 2.0.38",
1843]
420]
1844
421
1845[[package]]
422[[package]]
1846−name = "serde_spanned"
423+name = "helix-term"
1847−version = "0.6.3"
424+version = "0.5.0"
1848−source = "registry+https://github.com/rust-lang/crates.io-index"
1849−checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
1850dependencies = [
425dependencies = [
426+ "anyhow",
427+ "chrono",
428+ "content_inspector",
429+ "crossterm",
430+ "fern",
431+ "futures-util",
432+ "fuzzy-matcher",
433+ "grep-regex",
434+ "grep-searcher",
435+ "helix-core",
436+ "helix-lsp",
437+ "helix-tui",
438+ "helix-view",
439+ "ignore",
440+ "log",
441+ "num_cpus",
442+ "once_cell",
443+ "pulldown-cmark",
1851 "serde",
444 "serde",
445+ "serde_json",
446+ "signal-hook",
447+ "signal-hook-tokio",
448+ "tokio",
449+ "tokio-stream",
450+ "toml",
1852]
451]
1853
452
1854[[package]]
453[[package]]
1855−name = "sha1_smol"
454+name = "helix-tui"
1856−version = "1.0.0"
1857−source = "registry+https://github.com/rust-lang/crates.io-index"
1858−checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
1859−
1860−[[package]]
1861−name = "signal-hook"
1862−version = "0.3.17"
455+version = "0.5.0"
1863−source = "registry+https://github.com/rust-lang/crates.io-index"
1864−checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
1865dependencies = [
456dependencies = [
1866− "libc",
457+ "bitflags",
1867− "signal-hook-registry",
458+ "cassowary",
459+ "crossterm",
460+ "helix-core",
461+ "helix-view",
462+ "serde",
463+ "unicode-segmentation",
1868]
464]
1869
465
1870[[package]]
466[[package]]
1871−name = "signal-hook-mio"
467+name = "helix-view"
1872−version = "0.2.3"
468+version = "0.5.0"
1873−source = "registry+https://github.com/rust-lang/crates.io-index"
1874−checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
1875dependencies = [
469dependencies = [
1876− "libc",
470+ "anyhow",
1877− "mio",
471+ "bitflags",
1878− "signal-hook",
472+ "chardetng",
473+ "clipboard-win",
474+ "crossterm",
475+ "futures-util",
476+ "helix-core",
477+ "helix-lsp",
478+ "helix-tui",
479+ "log",
480+ "once_cell",
481+ "serde",
482+ "slotmap",
483+ "tokio",
484+ "toml",
485+ "url",
486+ "which",
1879]
487]
1880
488
1881[[package]]
489[[package]]
1882−name = "signal-hook-registry"
490+name = "hermit-abi"
1883−version = "1.4.1"
491+version = "0.1.19"
1884source = "registry+https://github.com/rust-lang/crates.io-index"
492source = "registry+https://github.com/rust-lang/crates.io-index"
1885−checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
493+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
1886dependencies = [
494dependencies = [
1887 "libc",
495 "libc",
1888]
496]
1889
497
1890[[package]]
498[[package]]
1891−name = "signal-hook-tokio"
499+name = "idna"
1892−version = "0.3.1"
500+version = "0.2.3"
1893source = "registry+https://github.com/rust-lang/crates.io-index"
501source = "registry+https://github.com/rust-lang/crates.io-index"
1894−checksum = "213241f76fb1e37e27de3b6aa1b068a2c333233b59cca6634f634b80a27ecf1e"
502+checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
1895dependencies = [
503dependencies = [
1896− "futures-core",
504+ "matches",
1897− "libc",
505+ "unicode-bidi",
1898− "signal-hook",
506+ "unicode-normalization",
1899− "tokio",
1900]
507]
1901
508
1902[[package]]
509[[package]]
1903−name = "slab"
510+name = "ignore"
1904−version = "0.4.8"
511+version = "0.4.18"
1905source = "registry+https://github.com/rust-lang/crates.io-index"
512source = "registry+https://github.com/rust-lang/crates.io-index"
1906−checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
513+checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d"
1907dependencies = [
514dependencies = [
1908− "autocfg",
515+ "crossbeam-utils",
516+ "globset",
517+ "lazy_static",
518+ "log",
519+ "memchr",
520+ "regex",
521+ "same-file",
522+ "thread_local",
523+ "walkdir",
524+ "winapi-util",
1909]
525]
1910
526
1911[[package]]
527[[package]]
1912−name = "slotmap"
528+name = "instant"
1913−version = "1.0.7"
529+version = "0.1.12"
1914source = "registry+https://github.com/rust-lang/crates.io-index"
530source = "registry+https://github.com/rust-lang/crates.io-index"
1915−checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
531+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
1916dependencies = [
532dependencies = [
1917− "version_check",
533+ "cfg-if",
1918]
534]
1919
535
1920[[package]]
536[[package]]
1921−name = "smallvec"
537+name = "itoa"
1922−version = "1.11.2"
1923−source = "registry+https://github.com/rust-lang/crates.io-index"
1924−checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
1925−
1926−[[package]]
1927−name = "smartstring"
1928version = "1.0.1"
538version = "1.0.1"
1929source = "registry+https://github.com/rust-lang/crates.io-index"
539source = "registry+https://github.com/rust-lang/crates.io-index"
1930−checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29"
540+checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
1931−dependencies = [
1932− "autocfg",
1933− "static_assertions",
1934− "version_check",
1935−]
1936−
1937−[[package]]
1938−name = "smawk"
1939−version = "0.3.1"
1940−source = "registry+https://github.com/rust-lang/crates.io-index"
1941−checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
1942
541
1943[[package]]
542[[package]]
1944−name = "socket2"
543+name = "jsonrpc-core"
1945−version = "0.5.5"
544+version = "18.0.0"
1946source = "registry+https://github.com/rust-lang/crates.io-index"
545source = "registry+https://github.com/rust-lang/crates.io-index"
1947−checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
546+checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb"
1948dependencies = [
547dependencies = [
1949− "libc",
548+ "futures-util",
1950− "windows-sys 0.48.0",
549+ "log",
550+ "serde",
551+ "serde_derive",
552+ "serde_json",
1951]
553]
1952
554
1953[[package]]
555[[package]]
1954−name = "static_assertions"
556+name = "lazy_static"
1955−version = "1.1.0"
557+version = "1.4.0"
1956source = "registry+https://github.com/rust-lang/crates.io-index"
558source = "registry+https://github.com/rust-lang/crates.io-index"
1957−checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
559+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
1958
560
1959[[package]]
561[[package]]
1960−name = "str_indices"
562+name = "libc"
1961−version = "0.4.1"
563+version = "0.2.104"
1962source = "registry+https://github.com/rust-lang/crates.io-index"
564source = "registry+https://github.com/rust-lang/crates.io-index"
1963−checksum = "5f026164926842ec52deb1938fae44f83dfdb82d0a5b0270c5bd5935ab74d6dd"
565+checksum = "7b2f96d100e1cf1929e7719b7edb3b90ab5298072638fccd77be9ce942ecdfce"
1964
566
1965[[package]]
567[[package]]
1966−name = "syn"
568+name = "libloading"
1967−version = "1.0.109"
569+version = "0.7.2"
1968source = "registry+https://github.com/rust-lang/crates.io-index"
570source = "registry+https://github.com/rust-lang/crates.io-index"
1969−checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
571+checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52"
1970dependencies = [
572dependencies = [
1971− "proc-macro2",
573+ "cfg-if",
1972− "quote",
574+ "winapi",
1973− "unicode-ident",
1974]
575]
1975
576
1976[[package]]
577[[package]]
1977−name = "syn"
578+name = "lock_api"
1978−version = "2.0.38"
579+version = "0.4.5"
1979source = "registry+https://github.com/rust-lang/crates.io-index"
580source = "registry+https://github.com/rust-lang/crates.io-index"
1980−checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
581+checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
1981dependencies = [
582dependencies = [
1982− "proc-macro2",
583+ "scopeguard",
1983− "quote",
1984− "unicode-ident",
1985]
584]
1986
585
1987[[package]]
586[[package]]
1988−name = "tempfile"
587+name = "log"
1989−version = "3.8.1"
588+version = "0.4.14"
1990source = "registry+https://github.com/rust-lang/crates.io-index"
589source = "registry+https://github.com/rust-lang/crates.io-index"
1991−checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
590+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
1992dependencies = [
591dependencies = [
1993 "cfg-if",
592 "cfg-if",
1994− "fastrand",
1995− "redox_syscall 0.4.1",
1996− "rustix",
1997− "windows-sys 0.48.0",
1998]
593]
1999
594
2000[[package]]
595[[package]]
2001−name = "termcolor"
596+name = "lsp-types"
2002−version = "1.2.0"
597+version = "0.91.1"
2003source = "registry+https://github.com/rust-lang/crates.io-index"
598source = "registry+https://github.com/rust-lang/crates.io-index"
2004−checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
599+checksum = "2368312c59425dd133cb9a327afee65be0a633a8ce471d248e2202a48f8f68ae"
2005dependencies = [
600dependencies = [
2006− "winapi-util",
601+ "bitflags",
602+ "serde",
603+ "serde_json",
604+ "serde_repr",
605+ "url",
2007]
606]
2008
607
2009[[package]]
608[[package]]
2010−name = "termini"
609+name = "mac"
2011−version = "1.0.0"
610+version = "0.1.1"
2012source = "registry+https://github.com/rust-lang/crates.io-index"
611source = "registry+https://github.com/rust-lang/crates.io-index"
2013−checksum = "2ad441d87dd98bc5eeb31cf2fb7e4839968763006b478efb38668a3bf9da0d59"
612+checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
2014−dependencies = [
2015− "home",
2016−]
2017
613
2018[[package]]
614[[package]]
2019−name = "textwrap"
615+name = "matches"
2020−version = "0.16.0"
616+version = "0.1.9"
2021source = "registry+https://github.com/rust-lang/crates.io-index"
617source = "registry+https://github.com/rust-lang/crates.io-index"
2022−checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
618+checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
2023−dependencies = [
2024− "smawk",
2025− "unicode-linebreak",
2026− "unicode-width",
2027−]
2028
619
2029[[package]]
620[[package]]
2030−name = "thiserror"
621+name = "memchr"
2031−version = "1.0.52"
622+version = "2.4.1"
2032source = "registry+https://github.com/rust-lang/crates.io-index"
623source = "registry+https://github.com/rust-lang/crates.io-index"
2033−checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d"
624+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
2034−dependencies = [
2035− "thiserror-impl",
2036−]
2037
625
2038[[package]]
626[[package]]
2039−name = "thiserror-impl"
627+name = "memmap2"
2040−version = "1.0.52"
628+version = "0.3.1"
2041source = "registry+https://github.com/rust-lang/crates.io-index"
629source = "registry+https://github.com/rust-lang/crates.io-index"
2042−checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3"
630+checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357"
2043dependencies = [
631dependencies = [
2044− "proc-macro2",
632+ "libc",
2045− "quote",
2046− "syn 2.0.38",
2047]
633]
2048
634
2049[[package]]
635[[package]]
2050−name = "threadpool"
636+name = "mio"
2051−version = "1.8.1"
637+version = "0.7.14"
2052source = "registry+https://github.com/rust-lang/crates.io-index"
638source = "registry+https://github.com/rust-lang/crates.io-index"
2053−checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
639+checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
2054dependencies = [
640dependencies = [
2055− "num_cpus",
641+ "libc",
642+ "log",
643+ "miow",
644+ "ntapi",
645+ "winapi",
2056]
646]
2057
647
2058[[package]]
648[[package]]
2059−name = "time"
649+name = "miow"
2060−version = "0.3.23"
650+version = "0.3.7"
2061source = "registry+https://github.com/rust-lang/crates.io-index"
651source = "registry+https://github.com/rust-lang/crates.io-index"
2062−checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446"
652+checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
2063dependencies = [
653dependencies = [
2064− "itoa",
654+ "winapi",
2065− "libc",
2066− "num_threads",
2067− "serde",
2068− "time-core",
2069− "time-macros",
2070]
655]
2071
656
2072[[package]]
657[[package]]
2073−name = "time-core"
658+name = "new_debug_unreachable"
2074−version = "0.1.1"
659+version = "1.0.4"
2075source = "registry+https://github.com/rust-lang/crates.io-index"
660source = "registry+https://github.com/rust-lang/crates.io-index"
2076−checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
661+checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
2077
662
2078[[package]]
663[[package]]
2079−name = "time-macros"
664+name = "ntapi"
2080−version = "0.2.10"
665+version = "0.3.6"
2081source = "registry+https://github.com/rust-lang/crates.io-index"
666source = "registry+https://github.com/rust-lang/crates.io-index"
2082−checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4"
667+checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
2083dependencies = [
668dependencies = [
2084− "time-core",
669+ "winapi",
2085]
670]
2086
671
2087[[package]]
672[[package]]
2088−name = "tinyvec"
673+name = "num-integer"
2089−version = "1.6.0"
674+version = "0.1.44"
2090source = "registry+https://github.com/rust-lang/crates.io-index"
675source = "registry+https://github.com/rust-lang/crates.io-index"
2091−checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
676+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
2092dependencies = [
677dependencies = [
2093− "tinyvec_macros",
678+ "autocfg",
679+ "num-traits",
2094]
680]
2095
681
2096[[package]]
682[[package]]
2097−name = "tinyvec_macros"
683+name = "num-traits"
2098−version = "0.1.1"
684+version = "0.2.14"
2099source = "registry+https://github.com/rust-lang/crates.io-index"
685source = "registry+https://github.com/rust-lang/crates.io-index"
2100−checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
686+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
687+dependencies = [
688+ "autocfg",
689+]
2101
690
2102[[package]]
691[[package]]
2103−name = "tokio"
692+name = "num_cpus"
2104−version = "1.35.1"
693+version = "1.13.1"
2105source = "registry+https://github.com/rust-lang/crates.io-index"
694source = "registry+https://github.com/rust-lang/crates.io-index"
2106−checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
695+checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
2107dependencies = [
696dependencies = [
2108− "backtrace",
697+ "hermit-abi",
2109− "bytes",
2110 "libc",
698 "libc",
2111− "mio",
2112− "num_cpus",
2113− "parking_lot",
2114− "pin-project-lite",
2115− "signal-hook-registry",
2116− "socket2",
2117− "tokio-macros",
2118− "windows-sys 0.48.0",
2119]
699]
2120
700
2121[[package]]
701[[package]]
2122−name = "tokio-macros"
702+name = "once_cell"
2123−version = "2.2.0"
703+version = "1.9.0"
2124source = "registry+https://github.com/rust-lang/crates.io-index"
704source = "registry+https://github.com/rust-lang/crates.io-index"
2125−checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
705+checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
2126−dependencies = [
2127− "proc-macro2",
2128− "quote",
2129− "syn 2.0.38",
2130−]
2131
706
2132[[package]]
707[[package]]
2133−name = "tokio-stream"
708+name = "parking_lot"
2134−version = "0.1.14"
709+version = "0.11.2"
2135source = "registry+https://github.com/rust-lang/crates.io-index"
710source = "registry+https://github.com/rust-lang/crates.io-index"
2136−checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
711+checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
2137dependencies = [
712dependencies = [
2138− "futures-core",
713+ "instant",
2139− "pin-project-lite",
714+ "lock_api",
2140− "tokio",
715+ "parking_lot_core",
2141]
716]
2142
717
2143[[package]]
718[[package]]
2144−name = "toml"
719+name = "parking_lot_core"
2145−version = "0.7.6"
720+version = "0.8.5"
2146source = "registry+https://github.com/rust-lang/crates.io-index"
721source = "registry+https://github.com/rust-lang/crates.io-index"
2147−checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542"
722+checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
2148dependencies = [
723dependencies = [
2149− "serde",
724+ "cfg-if",
2150− "serde_spanned",
725+ "instant",
2151− "toml_datetime",
726+ "libc",
2152− "toml_edit",
727+ "redox_syscall",
728+ "smallvec",
729+ "winapi",
2153]
730]
2154
731
2155[[package]]
732[[package]]
2156−name = "toml_datetime"
733+name = "percent-encoding"
2157−version = "0.6.3"
734+version = "2.1.0"
2158source = "registry+https://github.com/rust-lang/crates.io-index"
735source = "registry+https://github.com/rust-lang/crates.io-index"
2159−checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
736+checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
2160−dependencies = [
737+
2161− "serde",
738+[[package]]
2162−]
739+name = "pin-project-lite"
740+version = "0.2.7"
741+source = "registry+https://github.com/rust-lang/crates.io-index"
742+checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
743+
744+[[package]]
745+name = "pin-utils"
746+version = "0.1.0"
747+source = "registry+https://github.com/rust-lang/crates.io-index"
748+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
2163
749
2164[[package]]
750[[package]]
2165−name = "toml_edit"
751+name = "proc-macro2"
2166−version = "0.19.12"
752+version = "1.0.30"
2167source = "registry+https://github.com/rust-lang/crates.io-index"
753source = "registry+https://github.com/rust-lang/crates.io-index"
2168−checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78"
754+checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
2169dependencies = [
755dependencies = [
2170− "indexmap",
756+ "unicode-xid",
2171− "serde",
2172− "serde_spanned",
2173− "toml_datetime",
2174− "winnow 0.4.6",
2175]
757]
2176
758
2177[[package]]
759[[package]]
2178−name = "tree-sitter"
760+name = "pulldown-cmark"
2179−version = "0.20.10"
761+version = "0.8.0"
2180−source = "git+https://github.com/tree-sitter/tree-sitter?rev=ab09ae20d640711174b8da8a654f6b3dec93da1a#ab09ae20d640711174b8da8a654f6b3dec93da1a"
762+source = "registry+https://github.com/rust-lang/crates.io-index"
763+checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
2181dependencies = [
764dependencies = [
2182− "cc",
765+ "bitflags",
2183− "regex",
766+ "memchr",
767+ "unicase",
2184]
768]
2185
769
2186[[package]]
770[[package]]
2187−name = "unicase"
771+name = "quickcheck"
2188−version = "2.6.0"
772+version = "1.0.3"
2189source = "registry+https://github.com/rust-lang/crates.io-index"
773source = "registry+https://github.com/rust-lang/crates.io-index"
2190−checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
774+checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6"
2191dependencies = [
775dependencies = [
2192− "version_check",
776+ "rand",
2193]
777]
2194
778
2195[[package]]
779[[package]]
2196−name = "unicode-bidi"
780+name = "quote"
2197−version = "0.3.13"
781+version = "1.0.10"
2198source = "registry+https://github.com/rust-lang/crates.io-index"
782source = "registry+https://github.com/rust-lang/crates.io-index"
2199−checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
783+checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
784+dependencies = [
785+ "proc-macro2",
786+]
2200
787
2201[[package]]
788[[package]]
2202−name = "unicode-bom"
789+name = "rand"
2203−version = "2.0.2"
790+version = "0.8.4"
2204source = "registry+https://github.com/rust-lang/crates.io-index"
791source = "registry+https://github.com/rust-lang/crates.io-index"
2205−checksum = "98e90c70c9f0d4d1ee6d0a7d04aa06cb9bbd53d8cfbdd62a0269a7c2eb640552"
792+checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
793+dependencies = [
794+ "rand_core",
795+]
2206
796
2207[[package]]
797[[package]]
2208−name = "unicode-general-category"
798+name = "rand_core"
2209−version = "0.6.0"
799+version = "0.6.3"
2210source = "registry+https://github.com/rust-lang/crates.io-index"
800source = "registry+https://github.com/rust-lang/crates.io-index"
2211−checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7"
801+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
802+dependencies = [
803+ "getrandom",
804+]
2212
805
2213[[package]]
806[[package]]
2214−name = "unicode-ident"
807+name = "redox_syscall"
2215−version = "1.0.8"
808+version = "0.2.10"
2216source = "registry+https://github.com/rust-lang/crates.io-index"
809source = "registry+https://github.com/rust-lang/crates.io-index"
2217−checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
810+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
811+dependencies = [
812+ "bitflags",
813+]
2218
814
2219[[package]]
815[[package]]
2220−name = "unicode-linebreak"
816+name = "redox_users"
2221−version = "0.1.5"
817+version = "0.4.0"
2222source = "registry+https://github.com/rust-lang/crates.io-index"
818source = "registry+https://github.com/rust-lang/crates.io-index"
2223−checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
819+checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
820+dependencies = [
821+ "getrandom",
822+ "redox_syscall",
823+]
2224
824
2225[[package]]
825[[package]]
2226−name = "unicode-normalization"
826+name = "regex"
2227−version = "0.1.22"
827+version = "1.5.4"
2228source = "registry+https://github.com/rust-lang/crates.io-index"
828source = "registry+https://github.com/rust-lang/crates.io-index"
2229−checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
829+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
2230dependencies = [
830dependencies = [
2231− "tinyvec",
831+ "aho-corasick",
832+ "memchr",
833+ "regex-syntax",
2232]
834]
2233
835
2234[[package]]
836[[package]]
2235−name = "unicode-segmentation"
837+name = "regex-automata"
2236−version = "1.10.1"
838+version = "0.1.10"
2237source = "registry+https://github.com/rust-lang/crates.io-index"
839source = "registry+https://github.com/rust-lang/crates.io-index"
2238−checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
840+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
2239
841
2240[[package]]
842[[package]]
2241−name = "unicode-width"
843+name = "regex-syntax"
2242−version = "0.1.11"
844+version = "0.6.25"
2243source = "registry+https://github.com/rust-lang/crates.io-index"
845source = "registry+https://github.com/rust-lang/crates.io-index"
2244−checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
846+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
2245
847
2246[[package]]
848[[package]]
2247−name = "url"
849+name = "ropey"
2248−version = "2.5.0"
850+version = "1.3.2"
2249source = "registry+https://github.com/rust-lang/crates.io-index"
851source = "registry+https://github.com/rust-lang/crates.io-index"
2250−checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
852+checksum = "e6b9aa65bcd9f308d37c7158b4a1afaaa32b8450213e20c9b98e7d5b3cc2fec3"
2251dependencies = [
853dependencies = [
2252− "form_urlencoded",
854+ "smallvec",
2253− "idna",
2254− "percent-encoding",
2255− "serde",
2256]
855]
2257
856
2258[[package]]
857[[package]]
2259−name = "version_check"
858+name = "ryu"
2260−version = "0.9.4"
859+version = "1.0.5"
2261source = "registry+https://github.com/rust-lang/crates.io-index"
860source = "registry+https://github.com/rust-lang/crates.io-index"
2262−checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
861+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
2263
862
2264[[package]]
863[[package]]
2265−name = "walkdir"
864+name = "same-file"
2266−version = "2.4.0"
865+version = "1.0.6"
2267source = "registry+https://github.com/rust-lang/crates.io-index"
866source = "registry+https://github.com/rust-lang/crates.io-index"
2268−checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
867+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
2269dependencies = [
868dependencies = [
2270− "same-file",
2271 "winapi-util",
869 "winapi-util",
2272]
870]
2273
871
2274[[package]]
872[[package]]
2275−name = "wasi"
873+name = "scopeguard"
2276−version = "0.11.0+wasi-snapshot-preview1"
874+version = "1.1.0"
2277source = "registry+https://github.com/rust-lang/crates.io-index"
875source = "registry+https://github.com/rust-lang/crates.io-index"
2278−checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
876+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
2279
877
2280[[package]]
878[[package]]
2281−name = "wasm-bindgen"
879+name = "serde"
2282−version = "0.2.84"
880+version = "1.0.133"
2283source = "registry+https://github.com/rust-lang/crates.io-index"
881source = "registry+https://github.com/rust-lang/crates.io-index"
2284−checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
882+checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a"
2285dependencies = [
883dependencies = [
2286− "cfg-if",
884+ "serde_derive",
2287− "wasm-bindgen-macro",
2288]
885]
2289
886
2290[[package]]
887[[package]]
2291−name = "wasm-bindgen-backend"
888+name = "serde_derive"
2292−version = "0.2.84"
889+version = "1.0.133"
2293source = "registry+https://github.com/rust-lang/crates.io-index"
890source = "registry+https://github.com/rust-lang/crates.io-index"
2294−checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
891+checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537"
2295dependencies = [
892dependencies = [
2296− "bumpalo",
2297− "log",
2298− "once_cell",
2299 "proc-macro2",
893 "proc-macro2",
2300 "quote",
894 "quote",
2301− "syn 1.0.109",
895+ "syn",
2302− "wasm-bindgen-shared",
2303]
896]
2304
897
2305[[package]]
898[[package]]
2306−name = "wasm-bindgen-macro"
899+name = "serde_json"
2307−version = "0.2.84"
900+version = "1.0.74"
2308source = "registry+https://github.com/rust-lang/crates.io-index"
901source = "registry+https://github.com/rust-lang/crates.io-index"
2309−checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
902+checksum = "ee2bb9cd061c5865d345bb02ca49fcef1391741b672b54a0bf7b679badec3142"
2310dependencies = [
903dependencies = [
2311− "quote",
904+ "itoa",
2312− "wasm-bindgen-macro-support",
905+ "ryu",
906+ "serde",
2313]
907]
2314
908
2315[[package]]
909[[package]]
2316−name = "wasm-bindgen-macro-support"
910+name = "serde_repr"
2317−version = "0.2.84"
911+version = "0.1.7"
2318source = "registry+https://github.com/rust-lang/crates.io-index"
912source = "registry+https://github.com/rust-lang/crates.io-index"
2319−checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
913+checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5"
2320dependencies = [
914dependencies = [
2321 "proc-macro2",
915 "proc-macro2",
2322 "quote",
916 "quote",
2323− "syn 1.0.109",
917+ "syn",
2324− "wasm-bindgen-backend",
2325− "wasm-bindgen-shared",
2326]
918]
2327
919
2328[[package]]
920[[package]]
2329−name = "wasm-bindgen-shared"
921+name = "signal-hook"
2330−version = "0.2.84"
922+version = "0.3.13"
2331source = "registry+https://github.com/rust-lang/crates.io-index"
923source = "registry+https://github.com/rust-lang/crates.io-index"
2332−checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
924+checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
925+dependencies = [
926+ "libc",
927+ "signal-hook-registry",
928+]
2333
929
2334[[package]]
930[[package]]
2335−name = "which"
931+name = "signal-hook-mio"
2336−version = "5.0.0"
932+version = "0.2.1"
2337source = "registry+https://github.com/rust-lang/crates.io-index"
933source = "registry+https://github.com/rust-lang/crates.io-index"
2338−checksum = "9bf3ea8596f3a0dd5980b46430f2058dfe2c36a27ccfbb1845d6fbfcd9ba6e14"
934+checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4"
2339dependencies = [
935dependencies = [
2340− "either",
936+ "libc",
2341− "home",
937+ "mio",
2342− "once_cell",
938+ "signal-hook",
2343− "rustix",
2344− "windows-sys 0.48.0",
2345]
939]
2346
940
2347[[package]]
941[[package]]
2348−name = "winapi"
942+name = "signal-hook-registry"
2349−version = "0.3.9"
943+version = "1.4.0"
2350source = "registry+https://github.com/rust-lang/crates.io-index"
944source = "registry+https://github.com/rust-lang/crates.io-index"
2351−checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
945+checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
2352dependencies = [
946dependencies = [
2353− "winapi-i686-pc-windows-gnu",
947+ "libc",
2354− "winapi-x86_64-pc-windows-gnu",
2355]
948]
2356
949
2357[[package]]
950[[package]]
2358−name = "winapi-i686-pc-windows-gnu"
951+name = "signal-hook-tokio"
2359−version = "0.4.0"
952+version = "0.3.0"
2360source = "registry+https://github.com/rust-lang/crates.io-index"
953source = "registry+https://github.com/rust-lang/crates.io-index"
2361−checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
954+checksum = "f6c5d32165ff8b94e68e7b3bdecb1b082e958c22434b363482cfb89dcd6f3ff8"
955+dependencies = [
956+ "futures-core",
957+ "libc",
958+ "signal-hook",
959+ "tokio",
960+]
2362
961
2363[[package]]
962[[package]]
2364−name = "winapi-util"
963+name = "similar"
2365−version = "0.1.5"
964+version = "2.1.0"
2366source = "registry+https://github.com/rust-lang/crates.io-index"
965source = "registry+https://github.com/rust-lang/crates.io-index"
2367−checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
966+checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3"
2368−dependencies = [
2369− "winapi",
2370−]
2371
967
2372[[package]]
968[[package]]
2373−name = "winapi-x86_64-pc-windows-gnu"
969+name = "slab"
2374−version = "0.4.0"
970+version = "0.4.5"
2375source = "registry+https://github.com/rust-lang/crates.io-index"
971source = "registry+https://github.com/rust-lang/crates.io-index"
2376−checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
972+checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
2377
973
2378[[package]]
974[[package]]
2379−name = "windows"
975+name = "slotmap"
2380−version = "0.48.0"
976+version = "1.0.6"
2381source = "registry+https://github.com/rust-lang/crates.io-index"
977source = "registry+https://github.com/rust-lang/crates.io-index"
2382−checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
978+checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
2383dependencies = [
979dependencies = [
2384− "windows-targets 0.48.0",
980+ "version_check",
2385]
981]
2386
982
2387[[package]]
983[[package]]
2388−name = "windows"
984+name = "smallvec"
2389−version = "0.52.0"
985+version = "1.7.0"
2390source = "registry+https://github.com/rust-lang/crates.io-index"
986source = "registry+https://github.com/rust-lang/crates.io-index"
2391−checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
987+checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
2392−dependencies = [
988+
2393− "windows-core",
989+[[package]]
2394− "windows-targets 0.52.0",
990+name = "str-buf"
2395−]
991+version = "1.0.5"
992+source = "registry+https://github.com/rust-lang/crates.io-index"
993+checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a"
2396
994
2397[[package]]
995[[package]]
2398−name = "windows-core"
996+name = "syn"
2399−version = "0.52.0"
997+version = "1.0.80"
2400source = "registry+https://github.com/rust-lang/crates.io-index"
998source = "registry+https://github.com/rust-lang/crates.io-index"
2401−checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
999+checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
2402dependencies = [
1000dependencies = [
2403− "windows-targets 0.52.0",
1001+ "proc-macro2",
1002+ "quote",
1003+ "unicode-xid",
2404]
1004]
2405
1005
2406[[package]]
1006[[package]]
2407−name = "windows-sys"
1007+name = "tendril"
2408−version = "0.45.0"
1008+version = "0.4.2"
2409source = "registry+https://github.com/rust-lang/crates.io-index"
1009source = "registry+https://github.com/rust-lang/crates.io-index"
2410−checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
1010+checksum = "a9ef557cb397a4f0a5a3a628f06515f78563f2209e64d47055d9dc6052bf5e33"
2411dependencies = [
1011dependencies = [
2412− "windows-targets 0.42.2",
1012+ "futf",
1013+ "mac",
1014+ "utf-8",
2413]
1015]
2414
1016
2415[[package]]
1017[[package]]
2416−name = "windows-sys"
1018+name = "thiserror"
2417−version = "0.48.0"
1019+version = "1.0.30"
2418source = "registry+https://github.com/rust-lang/crates.io-index"
1020source = "registry+https://github.com/rust-lang/crates.io-index"
2419−checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
1021+checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
2420dependencies = [
1022dependencies = [
2421− "windows-targets 0.48.0",
1023+ "thiserror-impl",
2422]
1024]
2423
1025
2424[[package]]
1026[[package]]
2425−name = "windows-sys"
1027+name = "thiserror-impl"
2426−version = "0.52.0"
1028+version = "1.0.30"
2427source = "registry+https://github.com/rust-lang/crates.io-index"
1029source = "registry+https://github.com/rust-lang/crates.io-index"
2428−checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
1030+checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
2429dependencies = [
1031dependencies = [
2430− "windows-targets 0.52.0",
1032+ "proc-macro2",
1033+ "quote",
1034+ "syn",
2431]
1035]
2432
1036
2433[[package]]
1037[[package]]
2434−name = "windows-targets"
1038+name = "thread_local"
2435−version = "0.42.2"
1039+version = "1.1.3"
2436source = "registry+https://github.com/rust-lang/crates.io-index"
1040source = "registry+https://github.com/rust-lang/crates.io-index"
2437−checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
1041+checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
2438dependencies = [
1042dependencies = [
2439− "windows_aarch64_gnullvm 0.42.2",
1043+ "once_cell",
2440− "windows_aarch64_msvc 0.42.2",
2441− "windows_i686_gnu 0.42.2",
2442− "windows_i686_msvc 0.42.2",
2443− "windows_x86_64_gnu 0.42.2",
2444− "windows_x86_64_gnullvm 0.42.2",
2445− "windows_x86_64_msvc 0.42.2",
2446]
1044]
2447
1045
2448[[package]]
1046[[package]]
2449−name = "windows-targets"
1047+name = "threadpool"
2450−version = "0.48.0"
1048+version = "1.8.1"
2451source = "registry+https://github.com/rust-lang/crates.io-index"
1049source = "registry+https://github.com/rust-lang/crates.io-index"
2452−checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
1050+checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
2453dependencies = [
1051dependencies = [
2454− "windows_aarch64_gnullvm 0.48.0",
1052+ "num_cpus",
2455− "windows_aarch64_msvc 0.48.0",
2456− "windows_i686_gnu 0.48.0",
2457− "windows_i686_msvc 0.48.0",
2458− "windows_x86_64_gnu 0.48.0",
2459− "windows_x86_64_gnullvm 0.48.0",
2460− "windows_x86_64_msvc 0.48.0",
2461]
1053]
2462
1054
2463[[package]]
1055[[package]]
2464−name = "windows-targets"
1056+name = "tinyvec"
2465−version = "0.52.0"
1057+version = "1.5.0"
2466source = "registry+https://github.com/rust-lang/crates.io-index"
1058source = "registry+https://github.com/rust-lang/crates.io-index"
2467−checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
1059+checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7"
2468dependencies = [
1060dependencies = [
2469− "windows_aarch64_gnullvm 0.52.0",
1061+ "tinyvec_macros",
2470− "windows_aarch64_msvc 0.52.0",
2471− "windows_i686_gnu 0.52.0",
2472− "windows_i686_msvc 0.52.0",
2473− "windows_x86_64_gnu 0.52.0",
2474− "windows_x86_64_gnullvm 0.52.0",
2475− "windows_x86_64_msvc 0.52.0",
2476]
1062]
2477
1063
2478[[package]]
1064[[package]]
2479−name = "windows_aarch64_gnullvm"
1065+name = "tinyvec_macros"
2480−version = "0.42.2"
1066+version = "0.1.0"
2481source = "registry+https://github.com/rust-lang/crates.io-index"
1067source = "registry+https://github.com/rust-lang/crates.io-index"
2482−checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
1068+checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
2483
1069
2484[[package]]
1070[[package]]
2485−name = "windows_aarch64_gnullvm"
1071+name = "tokio"
2486−version = "0.48.0"
1072+version = "1.15.0"
2487source = "registry+https://github.com/rust-lang/crates.io-index"
1073source = "registry+https://github.com/rust-lang/crates.io-index"
2488−checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
1074+checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838"
1075+dependencies = [
1076+ "bytes",
1077+ "libc",
1078+ "memchr",
1079+ "mio",
1080+ "num_cpus",
1081+ "once_cell",
1082+ "parking_lot",
1083+ "pin-project-lite",
1084+ "signal-hook-registry",
1085+ "tokio-macros",
1086+ "winapi",
1087+]
2489
1088
2490[[package]]
1089[[package]]
2491−name = "windows_aarch64_gnullvm"
1090+name = "tokio-macros"
2492−version = "0.52.0"
1091+version = "1.7.0"
2493source = "registry+https://github.com/rust-lang/crates.io-index"
1092source = "registry+https://github.com/rust-lang/crates.io-index"
2494−checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
1093+checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
1094+dependencies = [
1095+ "proc-macro2",
1096+ "quote",
1097+ "syn",
1098+]
2495
1099
2496[[package]]
1100[[package]]
2497−name = "windows_aarch64_msvc"
1101+name = "tokio-stream"
2498−version = "0.42.2"
1102+version = "0.1.8"
2499source = "registry+https://github.com/rust-lang/crates.io-index"
1103source = "registry+https://github.com/rust-lang/crates.io-index"
2500−checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
1104+checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3"
1105+dependencies = [
1106+ "futures-core",
1107+ "pin-project-lite",
1108+ "tokio",
1109+]
2501
1110
2502[[package]]
1111[[package]]
2503−name = "windows_aarch64_msvc"
1112+name = "toml"
2504−version = "0.48.0"
1113+version = "0.5.8"
2505source = "registry+https://github.com/rust-lang/crates.io-index"
1114source = "registry+https://github.com/rust-lang/crates.io-index"
2506−checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
1115+checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
1116+dependencies = [
1117+ "serde",
1118+]
2507
1119
2508[[package]]
1120[[package]]
2509−name = "windows_aarch64_msvc"
1121+name = "tree-sitter"
2510−version = "0.52.0"
1122+version = "0.20.2"
2511source = "registry+https://github.com/rust-lang/crates.io-index"
1123source = "registry+https://github.com/rust-lang/crates.io-index"
2512−checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
1124+checksum = "c36be3222512d85a112491ae0cc280a38076022414f00b64582da1b7565ffd82"
1125+dependencies = [
1126+ "cc",
1127+ "regex",
1128+]
2513
1129
2514[[package]]
1130[[package]]
2515−name = "windows_i686_gnu"
1131+name = "unicase"
2516−version = "0.42.2"
1132+version = "2.6.0"
2517source = "registry+https://github.com/rust-lang/crates.io-index"
1133source = "registry+https://github.com/rust-lang/crates.io-index"
2518−checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
1134+checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
1135+dependencies = [
1136+ "version_check",
1137+]
2519
1138
2520[[package]]
1139[[package]]
2521−name = "windows_i686_gnu"
1140+name = "unicode-bidi"
2522−version = "0.48.0"
1141+version = "0.3.7"
2523source = "registry+https://github.com/rust-lang/crates.io-index"
1142source = "registry+https://github.com/rust-lang/crates.io-index"
2524−checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
1143+checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
2525
1144
2526[[package]]
1145[[package]]
2527−name = "windows_i686_gnu"
1146+name = "unicode-general-category"
2528−version = "0.52.0"
1147+version = "0.4.0"
2529source = "registry+https://github.com/rust-lang/crates.io-index"
1148source = "registry+https://github.com/rust-lang/crates.io-index"
2530−checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
1149+checksum = "07547e3ee45e28326cc23faac56d44f58f16ab23e413db526debce3b0bfd2742"
2531
1150
2532[[package]]
1151[[package]]
2533−name = "windows_i686_msvc"
1152+name = "unicode-normalization"
2534−version = "0.42.2"
1153+version = "0.1.19"
2535source = "registry+https://github.com/rust-lang/crates.io-index"
1154source = "registry+https://github.com/rust-lang/crates.io-index"
2536−checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
1155+checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
1156+dependencies = [
1157+ "tinyvec",
1158+]
2537
1159
2538[[package]]
1160[[package]]
2539−name = "windows_i686_msvc"
1161+name = "unicode-segmentation"
2540−version = "0.48.0"
1162+version = "1.8.0"
2541source = "registry+https://github.com/rust-lang/crates.io-index"
1163source = "registry+https://github.com/rust-lang/crates.io-index"
2542−checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
1164+checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
2543
1165
2544[[package]]
1166[[package]]
2545−name = "windows_i686_msvc"
1167+name = "unicode-width"
2546−version = "0.52.0"
1168+version = "0.1.9"
2547source = "registry+https://github.com/rust-lang/crates.io-index"
1169source = "registry+https://github.com/rust-lang/crates.io-index"
2548−checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
1170+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
2549
1171
2550[[package]]
1172[[package]]
2551−name = "windows_x86_64_gnu"
1173+name = "unicode-xid"
2552−version = "0.42.2"
1174+version = "0.2.2"
2553source = "registry+https://github.com/rust-lang/crates.io-index"
1175source = "registry+https://github.com/rust-lang/crates.io-index"
2554−checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
1176+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
2555
1177
2556[[package]]
1178[[package]]
2557−name = "windows_x86_64_gnu"
1179+name = "url"
2558−version = "0.48.0"
1180+version = "2.2.2"
2559source = "registry+https://github.com/rust-lang/crates.io-index"
1181source = "registry+https://github.com/rust-lang/crates.io-index"
2560−checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
1182+checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
1183+dependencies = [
1184+ "form_urlencoded",
1185+ "idna",
1186+ "matches",
1187+ "percent-encoding",
1188+ "serde",
1189+]
2561
1190
2562[[package]]
1191[[package]]
2563−name = "windows_x86_64_gnu"
1192+name = "utf-8"
2564−version = "0.52.0"
1193+version = "0.7.6"
2565source = "registry+https://github.com/rust-lang/crates.io-index"
1194source = "registry+https://github.com/rust-lang/crates.io-index"
2566−checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
1195+checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
2567
1196
2568[[package]]
1197[[package]]
2569−name = "windows_x86_64_gnullvm"
1198+name = "version_check"
2570−version = "0.42.2"
1199+version = "0.9.3"
2571source = "registry+https://github.com/rust-lang/crates.io-index"
1200source = "registry+https://github.com/rust-lang/crates.io-index"
2572−checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
1201+checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
2573
1202
2574[[package]]
1203[[package]]
2575−name = "windows_x86_64_gnullvm"
1204+name = "walkdir"
2576−version = "0.48.0"
1205+version = "2.3.2"
2577source = "registry+https://github.com/rust-lang/crates.io-index"
1206source = "registry+https://github.com/rust-lang/crates.io-index"
2578−checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
1207+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
1208+dependencies = [
1209+ "same-file",
1210+ "winapi",
1211+ "winapi-util",
1212+]
2579
1213
2580[[package]]
1214[[package]]
2581−name = "windows_x86_64_gnullvm"
1215+name = "wasi"
2582−version = "0.52.0"
1216+version = "0.10.2+wasi-snapshot-preview1"
2583source = "registry+https://github.com/rust-lang/crates.io-index"
1217source = "registry+https://github.com/rust-lang/crates.io-index"
2584−checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
1218+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
2585
1219
2586[[package]]
1220[[package]]
2587−name = "windows_x86_64_msvc"
1221+name = "which"
2588−version = "0.42.2"
1222+version = "4.2.2"
2589source = "registry+https://github.com/rust-lang/crates.io-index"
1223source = "registry+https://github.com/rust-lang/crates.io-index"
2590−checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
1224+checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9"
1225+dependencies = [
1226+ "either",
1227+ "lazy_static",
1228+ "libc",
1229+]
2591
1230
2592[[package]]
1231[[package]]
2593−name = "windows_x86_64_msvc"
1232+name = "winapi"
2594−version = "0.48.0"
1233+version = "0.3.9"
2595source = "registry+https://github.com/rust-lang/crates.io-index"
1234source = "registry+https://github.com/rust-lang/crates.io-index"
2596−checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
1235+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1236+dependencies = [
1237+ "winapi-i686-pc-windows-gnu",
1238+ "winapi-x86_64-pc-windows-gnu",
1239+]
2597
1240
2598[[package]]
1241[[package]]
2599−name = "windows_x86_64_msvc"
1242+name = "winapi-i686-pc-windows-gnu"
2600−version = "0.52.0"
1243+version = "0.4.0"
2601source = "registry+https://github.com/rust-lang/crates.io-index"
1244source = "registry+https://github.com/rust-lang/crates.io-index"
2602−checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
1245+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
2603
1246
2604[[package]]
1247[[package]]
2605−name = "winnow"
1248+name = "winapi-util"
2606−version = "0.4.6"
1249+version = "0.1.5"
2607source = "registry+https://github.com/rust-lang/crates.io-index"
1250source = "registry+https://github.com/rust-lang/crates.io-index"
2608−checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
1251+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
2609dependencies = [
1252dependencies = [
2610− "memchr",
1253+ "winapi",
2611]
1254]
2612
1255
2613[[package]]
1256[[package]]
2614−name = "winnow"
1257+name = "winapi-x86_64-pc-windows-gnu"
2615−version = "0.5.28"
1258+version = "0.4.0"
2616source = "registry+https://github.com/rust-lang/crates.io-index"
1259source = "registry+https://github.com/rust-lang/crates.io-index"
2617−checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2"
1260+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
2618−dependencies = [
2619− "memchr",
2620−]
2621
1261
2622[[package]]
1262[[package]]
2623name = "xtask"
1263name = "xtask"
2624−version = "23.10.0"
1264+version = "0.5.0"
2625dependencies = [
1265dependencies = [
2626 "helix-core",
1266 "helix-core",
2627− "helix-loader",
2628 "helix-term",
1267 "helix-term",
2629− "helix-view",
2630 "toml",
1268 "toml",
2631]
1269]
2632−
2633−[[package]]
2634−name = "zerocopy"
2635−version = "0.7.31"
2636−source = "registry+https://github.com/rust-lang/crates.io-index"
2637−checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d"
2638−dependencies = [
2639− "zerocopy-derive",
2640−]
2641−
2642−[[package]]
2643−name = "zerocopy-derive"
2644−version = "0.7.31"
2645−source = "registry+https://github.com/rust-lang/crates.io-index"
2646−checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a"
2647−dependencies = [
2648− "proc-macro2",
2649− "quote",
2650− "syn 2.0.38",
2651−]
Cargo.toml+7−37
@@ -1,50 +1,20 @@
1[workspace]
1[workspace]
2−resolver = "2"
3members = [
2members = [
4 "helix-core",
3 "helix-core",
5 "helix-view",
4 "helix-view",
6 "helix-term",
5 "helix-term",
7 "helix-tui",
6 "helix-tui",
7+ "helix-syntax",
8 "helix-lsp",
8 "helix-lsp",
9− "helix-event",
10− "helix-dap",
11− "helix-loader",
12− "helix-vcs",
13− "helix-parsec",
14 "xtask",
9 "xtask",
15]
10]
16
11
17−default-members = [
12+# Build helix-syntax in release mode to make the code path faster in development.
18− "helix-term"
13+# [profile.dev.package."helix-syntax"]
19−]
14+# opt-level = 3
15+
16+[profile.dev]
17+split-debuginfo = "unpacked"
20
18
21[profile.release]
19[profile.release]
22lto = "thin"
20lto = "thin"
23−# debug = true
24−
25−[profile.opt]
26−inherits = "release"
27−lto = "fat"
28−codegen-units = 1
29−# strip = "debuginfo" # TODO: or strip = true
30−opt-level = 3
31−
32−[profile.integration]
33−inherits = "test"
34−package.helix-core.opt-level = 2
35−package.helix-tui.opt-level = 2
36−package.helix-term.opt-level = 2
37−
38−[workspace.dependencies]
39−tree-sitter = { version = "0.20", git = "https://github.com/tree-sitter/tree-sitter", rev = "ab09ae20d640711174b8da8a654f6b3dec93da1a" }
40−nucleo = "0.2.0"
41−
42−[workspace.package]
43−version = "23.10.0"
44−edition = "2021"
45−authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
46−categories = ["editor"]
47−repository = "https://github.com/helix-editor/helix"
48−homepage = "https://helix-editor.com"
49−license = "MPL-2.0"
50−rust-version = "1.70"
README.md+34−24
@@ -1,27 +1,14 @@
1−<div align="center">
1+# Helix
2
2
3−<h1>
4−<picture>
5− <source media="(prefers-color-scheme: dark)" srcset="logo_dark.svg">
6− <source media="(prefers-color-scheme: light)" srcset="logo_light.svg">
7− <img alt="Helix" height="128" src="logo_light.svg">
8−</picture>
9−</h1>
10
3
11[![Build status](https://github.com/helix-editor/helix/actions/workflows/build.yml/badge.svg)](https://github.com/helix-editor/helix/actions)
4[![Build status](https://github.com/helix-editor/helix/actions/workflows/build.yml/badge.svg)](https://github.com/helix-editor/helix/actions)
12−[![GitHub Release](https://img.shields.io/github/v/release/helix-editor/helix)](https://github.com/helix-editor/helix/releases/latest)
13−[![Documentation](https://shields.io/badge/-documentation-452859)](https://docs.helix-editor.com/)
14−[![GitHub contributors](https://img.shields.io/github/contributors/helix-editor/helix)](https://github.com/helix-editor/helix/graphs/contributors)
15−[![Matrix Space](https://img.shields.io/matrix/helix-community:matrix.org)](https://matrix.to/#/#helix-community:matrix.org)
16−
17−</div>
18
5
19![Screenshot](./screenshot.png)
6![Screenshot](./screenshot.png)
20
7
21−A [Kakoune](https://github.com/mawww/kakoune) / [Neovim](https://github.com/neovim/neovim) inspired editor, written in Rust.
8+A kakoune / neovim inspired editor, written in Rust.
22
9
23−The editing model is very heavily based on Kakoune; during development I found
10+The editing model is very heavily based on kakoune; during development I found
24−myself agreeing with most of Kakoune's design decisions.
11+myself agreeing with most of kakoune's design decisions.
25
12
26For more information, see the [website](https://helix-editor.com) or
13For more information, see the [website](https://helix-editor.com) or
27[documentation](https://docs.helix-editor.com/).
14[documentation](https://docs.helix-editor.com/).
@@ -38,17 +25,44 @@ All shortcuts/keymaps can be found [in the documentation on the website](https:/
38- Smart, incremental syntax highlighting and code editing via tree-sitter
25- Smart, incremental syntax highlighting and code editing via tree-sitter
39
26
40It's a terminal-based editor first, but I'd like to explore a custom renderer
27It's a terminal-based editor first, but I'd like to explore a custom renderer
41−(similar to Emacs) in wgpu or skulpin.
28+(similar to emacs) in wgpu or skulpin.
42
29
43Note: Only certain languages have indentation definitions at the moment. Check
30Note: Only certain languages have indentation definitions at the moment. Check
44−`runtime/queries/<lang>/` for `indents.scm`.
31+`runtime/queries/<lang>/` for `indents.toml`.
45
32
46# Installation
33# Installation
47
34
48−[Installation documentation](https://docs.helix-editor.com/install.html).
35+We provide packaging for various distributions, but here's a quick method to
36+build from source.
37+
38+```
39+git clone --recurse-submodules --shallow-submodules -j8 https://github.com/helix-editor/helix
40+cd helix
41+cargo install --path helix-term
42+```
43+
44+This will install the `hx` binary to `$HOME/.cargo/bin`.
45+
46+Helix also needs its runtime files so make sure to copy/symlink the `runtime/` directory into the
47+config directory (for example `~/.config/helix/runtime` on Linux/macOS, or `%AppData%/helix/runtime` on Windows).
48+This location can be overriden via the `HELIX_RUNTIME` environment variable.
49+
50+Packages already solve this for you by wrapping the `hx` binary with a wrapper
51+that sets the variable to the install dir.
52+
53+> NOTE: running via cargo also doesn't require setting explicit `HELIX_RUNTIME` path, it will automatically
54+> detect the `runtime` directory in the project root.
49
55
50[![Packaging status](https://repology.org/badge/vertical-allrepos/helix.svg)](https://repology.org/project/helix/versions)
56[![Packaging status](https://repology.org/badge/vertical-allrepos/helix.svg)](https://repology.org/project/helix/versions)
51
57
58+## MacOS
59+Helix can be installed on MacOS through homebrew via:
60+
61+```
62+brew tap helix-editor/helix
63+brew install helix
64+```
65+
52# Contributing
66# Contributing
53
67
54Contributing guidelines can be found [here](./docs/CONTRIBUTING.md).
68Contributing guidelines can be found [here](./docs/CONTRIBUTING.md).
@@ -58,7 +72,3 @@ Contributing guidelines can be found [here](./docs/CONTRIBUTING.md).
58Your question might already be answered on the [FAQ](https://github.com/helix-editor/helix/wiki/FAQ).
72Your question might already be answered on the [FAQ](https://github.com/helix-editor/helix/wiki/FAQ).
59
73
60Discuss 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).
74Discuss 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).
61−
62−# Credits
63−
64−Thanks to [@jakenvac](https://github.com/jakenvac) for designing the logo!
TODO.mdnew file+32
@@ -0,0 +1,32 @@
1+
2+- tree sitter:
3+ - markdown
4+ - regex
5+ - kotlin
6+ - clojure
7+ - erlang
8+
9+- [ ] completion isIncomplete support
10+
11+1
12+- [ ] respect view fullscreen flag
13+- [ ] Implement marks (superset of Selection/Range)
14+
15+- [ ] = for auto indent line/selection
16+- [ ] :x for closing buffers
17+- [ ] lsp: signature help
18+
19+2
20+- [ ] macro recording
21+- [ ] extend selection (treesitter select parent node) (replaces viw, vi(, va( etc )
22+- [ ] selection align
23+- [ ] store some state between restarts: file positions, prompt history
24+- [ ] highlight matched characters in picker
25+
26+3
27+- [ ] diff mode with highlighting?
28+- [ ] snippet support (tab to jump between marks)
29+- [ ] gamelisp/wasm scripting
30+
31+X
32+- [ ] rendering via skulpin/skia or raw wgpu
base16_theme.toml+3−12
@@ -1,17 +1,17 @@
1# Author: NNB <nnbnh@protonmail.com>
1# Author: NNB <nnbnh@protonmail.com>
2
2
3−"ui.menu" = { fg = "black", bg = "white" }
3+"ui.menu" = "black"
4"ui.menu.selected" = { modifiers = ["reversed"] }
4"ui.menu.selected" = { modifiers = ["reversed"] }
5"ui.linenr" = { fg = "gray", bg = "black" }
5"ui.linenr" = { fg = "gray", bg = "black" }
6"ui.popup" = { modifiers = ["reversed"] }
6"ui.popup" = { modifiers = ["reversed"] }
7"ui.linenr.selected" = { fg = "white", bg = "black", modifiers = ["bold"] }
7"ui.linenr.selected" = { fg = "white", bg = "black", modifiers = ["bold"] }
8"ui.selection" = { fg = "black", bg = "blue" }
8"ui.selection" = { fg = "black", bg = "blue" }
9"ui.selection.primary" = { fg = "white", bg = "blue" }
9"ui.selection.primary" = { fg = "white", bg = "blue" }
10−"ui.text.inactive" = { fg = "gray" }
11"comment" = { fg = "gray" }
10"comment" = { fg = "gray" }
12"ui.statusline" = { fg = "black", bg = "white" }
11"ui.statusline" = { fg = "black", bg = "white" }
13"ui.statusline.inactive" = { fg = "gray", bg = "white" }
12"ui.statusline.inactive" = { fg = "gray", bg = "white" }
13+"ui.help" = { modifiers = ["reversed"] }
14−"ui.cursor" = { fg = "white", modifiers = ["reversed"] }
14+"ui.cursor" = { modifiers = ["reversed"] }
15"variable" = "red"
15"variable" = "red"
16"constant.numeric" = "yellow"
16"constant.numeric" = "yellow"
17"constant" = "yellow"
17"constant" = "yellow"
@@ -29,15 +29,6 @@
29"namespace" = "magenta"
29"namespace" = "magenta"
30"ui.help" = { fg = "white", bg = "black" }
30"ui.help" = { fg = "white", bg = "black" }
31
31
32−"markup.heading" = "blue"
33−"markup.list" = "red"
34−"markup.bold" = { fg = "yellow", modifiers = ["bold"] }
35−"markup.italic" = { fg = "magenta", modifiers = ["italic"] }
36−"markup.link.url" = { fg = "yellow", modifiers = ["underlined"] }
37−"markup.link.text" = "red"
38−"markup.quote" = "cyan"
39−"markup.raw" = "green"
40−
41"diff.plus" = "green"
32"diff.plus" = "green"
42"diff.delta" = "yellow"
33"diff.delta" = "yellow"
43"diff.minus" = "red"
34"diff.minus" = "red"
book/book.toml+1−6
@@ -3,14 +3,9 @@ authors = ["Blaž Hrastnik"]
3language = "en"
3language = "en"
4multilingual = false
4multilingual = false
5src = "src"
5src = "src"
6+edit-url-template = "https://github.com/helix-editor/helix/tree/master/book/{path}?mode=edit"
6
7
7[output.html]
8[output.html]
8cname = "docs.helix-editor.com"
9cname = "docs.helix-editor.com"
9default-theme = "colibri"
10default-theme = "colibri"
10preferred-dark-theme = "colibri"
11preferred-dark-theme = "colibri"
11−git-repository-url = "https://github.com/helix-editor/helix"
12−edit-url-template = "https://github.com/helix-editor/helix/edit/master/book/{path}"
13−additional-css = ["custom.css"]
14−
15−[output.html.search]
16−use-boolean-and = true
book/custom.cssdeleted−231
@@ -1,231 +0,0 @@
1−html {
2− font-family: "Inter", sans-serif;
3−}
4−
5−.sidebar .sidebar-scrollbox {
6− padding: 0;
7−}
8−
9−.chapter {
10− margin: 0.25rem 0;
11−}
12−
13−.chapter li.chapter-item {
14− line-height: initial;
15− margin: 0;
16− padding: 1rem 1.5rem;
17−}
18−
19−.chapter .section li.chapter-item {
20− line-height: inherit;
21− padding: .5rem .5rem 0 .5rem;
22−}
23−
24−.content {
25− overflow-y: auto;
26− padding: 0 15px;
27− padding-bottom: 50px;
28−}
29−
30−/* 2 1.75 1.5 1.25 1 .875 */
31−.content h1 { font-size: 2em }
32−.content h2 { font-size: 1.75em }
33−.content h3 { font-size: 1.5em }
34−.content h4 { font-size: 1.25em }
35−.content h5 { font-size: 1em }
36−.content h6 { font-size: .875em }
37−
38−.content h1,
39−.content h2,
40−.content h3,
41−.content h4 {
42− font-weight: 500;
43− margin-top: 1.275em;
44− margin-bottom: .875em;
45−}
46−
47−.content p,
48−.content ol,
49−.content ul,
50−.content table {
51− margin-top: 0;
52− margin-bottom: .875em;
53−}
54−
55−.content ul li {
56− margin-bottom: .25rem;
57−}
58−
59−.content ul {
60− list-style-type: square;
61−}
62−
63−.content ul ul,
64−.content ol ul {
65− margin-bottom: .5rem;
66−}
67−
68−.content li p {
69− margin-bottom: .5em;
70−}
71−
72−blockquote {
73− margin: 1.5rem 0;
74− padding: 1rem 1.5rem;
75− color: var(--fg);
76− opacity: .9;
77− background-color: var(--quote-bg);
78− border-left: 4px solid var(--quote-border);
79− border-top: none;
80− border-bottom: none;
81−}
82−
83−blockquote *:last-child {
84− margin-bottom: 0;
85−}
86−
87−table {
88− width: 100%;
89−}
90−
91−table thead th {
92− padding: .75rem;
93− text-align: left;
94− font-weight: 500;
95− line-height: 1.5;
96− width: auto;
97−}
98−
99−table td {
100− padding: .75rem;
101− border: none;
102−}
103−
104−table thead tr {
105− border: none;
106− border-bottom: 2px var(--table-border-color) solid;
107−}
108−
109−table tbody tr {
110− border-bottom: 1px var(--table-border-line) solid;
111−}
112−
113−table tbody tr:nth-child(2n) {
114− background: unset;
115−}
116−
117−pre code.hljs {
118− display: block;
119− overflow-x: auto;
120− padding: 1em;
121−}
122−
123−code.hljs {
124− padding: 3px 5px;
125−}
126−
127−.colibri {
128− --bg: #3b224c;
129− --fg: #bcbdd0;
130− --heading-fg: #fff;
131−
132− --sidebar-bg: #281733;
133− --sidebar-fg: #c8c9db;
134− --sidebar-non-existent: #505274;
135− --sidebar-active: #a4a0e8;
136− --sidebar-spacer: #2d334f;
137−
138− --scrollbar: var(--sidebar-fg);
139−
140− --icons: #737480;
141− --icons-hover: #b7b9cc;
142−
143− /* --links: #a4a0e8; */
144− --links: #ECCDBA;
145−
146− --inline-code-color: hsl(48.7, 7.8%, 70%);
147−
148− --theme-popup-bg: #161923;
149− --theme-popup-border: #737480;
150− --theme-hover: rgba(0, 0, 0, .2);
151−
152− --quote-bg: #281733;
153− --quote-border: hsl(226, 15%, 22%);
154−
155− --table-border-color: hsl(226, 23%, 76%);
156− --table-header-bg: hsla(226, 23%, 31%, 0);
157− --table-alternate-bg: hsl(226, 23%, 14%);
158− --table-border-line: hsla(201deg, 20%, 92%, 0.2);
159−
160− --searchbar-border-color: #aaa;
161− --searchbar-bg: #aeaec6;
162− --searchbar-fg: #000;
163− --searchbar-shadow-color: #aaa;
164− --searchresults-header-fg: #5f5f71;
165− --searchresults-border-color: #5c5c68;
166− --searchresults-li-bg: #242430;
167− --search-mark-bg: #a2cff5;
168−}
169−
170−.colibri .content .header {
171− color: #fff;
172−}
173−
174−/* highlight.js theme, :where() is used to avoid increasing specificity */
175−
176−:where(.colibri) .hljs {
177− background: #2f1e2e;
178− color: #a39e9b;
179−}
180−
181−:where(.colibri) .hljs-comment,
182−:where(.colibri) .hljs-quote {
183− color: #8d8687;
184−}
185−
186−:where(.colibri) .hljs-link,
187−:where(.colibri) .hljs-meta,
188−:where(.colibri) .hljs-name,
189−:where(.colibri) .hljs-regexp,
190−:where(.colibri) .hljs-selector-class,
191−:where(.colibri) .hljs-selector-id,
192−:where(.colibri) .hljs-tag,
193−:where(.colibri) .hljs-template-variable,
194−:where(.colibri) .hljs-variable {
195− color: #ef6155;
196−}
197−
198−:where(.colibri) .hljs-built_in,
199−:where(.colibri) .hljs-deletion,
200−:where(.colibri) .hljs-literal,
201−:where(.colibri) .hljs-number,
202−:where(.colibri) .hljs-params,
203−:where(.colibri) .hljs-type {
204− color: #f99b15;
205−}
206−
207−:where(.colibri) .hljs-attribute,
208−:where(.colibri) .hljs-section,
209−:where(.colibri) .hljs-title {
210− color: #fec418;
211−}
212−
213−:where(.colibri) .hljs-addition,
214−:where(.colibri) .hljs-bullet,
215−:where(.colibri) .hljs-string,
216−:where(.colibri) .hljs-symbol {
217− color: #48b685;
218−}
219−
220−:where(.colibri) .hljs-keyword,
221−:where(.colibri) .hljs-selector-tag {
222− color: #815ba4;
223−}
224−
225−:where(.colibri) .hljs-emphasis {
226− font-style: italic;
227−}
228−
229−:where(.colibri) .hljs-strong {
230− font-weight: 700;
231−}
book/src/SUMMARY.md+5−8
@@ -1,19 +1,16 @@
1# Summary
1# Summary
2
2
3−[Helix](./title-page.md)
4−
5- [Installation](./install.md)
3- [Installation](./install.md)
6- [Usage](./usage.md)
4- [Usage](./usage.md)
7 - [Keymap](./keymap.md)
5 - [Keymap](./keymap.md)
8 - [Commands](./commands.md)
6 - [Commands](./commands.md)
9− - [Language support](./lang-support.md)
7+ - [Language Support](./lang-support.md)
10- [Migrating from Vim](./from-vim.md)
8- [Migrating from Vim](./from-vim.md)
11- [Configuration](./configuration.md)
9- [Configuration](./configuration.md)
12 - [Themes](./themes.md)
10 - [Themes](./themes.md)
13− - [Key remapping](./remapping.md)
11+ - [Key Remapping](./remapping.md)
12+ - [Hooks](./hooks.md)
14 - [Languages](./languages.md)
13 - [Languages](./languages.md)
15- [Guides](./guides/README.md)
14- [Guides](./guides/README.md)
16− - [Adding languages](./guides/adding_languages.md)
15+ - [Adding Languages](./guides/adding_languages.md)
17− - [Adding textobject queries](./guides/textobject.md)
16+ - [Adding Textobject Queries](./guides/textobject.md)
18− - [Adding indent queries](./guides/indent.md)
19− - [Adding injection queries](./guides/injection.md)
book/src/commands.md+1−1
@@ -1,5 +1,5 @@
1# Commands
1# Commands
2
2
3−Command mode can be activated by pressing `:`. The built-in commands are:
3+Command mode can be activated by pressing `:`, similar to vim. Built-in commands:
4
4
5{{#include ./generated/typable-cmd.md}}
5{{#include ./generated/typable-cmd.md}}
book/src/configuration.md+27−357
@@ -2,375 +2,45 @@
2
2
3To override global configuration parameters, create a `config.toml` file located in your config directory:
3To override global configuration parameters, create a `config.toml` file located in your config directory:
4
4
5−- Linux and Mac: `~/.config/helix/config.toml`
5+* Linux and Mac: `~/.config/helix/config.toml`
6−- Windows: `%AppData%\helix\config.toml`
6+* Windows: `%AppData%\helix\config.toml`
7−
8−> 💡 You can easily open the config file by typing `:config-open` within Helix normal mode.
9−
10−Example config:
11−
12−```toml
13−theme = "onedark"
14−
15−[editor]
16−line-number = "relative"
17−mouse = false
18−
19−[editor.cursor-shape]
20−insert = "bar"
21−normal = "block"
22−select = "underline"
23−
24−[editor.file-picker]
25−hidden = false
26−```
27−
28−You can use a custom configuration file by specifying it with the `-c` or
29−`--config` command line argument, for example `hx -c path/to/custom-config.toml`.
30−Additionally, you can reload the configuration file by sending the USR1
31−signal to the Helix process on Unix operating systems, such as by using the command `pkill -USR1 hx`.
32−
33−Finally, you can have a `config.toml` local to a project by putting it under a `.helix` directory in your repository.
34−Its settings will be merged with the configuration directory `config.toml` and the built-in configuration.
35
7
36## Editor
8## Editor
37
9
38−### `[editor]` Section
10+`[editor]` section of the config.
39
11
40| Key | Description | Default |
12| Key | Description | Default |
41|--|--|---------|
13|--|--|---------|
42−| `scrolloff` | Number of lines of padding around the edge of the screen when scrolling | `5` |
14+| `scrolloff` | Number of lines of padding around the edge of the screen when scrolling. | `3` |
43−| `mouse` | Enable mouse mode | `true` |
15+| `mouse` | Enable mouse mode. | `true` |
44−| `middle-click-paste` | Middle click paste support | `true` |
16+| `middle-click-paste` | Middle click paste support. | `true` |
45−| `scroll-lines` | Number of lines to scroll per scroll wheel step | `3` |
17+| `scroll-lines` | Number of lines to scroll per scroll wheel step. | `3` |
46−| `shell` | Shell to use when running external commands | Unix: `["sh", "-c"]`<br/>Windows: `["cmd", "/C"]` |
18+| `shell` | Shell to use when running external commands. | Unix: `["sh", "-c"]`<br/>Windows: `["cmd", "/C"]` |
47−| `line-number` | Line number display: `absolute` simply shows each line's number, while `relative` shows the distance from the current line. When unfocused or in insert mode, `relative` will still show absolute line numbers | `absolute` |
19+| `line-number` | Line number display (`absolute`, `relative`) | `absolute` |
48−| `cursorline` | Highlight all lines with a cursor | `false` |
20+| `smart-case` | Enable smart case regex searching (case insensitive unless pattern contains upper case characters) | `true` |
49−| `cursorcolumn` | Highlight all columns with a cursor | `false` |
21+| `auto-pairs` | Enable automatic insertion of pairs to parenthese, brackets, etc. | `true` |
50−| `gutters` | Gutters to display: Available are `diagnostics` and `diff` and `line-numbers` and `spacer`, note that `diagnostics` also includes other features like breakpoints, 1-width padding will be inserted if gutters is non-empty | `["diagnostics", "spacer", "line-numbers", "spacer", "diff"]` |
51−| `auto-completion` | Enable automatic pop up of auto-completion | `true` |
22+| `auto-completion` | Enable automatic pop up of auto-completion. | `true` |
52−| `auto-format` | Enable automatic formatting on save | `true` |
53−| `auto-save` | Enable automatic saving on the focus moving away from Helix. Requires [focus event support](https://github.com/helix-editor/helix/wiki/Terminal-Support) from your terminal | `false` |
54−| `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant | `250` |
23+| `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant. | `400` |
55−| `preview-completion-insert` | Whether to apply completion item instantly when selected | `true` |
56| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
24| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
57−| `completion-replace` | Set to `true` to make completions always replace the entire word and not just the part before the cursor | `false` |
58−| `auto-info` | Whether to display info boxes | `true` |
25+| `auto-info` | Whether to display infoboxes | `true` |
59−| `true-color` | Set to `true` to override automatic detection of terminal truecolor support in the event of a false negative | `false` |
26+| `true-color` | Set to `true` to override automatic detection of terminal truecolor support in the event of a false negative. | `false` |
60−| `undercurl` | Set to `true` to override automatic detection of terminal undercurl support in the event of a false negative | `false` |
61−| `rulers` | List of column positions at which to display the rulers. Can be overridden by language specific `rulers` in `languages.toml` file | `[]` |
62−| `bufferline` | Renders a line at the top of the editor displaying open buffers. Can be `always`, `never` or `multiple` (only shown if more than one buffer is in use) | `never` |
63−| `color-modes` | Whether to color the mode indicator with different colors depending on the mode itself | `false` |
64−| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap-at-text-width` is set | `80` |
65−| `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml` | `[]` |
66−| `default-line-ending` | The line ending to use for new documents. Can be `native`, `lf`, `crlf`, `ff`, `cr` or `nel`. `native` uses the platform's native line ending (`crlf` on Windows, otherwise `lf`). | `native` |
67−| `insert-final-newline` | Whether to automatically insert a trailing line-ending on write if missing | `true` |
68−| `popup-border` | Draw border around `popup`, `menu`, `all`, or `none` | `none` |
69−| `indent-heuristic` | How the indentation for a newly inserted line is computed: `simple` just copies the indentation level from the previous line, `tree-sitter` computes the indentation based on the syntax tree and `hybrid` combines both approaches. If the chosen heuristic is not available, a different one will be used as a fallback (the fallback order being `hybrid` -> `tree-sitter` -> `simple`). | `hybrid`
70−
71−### `[editor.statusline]` Section
72−
73−Allows configuring the statusline at the bottom of the editor.
74−
75−The configuration distinguishes between three areas of the status line:
76−
77−`[ ... ... LEFT ... ... | ... ... ... ... CENTER ... ... ... ... | ... ... RIGHT ... ... ]`
78−
79−Statusline elements can be defined as follows:
80−
81−```toml
82−[editor.statusline]
83−left = ["mode", "spinner"]
84−center = ["file-name"]
85−right = ["diagnostics", "selections", "position", "file-encoding", "file-line-ending", "file-type"]
86−separator = "│"
87−mode.normal = "NORMAL"
88−mode.insert = "INSERT"
89−mode.select = "SELECT"
90−```
91−The `[editor.statusline]` key takes the following sub-keys:
92−
93−| Key | Description | Default |
94−| --- | --- | --- |
95−| `left` | A list of elements aligned to the left of the statusline | `["mode", "spinner", "file-name", "read-only-indicator", "file-modification-indicator"]` |
96−| `center` | A list of elements aligned to the middle of the statusline | `[]` |
97−| `right` | A list of elements aligned to the right of the statusline | `["diagnostics", "selections", "register", "position", "file-encoding"]` |
98−| `separator` | The character used to separate elements in the statusline | `"│"` |
99−| `mode.normal` | The text shown in the `mode` element for normal mode | `"NOR"` |
100−| `mode.insert` | The text shown in the `mode` element for insert mode | `"INS"` |
101−| `mode.select` | The text shown in the `mode` element for select mode | `"SEL"` |
102−
103−The following statusline elements can be configured:
104−
105−| Key | Description |
106−| ------ | ----------- |
107−| `mode` | The current editor mode (`mode.normal`/`mode.insert`/`mode.select`) |
108−| `spinner` | A progress spinner indicating LSP activity |
109−| `file-name` | The path/name of the opened file |
110−| `file-base-name` | The basename of the opened file |
111−| `file-modification-indicator` | The indicator to show whether the file is modified (a `[+]` appears when there are unsaved changes) |
112−| `file-encoding` | The encoding of the opened file if it differs from UTF-8 |
113−| `file-line-ending` | The file line endings (CRLF or LF) |
114−| `read-only-indicator` | An indicator that shows `[readonly]` when a file cannot be written |
115−| `total-line-numbers` | The total line numbers of the opened file |
116−| `file-type` | The type of the opened file |
117−| `diagnostics` | The number of warnings and/or errors |
118−| `workspace-diagnostics` | The number of warnings and/or errors on workspace |
119−| `selections` | The number of active selections |
120−| `primary-selection-length` | The number of characters currently in primary selection |
121−| `position` | The cursor position |
122−| `position-percentage` | The cursor position as a percentage of the total number of lines |
123−| `separator` | The string defined in `editor.statusline.separator` (defaults to `"│"`) |
124−| `spacer` | Inserts a space between elements (multiple/contiguous spacers may be specified) |
125−| `version-control` | The current branch name or detached commit hash of the opened workspace |
126−| `register` | The current selected register |
127−
128−### `[editor.lsp]` Section
129−
130−| Key | Description | Default |
131−| --- | ----------- | ------- |
132−| `enable` | Enables LSP integration. Setting to false will completely disable language servers regardless of language settings.| `true` |
133−| `display-messages` | Display LSP progress messages below statusline[^1] | `false` |
134−| `auto-signature-help` | Enable automatic popup of signature help (parameter hints) | `true` |
135−| `display-inlay-hints` | Display inlay hints[^2] | `false` |
136−| `display-signature-help-docs` | Display docs under signature help popup | `true` |
137−| `snippets` | Enables snippet completions. Requires a server restart (`:lsp-restart`) to take effect after `:config-reload`/`:set`. | `true` |
138−| `goto-reference-include-declaration` | Include declaration in the goto references popup. | `true` |
139−
140−[^1]: By default, a progress spinner is shown in the statusline beside the file path.
141−
142−[^2]: You may also have to activate them in the LSP config for them to appear, not just in Helix. Inlay hints in Helix are still being improved on and may be a little bit laggy/janky under some circumstances. Please report any bugs you see so we can fix them!
143−
144−### `[editor.cursor-shape]` Section
145−
146−Defines the shape of cursor in each mode.
147−Valid values for these options are `block`, `bar`, `underline`, or `hidden`.
148−
149−> 💡 Due to limitations of the terminal environment, only the primary cursor can
150−> change shape.
151−
152−| Key | Description | Default |
153−| --- | ----------- | ------- |
154−| `normal` | Cursor shape in [normal mode][normal mode] | `block` |
155−| `insert` | Cursor shape in [insert mode][insert mode] | `block` |
156−| `select` | Cursor shape in [select mode][select mode] | `block` |
157−
158−[normal mode]: ./keymap.md#normal-mode
159−[insert mode]: ./keymap.md#insert-mode
160−[select mode]: ./keymap.md#select--extend-mode
161−
162−### `[editor.file-picker]` Section
163−
164−Set options for file picker and global search. Ignoring a file means it is
165−not visible in the Helix file picker and global search.
166−
167−All git related options are only enabled in a git repository.
168−
169−| Key | Description | Default |
170−|--|--|---------|
171−|`hidden` | Enables ignoring hidden files | `true`
172−|`follow-symlinks` | Follow symlinks instead of ignoring them | `true`
173−|`deduplicate-links` | Ignore symlinks that point at files already shown in the picker | `true`
174−|`parents` | Enables reading ignore files from parent directories | `true`
175−|`ignore` | Enables reading `.ignore` files | `true`
176−|`git-ignore` | Enables reading `.gitignore` files | `true`
177−|`git-global` | Enables reading global `.gitignore`, whose path is specified in git's config: `core.excludesfile` option | `true`
178−|`git-exclude` | Enables reading `.git/info/exclude` files | `true`
179−|`max-depth` | Set with an integer value for maximum depth to recurse | Defaults to `None`.
180−
181−Ignore files can be placed locally as `.ignore` or put in your home directory as `~/.ignore`. They support the usual ignore and negative ignore (unignore) rules used in `.gitignore` files.
182−
183−Additionally, you can use Helix-specific ignore files by creating a local `.helix/ignore` file in the current workspace or a global `ignore` file located in your Helix config directory:
184−- Linux and Mac: `~/.config/helix/ignore`
185−- Windows: `%AppData%\helix\ignore`
186−
187−Example:
188−
189−```ini
190−# unignore in file picker and global search
191−!.github/
192−!.gitignore
193−!.gitattributes
194−```
195−
196−### `[editor.auto-pairs]` Section
197−
198−Enables automatic insertion of pairs to parentheses, brackets, etc. Can be a
199−simple boolean value, or a specific mapping of pairs of single characters.
200−
201−To disable auto-pairs altogether, set `auto-pairs` to `false`:
202−
203−```toml
204−[editor]
205−auto-pairs = false # defaults to `true`
206−```
207−
208−The default pairs are <code>(){}[]''""``</code>, but these can be customized by
209−setting `auto-pairs` to a TOML table:
210−
211−```toml
212−[editor.auto-pairs]
213−'(' = ')'
214−'{' = '}'
215−'[' = ']'
216−'"' = '"'
217−'`' = '`'
218−'<' = '>'
219−```
220−
221−Additionally, this setting can be used in a language config. Unless
222−the editor setting is `false`, this will override the editor config in
223−documents with this language.
224
27
225−Example `languages.toml` that adds <> and removes ''
28+`[editor.filepicker]` section of the config. Sets options for file picker and global search. All but the last key listed in the default file-picker configuration below are IgnoreOptions: whether hidden files and files listed within ignore files are ignored by (not visible in) the helix file picker and global search. There is also one other key, `max-depth` available, which is not defined by default.
226−
227−```toml
228−[[language]]
229−name = "rust"
230−
231−[language.auto-pairs]
232−'(' = ')'
233−'{' = '}'
234−'[' = ']'
235−'"' = '"'
236−'`' = '`'
237−'<' = '>'
238−```
239−
240−### `[editor.search]` Section
241−
242−Search specific options.
243
29
244| Key | Description | Default |
30| Key | Description | Default |
245|--|--|---------|
31|--|--|---------|
246−| `smart-case` | Enable smart case regex searching (case-insensitive unless pattern contains upper case characters) | `true` |
32+|`hidden` | Enables ignoring hidden files. | true
247−| `wrap-around`| Whether the search should wrap after depleting the matches | `true` |
33+|`parents` | Enables reading ignore files from parent directories. | true
248−
34+|`ignore` | Enables reading `.ignore` files. | true
249−### `[editor.whitespace]` Section
35+|`git-ignore` | Enables reading `.gitignore` files. | true
250−
36+|`git-global` | Enables reading global .gitignore, whose path is specified in git's config: `core.excludefile` option. | true
251−Options for rendering whitespace with visible characters. Use `:set whitespace.render all` to temporarily enable visible whitespace.
37+|`git-exclude` | Enables reading `.git/info/exclude` files. | true
252−
38+|`max-depth` | Set with an integer value for maximum depth to recurse. | Defaults to `None`.
253−| Key | Description | Default |
254−|-----|-------------|---------|
255−| `render` | Whether to render whitespace. May either be `"all"` or `"none"`, or a table with sub-keys `space`, `nbsp`, `tab`, and `newline` | `"none"` |
256−| `characters` | Literal characters to use when rendering whitespace. Sub-keys may be any of `tab`, `space`, `nbsp`, `newline` or `tabpad` | See example below |
257−
258−Example
259−
260−```toml
261−[editor.whitespace]
262−render = "all"
263−# or control each character
264−[editor.whitespace.render]
265−space = "all"
266−tab = "all"
267−newline = "none"
268−
269−[editor.whitespace.characters]
270−space = "·"
271−nbsp = "⍽"
272−tab = "→"
273−newline = "⏎"
274−tabpad = "·" # Tabs will look like "→···" (depending on tab width)
275−```
276−
277−### `[editor.indent-guides]` Section
278−
279−Options for rendering vertical indent guides.
280−
281−| Key | Description | Default |
282−| --- | --- | --- |
283−| `render` | Whether to render indent guides | `false` |
284−| `character` | Literal character to use for rendering the indent guide | `│` |
285−| `skip-levels` | Number of indent levels to skip | `0` |
286−
287−Example:
288−
289−```toml
290−[editor.indent-guides]
291−render = true
292−character = "╎" # Some characters that work well: "▏", "┆", "┊", "⸽"
293−skip-levels = 1
294−```
295−
296−### `[editor.gutters]` Section
297−
298−For simplicity, `editor.gutters` accepts an array of gutter types, which will
299−use default settings for all gutter components.
300−
301−```toml
302−[editor]
303−gutters = ["diff", "diagnostics", "line-numbers", "spacer"]
304−```
305−
306−To customize the behavior of gutters, the `[editor.gutters]` section must
307−be used. This section contains top level settings, as well as settings for
308−specific gutter components as subsections.
309−
310−| Key | Description | Default |
311−| --- | --- | --- |
312−| `layout` | A vector of gutters to display | `["diagnostics", "spacer", "line-numbers", "spacer", "diff"]` |
313−
314−Example:
315−
316−```toml
317−[editor.gutters]
318−layout = ["diff", "diagnostics", "line-numbers", "spacer"]
319−```
320−
321−#### `[editor.gutters.line-numbers]` Section
322−
323−Options for the line number gutter
324−
325−| Key | Description | Default |
326−| --- | --- | --- |
327−| `min-width` | The minimum number of characters to use | `3` |
328−
329−Example:
330−
331−```toml
332−[editor.gutters.line-numbers]
333−min-width = 1
334−```
335−
336−#### `[editor.gutters.diagnostics]` Section
337−
338−Currently unused
339−
340−#### `[editor.gutters.diff]` Section
341−
342−Currently unused
343−
344−#### `[editor.gutters.spacer]` Section
345−
346−Currently unused
347
39
348−### `[editor.soft-wrap]` Section
40+## LSP
349−
350−Options for soft wrapping lines that exceed the view width:
351−
352−| Key | Description | Default |
353−| --- | --- | --- |
354−| `enable` | Whether soft wrapping is enabled. | `false` |
355−| `max-wrap` | Maximum free space left at the end of the line. | `20` |
356−| `max-indent-retain` | Maximum indentation to carry over when soft wrapping a line. | `40` |
357−| `wrap-indicator` | Text inserted before soft wrapped lines, highlighted with `ui.virtual.wrap` | `↪ ` |
358−| `wrap-at-text-width` | Soft wrap at `text-width` instead of using the full viewport size. | `false` |
359−
360−Example:
361
41
42+To display all language server messages in the status line add the following to your `config.toml`:
362```toml
43```toml
363−[editor.soft-wrap]
44+[lsp]
364−enable = true
45+display-messages = true
365−max-wrap = 25 # increase value to reduce forced mid-word wrapping
366−max-indent-retain = 0
367−wrap-indicator = "" # set wrap-indicator to "" to hide it
368```
46```
369−
370−### `[editor.smart-tab]` Section
371−
372−
373−| Key | Description | Default |
374−|------------|-------------|---------|
375−| `enable` | If set to true, then when the cursor is in a position with non-whitespace to its left, instead of inserting a tab, it will run `move_parent_node_end`. If there is only whitespace to the left, then it inserts a tab as normal. With the default bindings, to explicitly insert a tab character, press Shift-tab. | `true` |
376−| `supersede-menu` | Normally, when a menu is on screen, such as when auto complete is triggered, the tab key is bound to cycling through the items. This means when menus are on screen, one cannot use the tab key to trigger the `smart-tab` command. If this option is set to true, the `smart-tab` command always takes precedence, which means one cannot use the tab key to cycle through menu items. One of the other bindings must be used instead, such as arrow keys or `C-n`/`C-p`. | `false` |
book/src/from-vim.md+7−7
@@ -1,12 +1,12 @@
1# Migrating from Vim
1# Migrating from Vim
2
2
3−Helix's editing model is strongly inspired from Vim and Kakoune, and a notable
3+Helix's editing model is strongly inspired from vim and kakoune, and a notable
4−difference from Vim (and the most striking similarity to Kakoune) is that Helix
4+difference from vim (and the most striking similarity to kakoune) is that Helix
5−follows the `selection → action` model. This means that whatever you are
5+follows the `selection → action` model. This means that the whatever you are
6−going to act on (a word, a paragraph, a line, etc.) is selected first and the
6+going to act on (a word, a paragraph, a line, etc) is selected first and the
7−action itself (delete, change, yank, etc.) comes second. A cursor is simply a
7+action itself (delete, change, yank, etc) comes second. A cursor is simply a
8single width selection.
8single width selection.
9
9
10−See also Kakoune's [Migrating from Vim](https://github.com/mawww/kakoune/wiki/Migrating-from-Vim) and Helix's [Migrating from Vim](https://github.com/helix-editor/helix/wiki/Migrating-from-Vim).
10+See also Kakoune's [Migrating from Vim](https://github.com/mawww/kakoune/wiki/Migrating-from-Vim).
11
11
12−> TODO: Mention textobjects, surround, registers
12+> TODO: Mention texobjects, surround, registers
book/src/generated/lang-support.md+31−171
@@ -1,193 +1,53 @@
1| Language | Syntax Highlighting | Treesitter Textobjects | Auto Indent | Default LSP |
1| Language | Syntax Highlighting | Treesitter Textobjects | Auto Indent | Default LSP |
2| --- | --- | --- | --- | --- |
2| --- | --- | --- | --- | --- |
3−| agda | ✓ | | | |
4−| astro | ✓ | | | |
5−| awk | ✓ | ✓ | | `awk-language-server` |
6−| bash | ✓ | ✓ | ✓ | `bash-language-server` |
3+| bash | ✓ | | | `bash-language-server` |
7−| bass | ✓ | | | `bass` |
8−| beancount | ✓ | | | |
9−| bibtex | ✓ | | | `texlab` |
10−| bicep | ✓ | | | `bicep-langserver` |
11−| blueprint | ✓ | | | `blueprint-compiler` |
12| c | ✓ | ✓ | ✓ | `clangd` |
4| c | ✓ | ✓ | ✓ | `clangd` |
13−| c-sharp | ✓ | ✓ | | `OmniSharp` |
5+| c-sharp | ✓ | | | |
14−| cabal | | | | `haskell-language-server-wrapper` |
15−| cairo | ✓ | ✓ | ✓ | `cairo-language-server` |
16−| capnp | ✓ | | ✓ | |
17−| clojure | ✓ | | | `clojure-lsp` |
18| cmake | ✓ | ✓ | ✓ | `cmake-language-server` |
6| cmake | ✓ | ✓ | ✓ | `cmake-language-server` |
19| comment | ✓ | | | |
7| comment | ✓ | | | |
20−| common-lisp | ✓ | | ✓ | `cl-lsp` |
21−| cpon | ✓ | | ✓ | |
22| cpp | ✓ | ✓ | ✓ | `clangd` |
8| cpp | ✓ | ✓ | ✓ | `clangd` |
23−| crystal | ✓ | ✓ | | `crystalline` |
9+| css | ✓ | | | |
24−| css | ✓ | | | `vscode-css-language-server` |
25−| cue | ✓ | | | `cuelsp` |
26−| d | ✓ | ✓ | ✓ | `serve-d` |
27| dart | ✓ | | ✓ | `dart` |
10| dart | ✓ | | ✓ | `dart` |
28−| dbml | ✓ | | | |
29−| devicetree | ✓ | | | |
30−| dhall | ✓ | ✓ | | `dhall-lsp-server` |
31−| diff | ✓ | | | |
32| dockerfile | ✓ | | | `docker-langserver` |
11| dockerfile | ✓ | | | `docker-langserver` |
33−| dot | ✓ | | | `dot-language-server` |
34−| dtd | ✓ | | | |
35−| edoc | ✓ | | | |
36−| eex | ✓ | | | |
37−| ejs | ✓ | | | |
38−| elixir | ✓ | ✓ | ✓ | `elixir-ls` |
12+| elixir | ✓ | | | `elixir-ls` |
39−| elm | ✓ | ✓ | | `elm-language-server` |
40−| elvish | ✓ | | | `elvish` |
41−| env | ✓ | | | |
42−| erb | ✓ | | | |
43−| erlang | ✓ | ✓ | | `erlang_ls` |
44−| esdl | ✓ | | | |
45| fish | ✓ | ✓ | ✓ | |
13| fish | ✓ | ✓ | ✓ | |
46−| forth | ✓ | | | `forth-lsp` |
47−| fortran | ✓ | | ✓ | `fortls` |
48−| fsharp | ✓ | | | `fsautocomplete` |
49−| gas | ✓ | ✓ | | |
50−| gdscript | ✓ | ✓ | ✓ | |
51−| gemini | ✓ | | | |
52−| git-attributes | ✓ | | | |
53−| git-commit | ✓ | ✓ | | |
14+| git-commit | ✓ | | | |
54−| git-config | ✓ | | | |
15+| git-diff | ✓ | | | |
55−| git-ignore | ✓ | | | |
56| git-rebase | ✓ | | | |
16| git-rebase | ✓ | | | |
57−| gleam | ✓ | ✓ | | `gleam` |
58−| glsl | ✓ | ✓ | ✓ | |
17+| glsl | ✓ | | ✓ | |
59−| gn | ✓ | | | |
18+| go | ✓ | ✓ | ✓ | `gopls` |
60−| go | ✓ | ✓ | ✓ | `gopls`, `golangci-lint-langserver` |
19+| html | ✓ | | | |
61−| godot-resource | ✓ | | | |
62−| gomod | ✓ | | | `gopls` |
63−| gotmpl | ✓ | | | `gopls` |
64−| gowork | ✓ | | | `gopls` |
65−| graphql | ✓ | | | `graphql-lsp` |
66−| hare | ✓ | | | |
67−| haskell | ✓ | ✓ | | `haskell-language-server-wrapper` |
68−| haskell-persistent | ✓ | | | |
69−| hcl | ✓ | | ✓ | `terraform-ls` |
70−| heex | ✓ | ✓ | | `elixir-ls` |
71−| hosts | ✓ | | | |
72−| html | ✓ | | | `vscode-html-language-server` |
73−| hurl | ✓ | | ✓ | |
74−| idris | | | | `idris2-lsp` |
75−| iex | ✓ | | | |
76−| ini | ✓ | | | |
77−| janet | ✓ | | | |
78−| java | ✓ | ✓ | ✓ | `jdtls` |
20+| java | ✓ | | | |
79−| javascript | ✓ | ✓ | ✓ | `typescript-language-server` |
21+| javascript | ✓ | | ✓ | |
80−| jinja | ✓ | | | |
22+| json | ✓ | | ✓ | |
81−| jsdoc | ✓ | | | |
82−| json | ✓ | | ✓ | `vscode-json-language-server` |
83−| json5 | ✓ | | | |
84−| jsonnet | ✓ | | | `jsonnet-language-server` |
85−| jsx | ✓ | ✓ | ✓ | `typescript-language-server` |
86−| julia | ✓ | ✓ | ✓ | `julia` |
23+| julia | ✓ | | | `julia` |
87−| just | ✓ | ✓ | ✓ | |
88−| kdl | ✓ | ✓ | ✓ | |
89−| kotlin | ✓ | | | `kotlin-language-server` |
90−| latex | ✓ | ✓ | | `texlab` |
24+| latex | ✓ | | | |
91−| lean | ✓ | | | `lean` |
92| ledger | ✓ | | | |
25| ledger | ✓ | | | |
93| llvm | ✓ | ✓ | ✓ | |
26| llvm | ✓ | ✓ | ✓ | |
94| llvm-mir | ✓ | ✓ | ✓ | |
27| llvm-mir | ✓ | ✓ | ✓ | |
95| llvm-mir-yaml | ✓ | | ✓ | |
28| llvm-mir-yaml | ✓ | | ✓ | |
96−| log | ✓ | | | |
29+| lua | ✓ | | ✓ | |
97−| lpf | ✓ | | | |
98−| lua | ✓ | ✓ | ✓ | `lua-language-server` |
99−| make | ✓ | | | |
100−| markdoc | ✓ | | | `markdoc-ls` |
101−| markdown | ✓ | | | `marksman` |
102−| markdown.inline | ✓ | | | |
30+| markdown | ✓ | | | |
103−| matlab | ✓ | ✓ | ✓ | |
104−| mermaid | ✓ | | | |
105−| meson | ✓ | | ✓ | |
106| mint | | | | `mint` |
31| mint | | | | `mint` |
107−| msbuild | ✓ | | ✓ | |
32+| nix | ✓ | | ✓ | `rnix-lsp` |
108−| nasm | ✓ | ✓ | | |
33+| ocaml | ✓ | | ✓ | |
109−| nickel | ✓ | | ✓ | `nls` |
34+| ocaml-interface | ✓ | | | |
110−| nim | ✓ | ✓ | ✓ | `nimlangserver` |
35+| perl | ✓ | ✓ | ✓ | |
111−| nix | ✓ | | | `nil` |
36+| php | ✓ | | ✓ | |
112−| nu | ✓ | | | `nu` |
113−| nunjucks | ✓ | | | |
114−| ocaml | ✓ | | ✓ | `ocamllsp` |
115−| ocaml-interface | ✓ | | | `ocamllsp` |
116−| odin | ✓ | | ✓ | `ols` |
117−| opencl | ✓ | ✓ | ✓ | `clangd` |
118−| openscad | ✓ | | | `openscad-lsp` |
119−| org | ✓ | | | |
120−| pascal | ✓ | ✓ | | `pasls` |
121−| passwd | ✓ | | | |
122−| pem | ✓ | | | |
123−| perl | ✓ | ✓ | ✓ | `perlnavigator` |
124−| php | ✓ | ✓ | ✓ | `intelephense` |
125−| po | ✓ | ✓ | | |
126−| pod | ✓ | | | |
127−| ponylang | ✓ | ✓ | ✓ | |
128−| prisma | ✓ | | | `prisma-language-server` |
129| prolog | | | | `swipl` |
37| prolog | | | | `swipl` |
130−| protobuf | ✓ | | ✓ | `bufls`, `pb` |
38+| protobuf | ✓ | | ✓ | |
131−| prql | ✓ | | | |
132−| purescript | ✓ | ✓ | | `purescript-language-server` |
133| python | ✓ | ✓ | ✓ | `pylsp` |
39| python | ✓ | ✓ | ✓ | `pylsp` |
134−| qml | ✓ | | ✓ | `qmlls` |
135−| r | ✓ | | | `R` |
136−| racket | ✓ | | ✓ | `racket` |
40+| racket | | | | `racket` |
137−| regex | ✓ | | | |
138−| rego | ✓ | | | `regols` |
139−| rescript | ✓ | ✓ | | `rescript-language-server` |
140−| rmarkdown | ✓ | | ✓ | `R` |
141−| robot | ✓ | | | `robotframework_ls` |
142−| ron | ✓ | | ✓ | |
143−| rst | ✓ | | | |
144−| ruby | ✓ | ✓ | ✓ | `solargraph` |
41+| ruby | ✓ | | ✓ | `solargraph` |
145| rust | ✓ | ✓ | ✓ | `rust-analyzer` |
42| rust | ✓ | ✓ | ✓ | `rust-analyzer` |
146−| sage | ✓ | ✓ | | |
147| scala | ✓ | | ✓ | `metals` |
43| scala | ✓ | | ✓ | `metals` |
148−| scheme | ✓ | | ✓ | |
149−| scss | ✓ | | | `vscode-css-language-server` |
150−| slint | ✓ | | ✓ | `slint-lsp` |
151−| smali | ✓ | | ✓ | |
152−| smithy | ✓ | | | `cs` |
153−| sml | ✓ | | | |
154−| solidity | ✓ | | | `solc` |
155−| sql | ✓ | | | |
156−| sshclientconfig | ✓ | | | |
157−| starlark | ✓ | ✓ | | |
158−| strace | ✓ | | | |
159| svelte | ✓ | | ✓ | `svelteserver` |
44| svelte | ✓ | | ✓ | `svelteserver` |
160−| sway | ✓ | ✓ | ✓ | `forc` |
161−| swift | ✓ | | | `sourcekit-lsp` |
162−| t32 | ✓ | | | |
163| tablegen | ✓ | ✓ | ✓ | |
45| tablegen | ✓ | ✓ | ✓ | |
164−| task | ✓ | | | |
165−| templ | ✓ | | | `templ` |
166−| tfvars | ✓ | | ✓ | `terraform-ls` |
167−| todotxt | ✓ | | | |
168−| toml | ✓ | | | `taplo` |
46+| toml | ✓ | | | |
169| tsq | ✓ | | | |
47| tsq | ✓ | | | |
170−| tsx | ✓ | ✓ | ✓ | `typescript-language-server` |
171−| twig | ✓ | | | |
172−| typescript | ✓ | ✓ | ✓ | `typescript-language-server` |
48+| tsx | ✓ | | | `typescript-language-server` |
173−| typst | ✓ | | | `typst-lsp` |
174−| ungrammar | ✓ | | | |
175−| unison | ✓ | | | |
176−| uxntal | ✓ | | | |
177−| v | ✓ | ✓ | ✓ | `v-analyzer` |
178−| vala | ✓ | | | `vala-language-server` |
49+| typescript | ✓ | | ✓ | `typescript-language-server` |
179−| verilog | ✓ | ✓ | | `svlangserver` |
50+| vue | ✓ | | | |
180−| vhdl | ✓ | | | `vhdl_ls` |
51+| wgsl | ✓ | | | |
181−| vhs | ✓ | | | |
52+| yaml | ✓ | | ✓ | |
182−| vue | ✓ | | | `vue-language-server` |
183−| wast | ✓ | | | |
184−| wat | ✓ | | | |
185−| webc | ✓ | | | |
186−| wgsl | ✓ | | | `wgsl_analyzer` |
187−| wit | ✓ | | ✓ | |
188−| wren | ✓ | ✓ | ✓ | |
189−| xit | ✓ | | | |
190−| xml | ✓ | | ✓ | |
191−| yaml | ✓ | | ✓ | `yaml-language-server`, `ansible-language-server` |
192−| yuck | ✓ | | | |
193−| zig | ✓ | ✓ | ✓ | `zls` |
53+| zig | ✓ | | ✓ | `zls` |
book/src/generated/typable-cmd.md+14−55
@@ -1,38 +1,27 @@
1| Name | Description |
1| Name | Description |
2| --- | --- |
2| --- | --- |
3| `:quit`, `:q` | Close the current view. |
3| `:quit`, `:q` | Close the current view. |
4−| `:quit!`, `:q!` | Force close the current view, ignoring unsaved changes. |
4+| `:quit!`, `:q!` | Close the current view forcefully (ignoring unsaved changes). |
5| `:open`, `:o` | Open a file from disk into the current view. |
5| `:open`, `:o` | Open a file from disk into the current view. |
6| `:buffer-close`, `:bc`, `:bclose` | Close the current buffer. |
6| `:buffer-close`, `:bc`, `:bclose` | Close the current buffer. |
7−| `:buffer-close!`, `:bc!`, `:bclose!` | Close the current buffer forcefully, ignoring unsaved changes. |
7+| `:buffer-close!`, `:bc!`, `:bclose!` | Close the current buffer forcefully (ignoring unsaved changes). |
8−| `:buffer-close-others`, `:bco`, `:bcloseother` | Close all buffers but the currently focused one. |
9−| `:buffer-close-others!`, `:bco!`, `:bcloseother!` | Force close all buffers but the currently focused one. |
10−| `:buffer-close-all`, `:bca`, `:bcloseall` | Close all buffers without quitting. |
11−| `:buffer-close-all!`, `:bca!`, `:bcloseall!` | Force close all buffers ignoring unsaved changes without quitting. |
12−| `:buffer-next`, `:bn`, `:bnext` | Goto next buffer. |
13−| `:buffer-previous`, `:bp`, `:bprev` | Goto previous buffer. |
14| `:write`, `:w` | Write changes to disk. Accepts an optional path (:write some/path.txt) |
8| `:write`, `:w` | Write changes to disk. Accepts an optional path (:write some/path.txt) |
15−| `:write!`, `:w!` | Force write changes to disk creating necessary subdirectories. Accepts an optional path (:write! some/path.txt) |
16−| `:write-buffer-close`, `:wbc` | Write changes to disk and closes the buffer. Accepts an optional path (:write-buffer-close some/path.txt) |
17−| `:write-buffer-close!`, `:wbc!` | Force write changes to disk creating necessary subdirectories and closes the buffer. Accepts an optional path (:write-buffer-close! some/path.txt) |
18| `:new`, `:n` | Create a new scratch buffer. |
9| `:new`, `:n` | Create a new scratch buffer. |
19| `:format`, `:fmt` | Format the file using the LSP formatter. |
10| `:format`, `:fmt` | Format the file using the LSP formatter. |
20−| `:indent-style` | Set the indentation style for editing. ('t' for tabs or 1-16 for number of spaces.) |
11+| `:indent-style` | Set the indentation style for editing. ('t' for tabs or 1-8 for number of spaces.) |
21−| `:line-ending` | Set the document's default line ending. Options: crlf, lf. |
12+| `:line-ending` | Set the document's default line ending. Options: crlf, lf, cr, ff, nel. |
22| `:earlier`, `:ear` | Jump back to an earlier point in edit history. Accepts a number of steps or a time span. |
13| `:earlier`, `:ear` | Jump back to an earlier point in edit history. Accepts a number of steps or a time span. |
23| `:later`, `:lat` | Jump to a later point in edit history. Accepts a number of steps or a time span. |
14| `:later`, `:lat` | Jump to a later point in edit history. Accepts a number of steps or a time span. |
24| `:write-quit`, `:wq`, `:x` | Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt) |
15| `:write-quit`, `:wq`, `:x` | Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt) |
25| `:write-quit!`, `:wq!`, `:x!` | Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt) |
16| `:write-quit!`, `:wq!`, `:x!` | Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt) |
26−| `:write-all`, `:wa` | Write changes from all buffers to disk. |
17+| `:write-all`, `:wa` | Write changes from all views to disk. |
27−| `:write-all!`, `:wa!` | Forcefully write changes from all buffers to disk creating necessary subdirectories. |
28−| `:write-quit-all`, `:wqa`, `:xa` | Write changes from all buffers to disk and close all views. |
18+| `:write-quit-all`, `:wqa`, `:xa` | Write changes from all views to disk and close all views. |
29−| `:write-quit-all!`, `:wqa!`, `:xa!` | Write changes from all buffers to disk and close all views forcefully (ignoring unsaved changes). |
19+| `:write-quit-all!`, `:wqa!`, `:xa!` | Write changes from all views to disk and close all views forcefully (ignoring unsaved changes). |
30| `:quit-all`, `:qa` | Close all views. |
20| `:quit-all`, `:qa` | Close all views. |
31−| `:quit-all!`, `:qa!` | Force close all views ignoring unsaved changes. |
21+| `:quit-all!`, `:qa!` | Close all views forcefully (ignoring unsaved changes). |
32| `:cquit`, `:cq` | Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2). |
22| `:cquit`, `:cq` | Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2). |
33−| `:cquit!`, `:cq!` | Force quit with exit code (default 1) ignoring unsaved changes. Accepts an optional integer exit code (:cq! 2). |
23+| `:cquit!`, `:cq!` | Quit with exit code (default 1) forcefully (ignoring unsaved changes). Accepts an optional integer exit code (:cq! 2). |
34−| `:theme` | Change the editor theme (show current theme if no name specified). |
24+| `:theme` | Change the editor theme. |
35−| `:yank-join` | Yank joined selections. A separator can be provided as first argument. Default value is newline. |
36| `:clipboard-yank` | Yank main selection into system clipboard. |
25| `:clipboard-yank` | Yank main selection into system clipboard. |
37| `:clipboard-yank-join` | Yank joined selections into system clipboard. A separator can be provided as first argument. Default value is newline. |
26| `:clipboard-yank-join` | Yank joined selections into system clipboard. A separator can be provided as first argument. Default value is newline. |
38| `:primary-clipboard-yank` | Yank main selection into system primary clipboard. |
27| `:primary-clipboard-yank` | Yank main selection into system primary clipboard. |
@@ -46,43 +35,13 @@
46| `:show-clipboard-provider` | Show clipboard provider name in status bar. |
35| `:show-clipboard-provider` | Show clipboard provider name in status bar. |
47| `:change-current-directory`, `:cd` | Change the current working directory. |
36| `:change-current-directory`, `:cd` | Change the current working directory. |
48| `:show-directory`, `:pwd` | Show the current working directory. |
37| `:show-directory`, `:pwd` | Show the current working directory. |
49−| `:encoding` | Set encoding. Based on `https://encoding.spec.whatwg.org`. |
38+| `:encoding` | Set encoding based on `https://encoding.spec.whatwg.org` |
50−| `:character-info`, `:char` | Get info about the character under the primary cursor. |
51−| `:reload`, `:rl` | Discard changes and reload from the source file. |
39+| `:reload` | Discard changes and reload from the source file. |
52−| `:reload-all`, `:rla` | Discard changes and reload all documents from the source files. |
53−| `:update`, `:u` | Write changes only if the file has been modified. |
54−| `:lsp-workspace-command` | Open workspace command picker |
55−| `:lsp-restart` | Restarts the language servers used by the current doc |
56−| `:lsp-stop` | Stops the language servers that are used by the current doc |
57| `:tree-sitter-scopes` | Display tree sitter scopes, primarily for theming and development. |
40| `:tree-sitter-scopes` | Display tree sitter scopes, primarily for theming and development. |
58−| `:tree-sitter-highlight-name` | Display name of tree-sitter highlight scope under the cursor. |
59−| `:debug-start`, `:dbg` | Start a debug session from a given template with given parameters. |
60−| `:debug-remote`, `:dbg-tcp` | Connect to a debug adapter by TCP address and start a debugging session from a given template with given parameters. |
61−| `:debug-eval` | Evaluate expression in current debug context. |
62| `:vsplit`, `:vs` | Open the file in a vertical split. |
41| `:vsplit`, `:vs` | Open the file in a vertical split. |
63−| `:vsplit-new`, `:vnew` | Open a scratch buffer in a vertical split. |
64| `:hsplit`, `:hs`, `:sp` | Open the file in a horizontal split. |
42| `:hsplit`, `:hs`, `:sp` | Open the file in a horizontal split. |
65−| `:hsplit-new`, `:hnew` | Open a scratch buffer in a horizontal split. |
66| `:tutor` | Open the tutorial. |
43| `:tutor` | Open the tutorial. |
67−| `:goto`, `:g` | Goto line number. |
44+| `:goto`, `:g` | Go to line number. |
68−| `:set-language`, `:lang` | Set the language of current buffer (show current language if no value specified). |
69−| `:set-option`, `:set` | Set a config option at runtime.<br>For example to disable smart case search, use `:set search.smart-case false`. |
45+| `:set-option`, `:set` | Set a config option at runtime |
70−| `:toggle-option`, `:toggle` | Toggle a boolean config option at runtime.<br>For example to toggle smart case search, use `:toggle search.smart-case`. |
71−| `:get-option`, `:get` | Get the current value of a config option. |
72| `:sort` | Sort ranges in selection. |
46| `:sort` | Sort ranges in selection. |
73| `:rsort` | Sort ranges in selection in reverse order. |
47| `:rsort` | Sort ranges in selection in reverse order. |
74−| `:reflow` | Hard-wrap the current selection of lines to a given width. |
75−| `:tree-sitter-subtree`, `:ts-subtree` | Display tree sitter subtree under cursor, primarily for debugging queries. |
76−| `:config-reload` | Refresh user config. |
77−| `:config-open` | Open the user config.toml file. |
78−| `:config-open-workspace` | Open the workspace config.toml file. |
79−| `:log-open` | Open the helix log file. |
80−| `:insert-output` | Run shell command, inserting output before each selection. |
81−| `:append-output` | Run shell command, appending output after each selection. |
82−| `:pipe` | Pipe each selection to the shell command. |
83−| `:pipe-to` | Pipe each selection to the shell command, ignoring output. |
84−| `:run-shell-command`, `:sh` | Run a shell command |
85−| `:reset-diff-change`, `:diffget`, `:diffg` | Reset the diff change at the cursor position. |
86−| `:clear-register` | Clear given register. If no argument is provided, clear all registers. |
87−| `:redraw` | Clear and re-render the whole UI |
88−| `:move` | Move the current buffer and its corresponding file to a different path |
book/src/guides/README.md+1−1
@@ -1,4 +1,4 @@
1# Guides
1# Guides
2
2
3This section contains guides for adding new language server configurations,
3This section contains guides for adding new language server configurations,
4−tree-sitter grammars, textobject queries, and other similar items.
4+tree-sitter grammers, textobject queries, etc.
book/src/guides/adding_languages.md+62−46
@@ -1,55 +1,71 @@
1−# Adding new languages to Helix
1+# Adding languages
2
2
3−In order to add a new language to Helix, you will need to follow the steps
3+## Submodules
4−below.
5
4
6−## Language configuration
5+To add a new language, you should first add a tree-sitter submodule. To do this,
6+you can run the command
7+```sh
8+git submodule add -f <repository> helix-syntax/languages/tree-sitter-<name>
9+```
10+For example, to add tree-sitter-ocaml you would run
11+```sh
12+git submodule add -f https://github.com/tree-sitter/tree-sitter-ocaml helix-syntax/languages/tree-sitter-ocaml
13+```
14+Make sure the submodule is shallow by doing
15+```sh
16+git config -f .gitmodules submodule.helix-syntax/languages/tree-sitter-<name>.shallow true
17+```
7
18
8−1. Add a new `[[language]]` entry in the `languages.toml` file and provide the
19+or you can manually add `shallow = true` to `.gitmodules`.
9− necessary configuration for the new language. For more information on
10− language configuration, refer to the
11− [language configuration section](../languages.md) of the documentation.
12− A new language server can be added by extending the `[language-server]` table in the same file.
13−2. If you are adding a new language or updating an existing language server
14− configuration, run the command `cargo xtask docgen` to update the
15− [Language Support](../lang-support.md) documentation.
16
20
17−> 💡 If you are adding a new Language Server configuration, make sure to update
21+## languages.toml
18−> the
19−> [Language Server Wiki](https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers)
20−> with the installation instructions.
21
22
22−## Grammar configuration
23+Next, you need to add the language to the [`languages.toml`][languages.toml] found in the root of
24+the repository; this `languages.toml` file is included at compilation time, and
25+is distinct from the `language.toml` file in the user's [configuration
26+directory](../configuration.md).
23
27
24−1. If a tree-sitter grammar is available for the new language, add a new
28+These are the available keys and descriptions for the file.
25− `[[grammar]]` entry to the `languages.toml` file.
29+
26−2. If you are testing the grammar locally, you can use the `source.path` key
30+| Key | Description |
27− with an absolute path to the grammar. However, before submitting a pull
31+| ---- | ----------- |
28− request, make sure to switch to using `source.git`.
32+| name | The name of the language |
33+| scope | A string like `source.js` that identifies the language. Currently, we strive to match the scope names used by popular TextMate grammars and by the Linguist library. Usually `source.<name>` or `text.<name>` in case of markup languages |
34+| injection-regex | regex pattern that will be tested against a language name in order to determine whether this language should be used for a potential [language injection][treesitter-language-injection] site. |
35+| file-types | The filetypes of the language, for example `["yml", "yaml"]` |
36+| shebangs | The interpreters from the shebang line, for example `["sh", "bash"]` |
37+| roots | A set of marker files to look for when trying to find the workspace root. For example `Cargo.lock`, `yarn.lock` |
38+| auto-format | Whether to autoformat this language when saving |
39+| diagnostic-severity | Minimal severity of diagnostic for it to be displayed. (Allowed values: `Error`, `Warning`, `Info`, `Hint`) |
40+| comment-token | The token to use as a comment-token |
41+| indent | The indent to use. Has sub keys `tab-width` and `unit` |
42+| config | Language server configuration |
29
43
30## Queries
44## Queries
31
45
32−1. In order to provide syntax highlighting and indentation for the new language,
46+For a language to have syntax-highlighting and indentation among
33− you will need to add queries.
47+other things, you have to add queries. Add a directory for your
34−2. Create a new directory for the language with the path
35− `runtime/queries/<name>/`.
48+language with the path `runtime/queries/<name>/`. The tree-sitter
36−3. Refer to the
37− [tree-sitter website](https://tree-sitter.github.io/tree-sitter/syntax-highlighting#queries)
49+[website](https://tree-sitter.github.io/tree-sitter/syntax-highlighting#queries)
38− for more information on writing queries.
50+gives more info on how to write queries.
39−4. A list of highlight captures can be found [on the themes page](https://docs.helix-editor.com/themes.html#scopes).
51+
40−
41−> 💡 In Helix, the first matching query takes precedence when evaluating
52+> NOTE: When evaluating queries, the first matching query takes
42−> queries, which is different from other editors such as Neovim where the last
53+precedence, which is different from other editors like neovim where
43−> matching query supersedes the ones before it. See
54+the last matching query supercedes the ones before it. See
44−> [this issue](https://github.com/helix-editor/helix/pull/1170#issuecomment-997294090)
45−> for an example.
55+[this issue][neovim-query-precedence] for an example.
46−
56+
47−## Common issues
57+## Common Issues
48−
58+
49−- If you encounter errors when running Helix after switching branches, you may
59+- If you get errors when building after switching branches, you may have to remove or update tree-sitter submodules. You can update submodules by running
50− need to update the tree-sitter grammars. Run the command `hx --grammar fetch`
60+ ```sh
51− to fetch the grammars and `hx --grammar build` to build any out-of-date
61+ git submodule sync; git submodule update --init
52− grammars.
62+ ```
63+- Make sure to not use the `--remote` flag. To remove submodules look inside the `.gitmodules` and remove directories that are not present inside of it.
64+
53−- If a parser is causing a segfault, or you want to remove it, make sure to
65+- If a parser is segfaulting or you want to remove the parser, make sure to remove the submodule *and* the compiled parser in `runtime/grammar/<name>.so`
54− remove the compiled parser located at `runtime/grammars/<name>.so`.
66+
55−- If you are attempting to add queries and Helix is unable to locate them, ensure that the environment variable `HELIX_RUNTIME` is set to the location of the `runtime` folder you're developing in.
67+- The indents query is `indents.toml`, *not* `indents.scm`. See [this](https://github.com/helix-editor/helix/issues/114) issue for more information.
68+
69+[treesitter-language-injection]: https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection
70+[languages.toml]: https://github.com/helix-editor/helix/blob/master/languages.toml
71+[neovim-query-precedence]: https://github.com/helix-editor/helix/pull/1170#issuecomment-997294090
book/src/guides/indent.mddeleted−369
@@ -1,369 +0,0 @@
1−# Adding indent queries
2−
3−Helix uses tree-sitter to correctly indent new lines. This requires a tree-
4−sitter grammar and an `indent.scm` query file placed in `runtime/queries/
5−{language}/indents.scm`. The indentation for a line is calculated by traversing
6−the syntax tree from the lowest node at the beginning of the new line (see
7−[Indent queries](#indent-queries)). Each of these nodes contributes to the total
8−indent when it is captured by the query (in what way depends on the name of
9−the capture.
10−
11−Note that it matters where these added indents begin. For example,
12−multiple indent level increases that start on the same line only increase
13−the total indent level by 1. See [Capture types](#capture-types).
14−
15−By default, Helix uses the `hybrid` indentation heuristic. This means that
16−indent queries are not used to compute the expected absolute indentation of a
17−line but rather the expected difference in indentation between the new and an
18−already existing line. This difference is then added to the actual indentation
19−of the already existing line. Since this makes errors in the indent queries
20−harder to find, it is recommended to disable it when testing via
21−`:set indent-heuristic tree-sitter`. The rest of this guide assumes that
22−the `tree-sitter` heuristic is used.
23−
24−## Indent queries
25−
26−When Helix is inserting a new line through `o`, `O`, or `<ret>`, to determine
27−the indent level for the new line, the query in `indents.scm` is run on the
28−document. The starting position of the query is the end of the line above where
29−a new line will be inserted.
30−
31−For `o`, the inserted line is the line below the cursor, so that starting
32−position of the query is the end of the current line.
33−
34−```rust
35−fn need_hero(some_hero: Hero, life: Life) -> {
36− matches!(some_hero, Hero { // ←─────────────────╮
37− strong: true,//←╮ ↑ ↑ │
38− fast: true, // │ │ ╰── query start │
39− sure: true, // │ ╰───── cursor ├─ traversal
40− soon: true, // ╰──────── new line inserted │ start node
41− }) && // │
42−// ↑ │
43−// ╰───────────────────────────────────────────────╯
44− some_hero > life
45−}
46−```
47−
48−For `O`, the newly inserted line is the *current* line, so the starting position
49−of the query is the end of the line above the cursor.
50−
51−```rust
52−fn need_hero(some_hero: Hero, life: Life) -> { // ←─╮
53− matches!(some_hero, Hero { // ←╮ ↑ │
54− strong: true,// ↑ ╭───╯ │ │
55− fast: true, // │ │ query start ─╯ │
56− sure: true, // ╰───┼ cursor ├─ traversal
57− soon: true, // ╰ new line inserted │ start node
58− }) && // │
59− some_hero > life // │
60−} // ←──────────────────────────────────────────────╯
61−```
62−
63−From this starting node, the syntax tree is traversed up until the root node.
64−Each indent capture is collected along the way, and then combined according to
65−their [capture types](#capture-types) and [scopes](#scopes) to a final indent
66−level for the line.
67−
68−### Capture types
69−
70−- `@indent` (default scope `tail`):
71− Increase the indent level by 1. Multiple occurrences in the same line *do not*
72− stack. If there is at least one `@indent` and one `@outdent` capture on the
73− same line, the indent level isn't changed at all.
74−- `@outdent` (default scope `all`):
75− Decrease the indent level by 1. The same rules as for `@indent` apply.
76−- `@indent.always` (default scope `tail`):
77− Increase the indent level by 1. Multiple occurrences on the same line *do*
78− stack. The final indent level is `@indent.always` – `@outdent.always`. If
79− an `@indent` and an `@indent.always` are on the same line, the `@indent` is
80− ignored.
81−- `@outdent.always` (default scope `all`):
82− Decrease the indent level by 1. The same rules as for `@indent.always` apply.
83−- `@align` (default scope `all`):
84− Align everything inside this node to some anchor. The anchor is given
85− by the start of the node captured by `@anchor` in the same pattern.
86− Every pattern with an `@align` should contain exactly one `@anchor`.
87− Indent (and outdent) for nodes below (in terms of their starting line)
88− the `@align` node is added to the indentation required for alignment.
89−- `@extend`:
90− Extend the range of this node to the end of the line and to lines that are
91− indented more than the line that this node starts on. This is useful for
92− languages like Python, where for the purpose of indentation some nodes (like
93− functions or classes) should also contain indented lines that follow them.
94−- `@extend.prevent-once`:
95− Prevents the first extension of an ancestor of this node. For example, in Python
96− a return expression always ends the block that it is in. Note that this only
97− stops the extension of the next `@extend` capture. If multiple ancestors are
98− captured, only the extension of the innermost one is prevented. All other
99− ancestors are unaffected (regardless of whether the innermost ancestor would
100− actually have been extended).
101−
102−#### `@indent` / `@outdent`
103−
104−Consider this example:
105−
106−```rust
107−fn shout(things: Vec<Thing>) {
108− // ↑
109− // ├───────────────────────╮ indent level
110− // @indent ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄
111− // │
112− let it_all = |out| { things.filter(|thing| { // │ 1
113− // ↑ ↑ │
114− // ├───────────────────────┼─────┼┄┄┄┄┄┄┄┄┄┄┄┄┄┄
115− // @indent @indent │
116− // │ 2
117− thing.can_do_with(out) // │
118− })}; // ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄
119− //↑↑↑ │ 1
120−} //╰┼┴──────────────────────────────────────────────┴┄┄┄┄┄┄┄┄┄┄┄┄┄┄
121−// 3x @outdent
122−```
123−
124−```scm
125−((block) @indent)
126−["}" ")"] @outdent
127−```
128−
129−Note how on the second line, we have two blocks begin on the same line. In this
130−case, since both captures occur on the same line, they are combined and only
131−result in a net increase of 1. Also note that the closing `}`s are part of the
132−`@indent` captures, but the 3 `@outdent`s also combine into 1 and result in that
133−line losing one indent level.
134−
135−#### `@extend` / `@extend.prevent-once`
136−
137−For an example of where `@extend` can be useful, consider Python, which is
138−whitespace-sensitive.
139−
140−```scm
141−]
142− (parenthesized_expression)
143− (function_definition)
144− (class_definition)
145−] @indent
146−
147−```
148−
149−```python
150−class Hero:
151− def __init__(self, strong, fast, sure, soon):# ←─╮
152− self.is_strong = strong # │
153− self.is_fast = fast # ╭─── query start │
154− self.is_sure = sure # │ ╭─ cursor │
155− self.is_soon = soon # │ │ │
156− # ↑ ↑ │ │ │
157− # │ ╰──────╯ │ │
158− # ╰─────────────────────╯ │
159− # ├─ traversal
160− def need_hero(self, life): # │ start node
161− return ( # │
162− self.is_strong # │
163− and self.is_fast # │
164− and self.is_sure # │
165− and self.is_soon # │
166− and self > life # │
167− ) # ←─────────────────────────────────────────╯
168−```
169−
170−Without braces to catch the scope of the function, the smallest descendant of
171−the cursor on a line feed ends up being the entire inside of the class. Because
172−of this, it will miss the entire function node and its indent capture, leading
173−to an indent level one too small.
174−
175−To address this case, `@extend` tells helix to "extend" the captured node's span
176−to the line feed and every consecutive line that has a greater indent level than
177−the line of the node.
178−
179−```scm
180−(parenthesized_expression) @indent
181−
182−]
183− (function_definition)
184− (class_definition)
185−] @indent @extend
186−
187−```
188−
189−```python
190−class Hero:
191− def __init__(self, strong, fast, sure, soon):# ←─╮
192− self.is_strong = strong # │
193− self.is_fast = fast # ╭─── query start ├─ traversal
194− self.is_sure = sure # │ ╭─ cursor │ start node
195− self.is_soon = soon # │ │ ←───────────────╯
196− # ↑ ↑ │ │
197− # │ ╰──────╯ │
198− # ╰─────────────────────╯
199− def need_hero(self, life):
200− return (
201− self.is_strong
202− and self.is_fast
203− and self.is_sure
204− and self.is_soon
205− and self > life
206− )
207−```
208−
209−Furthermore, there are some cases where extending to everything with a greater
210−indent level may not be desirable. Consider the `need_hero` function above. If
211−our cursor is on the last line of the returned expression.
212−
213−```python
214−class Hero:
215− def __init__(self, strong, fast, sure, soon):
216− self.is_strong = strong
217− self.is_fast = fast
218− self.is_sure = sure
219− self.is_soon = soon
220−
221− def need_hero(self, life):
222− return (
223− self.is_strong
224− and self.is_fast
225− and self.is_sure
226− and self.is_soon
227− and self > life
228− ) # ←─── cursor
229− #←────────── where cursor should go on new line
230−```
231−
232−In Python, the are a few tokens that will always end a scope, such as a return
233−statement. Since the scope ends, so should the indent level. But because the
234−function span is extended to every line with a greater indent level, a new line
235−would just continue on the same level. And an `@outdent` would not help us here
236−either, since it would cause everything in the parentheses to become outdented
237−as well.
238−
239−To help, we need to signal an end to the extension. We can do this with
240−`@extend.prevent-once`.
241−
242−```scm
243−(parenthesized_expression) @indent
244−
245−]
246− (function_definition)
247− (class_definition)
248−] @indent @extend
249−
250−(return_statement) @extend.prevent-once
251−```
252−
253−#### `@indent.always` / `@outdent.always`
254−
255−As mentioned before, normally if there is more than one `@indent` or `@outdent`
256−capture on the same line, they are combined.
257−
258−Sometimes, there are cases when you may want to ensure that every indent capture
259−is additive, regardless of how many occur on the same line. Consider this
260−example in YAML.
261−
262−```yaml
263− - foo: bar
264−# ↑ ↑
265−# │ ╰─────────────── start of map
266−# ╰───────────────── start of list element
267− baz: quux # ←─── cursor
268− # ←───────────── where the cursor should go on a new line
269− garply: waldo
270− - quux:
271− bar: baz
272− xyzzy: thud
273− fred: plugh
274−```
275−
276−In YAML, you often have lists of maps. In these cases, the syntax is such that
277−the list element and the map both start on the same line. But we really do want
278−to start an indentation for each of these so that subsequent keys in the map
279−hang over the list and align properly. This is where `@indent.always` helps.
280−
281−```scm
282−((block_sequence_item) @item @indent.always @extend
283− (#not-one-line? @item))
284−
285−((block_mapping_pair
286− key: (_) @key
287− value: (_) @val
288− (#not-same-line? @key @val)
289− ) @indent.always @extend
290−)
291−```
292−
293−## Predicates
294−
295−In some cases, an S-expression cannot express exactly what pattern should be matched.
296−For that, tree-sitter allows for predicates to appear anywhere within a pattern,
297−similar to how `#set!` declarations work:
298−
299−```scm
300−(some_kind
301− (child_kind) @indent
302− (#predicate? arg1 arg2 ...)
303−)
304−```
305−
306−The number of arguments depends on the predicate that's used.
307−Each argument is either a capture (`@name`) or a string (`"some string"`).
308−The following predicates are supported by tree-sitter:
309−
310−- `#eq?`/`#not-eq?`:
311−The first argument (a capture) must/must not be equal to the second argument
312−(a capture or a string).
313−
314−- `#match?`/`#not-match?`:
315−The first argument (a capture) must/must not match the regex given in the
316−second argument (a string).
317−
318−Additionally, we support some custom predicates for indent queries:
319−
320−- `#not-kind-eq?`:
321−The kind of the first argument (a capture) must not be equal to the second
322−argument (a string).
323−
324−- `#same-line?`/`#not-same-line?`:
325−The captures given by the 2 arguments must/must not start on the same line.
326−
327−- `#one-line?`/`#not-one-line?`:
328−The captures given by the fist argument must/must span a total of one line.
329−
330−### Scopes
331−
332−Added indents don't always apply to the whole node. For example, in most
333−cases when a node should be indented, we actually only want everything
334−except for its first line to be indented. For this, there are several
335−scopes (more scopes may be added in the future if required):
336−
337−- `tail`:
338−This scope applies to everything except for the first line of the
339−captured node.
340−- `all`:
341−This scope applies to the whole captured node. This is only different from
342−`tail` when the captured node is the first node on its line.
343−
344−For example, imagine we have the following function
345−
346−```rust
347−fn aha() { // ←─────────────────────────────────────╮
348− let take = "on me"; // ←──────────────╮ scope: │
349− let take = "me on"; // ├─ "tail" ├─ (block) @indent
350− let ill = be_gone_days(1 || 2); // │ │
351−} // ←───────────────────────────────────┴──────────┴─ "}" @outdent
352− // scope: "all"
353−```
354−
355−We can write the following query with the `#set!` declaration:
356−
357− ```scm
358− ((block) @indent
359− (#set! "scope" "tail"))
360− ("}" @outdent
361− (#set! "scope" "all"))
362− ```
363−
364−As we can see, the "tail" scope covers the node, except for the first line.
365−Everything up to and including the closing brace gets an indent level of 1.
366−Then, on the closing brace, we encounter an outdent with a scope of "all", which
367−means the first line is included, and the indent level is cancelled out on this
368−line. (Note these scopes are the defaults for `@indent` and `@outdent`—they are
369−written explicitly for demonstration.)
book/src/guides/injection.mddeleted−57
@@ -1,57 +0,0 @@
1−# Adding Injection Queries
2−
3−Writing language injection queries allows one to highlight a specific node as a different language.
4−In addition to the [standard][upstream-docs] language injection options used by tree-sitter, there
5−are a few Helix specific extensions that allow for more control.
6−
7−And example of a simple query that would highlight all strings as bash in Nix:
8−```scm
9−((string_expression (string_fragment) @injection.content)
10− (#set! injection.language "bash"))
11−```
12−
13−## Capture Types
14−
15−- `@injection.language` (standard):
16−The captured node may contain the language name used to highlight the node captured by
17−`@injection.content`.
18−
19−- `@injection.content` (standard):
20−Marks the content to be highlighted as the language captured with `@injection.language` _et al_.
21−
22−- `@injection.filename` (extension):
23−The captured node may contain a filename with a file-extension known to Helix,
24−highlighting `@injection.content` as that language. This uses the language extensions defined in
25−both the default languages.toml distributed with Helix, as well as user defined languages.
26−
27−- `@injection.shebang` (extension):
28−The captured node may contain a shebang used to choose a language to highlight as. This also uses
29−the shebangs defined in the default and user `languages.toml`.
30−
31−## Settings
32−
33−- `injection.combined` (standard):
34−Indicates that all the matching nodes in the tree should have their content parsed as one
35−nested document.
36−
37−- `injection.language` (standard):
38−Forces the captured content to be highlighted as the given language
39−
40−- `injection.include-children` (standard):
41−Indicates that the content node’s entire text should be re-parsed, including the text of its child
42−nodes. By default, child nodes’ text will be excluded from the injected document.
43−
44−- `injection.include-unnamed-children` (extension):
45−Same as `injection.include-children` but only for unnamed child nodes.
46−
47−## Predicates
48−
49−- `#eq?` (standard):
50−The first argument (a capture) must be equal to the second argument
51−(a capture or a string).
52−
53−- `#match?` (standard):
54−The first argument (a capture) must match the regex given in the
55−second argument (a string).
56−
57−[upstream-docs]: http://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection
book/src/guides/textobject.md+5−22
@@ -1,14 +1,14 @@
1−# Adding textobject queries
1+# Adding Textobject Queries
2
2
3−Helix supports textobjects that are language specific, such as functions, classes, etc.
3+Textobjects that are language specific ([like functions, classes, etc][textobjects])
4−These textobjects require an accompanying tree-sitter grammar and a `textobjects.scm` query file
4+require an accompanying tree-sitter grammar and a `textobjects.scm` query file
5to work properly. Tree-sitter allows us to query the source code syntax tree
5to work properly. Tree-sitter allows us to query the source code syntax tree
6and capture specific parts of it. The queries are written in a lisp dialect.
6and capture specific parts of it. The queries are written in a lisp dialect.
7More information on how to write queries can be found in the [official tree-sitter
7More information on how to write queries can be found in the [official tree-sitter
8documentation][tree-sitter-queries].
8documentation][tree-sitter-queries].
9
9
10Query files should be placed in `runtime/queries/{language}/textobjects.scm`
10Query files should be placed in `runtime/queries/{language}/textobjects.scm`
11−when contributing to Helix. Note that to test the query files locally you should put
11+when contributing. Note that to test the query files locally you should put
12them under your local runtime directory (`~/.config/helix/runtime` on Linux
12them under your local runtime directory (`~/.config/helix/runtime` on Linux
13for example).
13for example).
14
14
@@ -20,28 +20,11 @@ The following [captures][tree-sitter-captures] are recognized:
20| `function.around` |
20| `function.around` |
21| `class.inside` |
21| `class.inside` |
22| `class.around` |
22| `class.around` |
23−| `test.inside` |
24−| `test.around` |
25| `parameter.inside` |
23| `parameter.inside` |
26−| `comment.inside` |
27−| `comment.around` |
28
24
29[Example query files][textobject-examples] can be found in the helix GitHub repository.
25[Example query files][textobject-examples] can be found in the helix GitHub repository.
30
26
31−## Queries for textobject based navigation
27+[textobjects]: ../usage.md#textobjects
32−
33−Tree-sitter based navigation in Helix is done using captures in the
34−following order:
35−
36−- `object.movement`
37−- `object.around`
38−- `object.inside`
39−
40−For example if a `function.around` capture has been already defined for a language
41−in its `textobjects.scm` file, function navigation should also work automatically.
42−`function.movement` should be defined only if the node captured by `function.around`
43−doesn't make sense in a navigation context.
44−
45[tree-sitter-queries]: https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax
28[tree-sitter-queries]: https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax
46[tree-sitter-captures]: https://tree-sitter.github.io/tree-sitter/using-parsers#capturing-nodes
29[tree-sitter-captures]: https://tree-sitter.github.io/tree-sitter/using-parsers#capturing-nodes
47[textobject-examples]: https://github.com/search?q=repo%3Ahelix-editor%2Fhelix+filename%3Atextobjects.scm&type=Code&ref=advsearch&l=&l=
30[textobject-examples]: https://github.com/search?q=repo%3Ahelix-editor%2Fhelix+filename%3Atextobjects.scm&type=Code&ref=advsearch&l=&l=
book/src/hooks.mdnew file+1
@@ -0,0 +1 @@
1+# Hooks
book/src/install.md+25−294
@@ -1,320 +1,51 @@
1−# Installing Helix
1+# Installation
2
2
3−<!--toc:start-->
4−- [Pre-built binaries](#pre-built-binaries)
5−- [Linux, macOS, Windows and OpenBSD packaging status](#linux-macos-windows-and-openbsd-packaging-status)
6−- [Linux](#linux)
7− - [Ubuntu](#ubuntu)
8− - [Fedora/RHEL](#fedorarhel)
9− - [Arch Linux extra](#arch-linux-extra)
10− - [NixOS](#nixos)
11− - [Flatpak](#flatpak)
12− - [Snap](#snap)
13− - [AppImage](#appimage)
14−- [macOS](#macos)
15− - [Homebrew Core](#homebrew-core)
16− - [MacPorts](#macports)
17−- [Windows](#windows)
18− - [Winget](#winget)
19− - [Scoop](#scoop)
20− - [Chocolatey](#chocolatey)
21− - [MSYS2](#msys2)
22−- [Building from source](#building-from-source)
23− - [Configuring Helix's runtime files](#configuring-helixs-runtime-files)
24− - [Linux and macOS](#linux-and-macos)
25− - [Windows](#windows)
26− - [Multiple runtime directories](#multiple-runtime-directories)
27− - [Validating the installation](#validating-the-installation)
28− - [Configure the desktop shortcut](#configure-the-desktop-shortcut)
29−<!--toc:end-->
30−
31−To install Helix, follow the instructions specific to your operating system.
32−Note that:
33−
34−- To get the latest nightly version of Helix, you need to
35− [build from source](#building-from-source).
36−
37−- To take full advantage of Helix, install the language servers for your
38− preferred programming languages. See the
39− [wiki](https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers)
40− for instructions.
41−
42−## Pre-built binaries
43−
44−Download pre-built binaries from the
45−[GitHub Releases page](https://github.com/helix-editor/helix/releases). Add the binary to your system's `$PATH` to use it from the command
3+We provide pre-built binaries on the [GitHub Releases page](https://github.com/helix-editor/helix/releases).
46−line.
47−
48−## Linux, macOS, Windows and OpenBSD packaging status
49
4
50[![Packaging status](https://repology.org/badge/vertical-allrepos/helix.svg)](https://repology.org/project/helix/versions)
5[![Packaging status](https://repology.org/badge/vertical-allrepos/helix.svg)](https://repology.org/project/helix/versions)
51
6
52−## Linux
7+## OSX
53−
54−The following third party repositories are available:
55−
56−### Ubuntu
57−
58−Add the `PPA` for Helix:
59−
60−```sh
61−sudo add-apt-repository ppa:maveonair/helix-editor
62−sudo apt update
63−sudo apt install helix
64−```
65−
66−### Fedora/RHEL
67−
68−```sh
69−sudo dnf install helix
70−```
71−
72−### Arch Linux extra
73−
74−Releases are available in the `extra` repository:
75−
76−```sh
77−sudo pacman -S helix
78−```
79−Additionally, a [helix-git](https://aur.archlinux.org/packages/helix-git/) package is available
80−in the AUR, which builds the master branch.
81−
82−### NixOS
83−
84−Helix is available in [nixpkgs](https://github.com/nixos/nixpkgs) through the `helix` attribute,
85−the unstable channel usually carries the latest release.
86
8
87−Helix is also available as a [flake](https://nixos.wiki/wiki/Flakes) in the project
9+A Homebrew tap is available:
88−root. Use `nix develop` to spin up a reproducible development shell. Outputs are
89−cached for each push to master using [Cachix](https://www.cachix.org/). The
90−flake is configured to automatically make use of this cache assuming the user
91−accepts the new settings on first use.
92
10
93−If you are using a version of Nix without flakes enabled,
94−[install Cachix CLI](https://docs.cachix.org/installation) and use
95−`cachix use helix` to configure Nix to use cached outputs when possible.
96−
97−### Flatpak
98−
99−Helix is available on [Flathub](https://flathub.org/en-GB/apps/com.helix_editor.Helix):
100−
101−```sh
102−flatpak install flathub com.helix_editor.Helix
103−flatpak run com.helix_editor.Helix
104−```
105−
106−### Snap
107−
108−Helix is available on [Snapcraft](https://snapcraft.io/helix) and can be installed with:
109−
110−```sh
111−snap install --classic helix
112−```
113−
114−This will install Helix as both `/snap/bin/helix` and `/snap/bin/hx`, so make sure `/snap/bin` is in your `PATH`.
115−
116−### AppImage
117−
118−Install Helix using the Linux [AppImage](https://appimage.org/) format.
119−Download the official Helix AppImage from the [latest releases](https://github.com/helix-editor/helix/releases/latest) page.
120−
121−```sh
122−chmod +x helix-*.AppImage # change permission for executable mode
123−./helix-*.AppImage # run helix
124```
11```
125−
12+brew tap helix-editor/helix
126−## macOS
127−
128−### Homebrew Core
129−
130−```sh
131brew install helix
13brew install helix
132```
14```
133
15
134−### MacPorts
16+## Linux
135−
136−```sh
137−port install helix
138−```
139−
140−## Windows
141−
142−Install on Windows using [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/), [Scoop](https://scoop.sh/), [Chocolatey](https://chocolatey.org/)
143−or [MSYS2](https://msys2.org/).
144−
145−### Winget
146−Windows Package Manager winget command-line tool is by default available on Windows 11 and modern versions of Windows 10 as a part of the App Installer.
147−You can get [App Installer from the Microsoft Store](https://www.microsoft.com/p/app-installer/9nblggh4nns1#activetab=pivot:overviewtab). If it's already installed, make sure it is updated with the latest version.
148−
149−```sh
150−winget install Helix.Helix
151−```
152−
153−### Scoop
154−
155−```sh
156−scoop install helix
157−```
158−
159−### Chocolatey
160−
161−```sh
162−choco install helix
163−```
164−
165−### MSYS2
166−
167−For 64-bit Windows 8.1 or above:
168−
169−```sh
170−pacman -S mingw-w64-ucrt-x86_64-helix
171−```
172−
173−## Building from source
174−
175−Requirements:
176−
177−Clone the Helix GitHub repository into a directory of your choice. The
178−examples in this documentation assume installation into either `~/src/` on
179−Linux and macOS, or `%userprofile%\src\` on Windows.
180−
181−- The [Rust toolchain](https://www.rust-lang.org/tools/install)
182−- The [Git version control system](https://git-scm.com/)
183−- A C++14 compatible compiler to build the tree-sitter grammars, for example GCC or Clang
184−
185−If you are using the `musl-libc` standard library instead of `glibc` the following environment variable must be set during the build to ensure tree-sitter grammars can be loaded correctly:
186−
187−```sh
188−RUSTFLAGS="-C target-feature=-crt-static"
189−```
190−
191−1. Clone the repository:
192−
193− ```sh
194− git clone https://github.com/helix-editor/helix
195− cd helix
196− ```
197−
198−2. Compile from source:
199
17
200− ```sh
18+### NixOS
201− cargo install --path helix-term --locked
202− ```
203
19
204− This command will create the `hx` executable and construct the tree-sitter
20+A [flake](https://nixos.wiki/wiki/Flakes) containing the package is available in
205− grammars in the local `runtime` folder.
21+the project root. The flake can also be used to spin up a reproducible development
22+shell for working on Helix.
206
23
207−> 💡 Tree-sitter grammars can be fetched and compiled if not pre-packaged. Fetch
24+### Arch Linux
208−> grammars with `hx --grammar fetch` and compile them with
209−> `hx --grammar build`. This will install them in
210−> the `runtime` directory within the user's helix config directory (more
211−> [details below](#multiple-runtime-directories)).
212
25
213−### Configuring Helix's runtime files
26+Releases are available in the `community` repository.
214
27
215−#### Linux and macOS
28+A [helix-git](https://aur.archlinux.org/packages/helix-git/) package is also available on the AUR, which builds the master branch.
216
29
217−The **runtime** directory is one below the Helix source, so either set a
30+### Fedora Linux
218−`HELIX_RUNTIME` environment variable to point to that directory and add it to
219−your `~/.bashrc` or equivalent:
220
31
221−```sh
32+You can install the COPR package for Helix via
222−HELIX_RUNTIME=~/src/helix/runtime
223−```
224
33
225−Or, create a symbolic link:
226−
227−```sh
228−ln -Ts $PWD/runtime ~/.config/helix/runtime
229```
34```
230−
35+sudo dnf copr enable varlad/helix
231−If the above command fails to create a symbolic link because the file exists either move `~/.config/helix/runtime` to a new location or delete it, then run the symlink command above again.
36+sudo dnf install helix
232−
233−#### Windows
234−
235−Either set the `HELIX_RUNTIME` environment variable to point to the runtime files using the Windows setting (search for
236−`Edit environment variables for your account`) or use the `setx` command in
237−Cmd:
238−
239−```sh
240−setx HELIX_RUNTIME "%userprofile%\source\repos\helix\runtime"
241```
37```
242
38
243−> 💡 `%userprofile%` resolves to your user directory like
39+## Build from source
244−> `C:\Users\Your-Name\` for example.
245−
246−Or, create a symlink in `%appdata%\helix\` that links to the source code directory:
247−
248−| Method | Command |
249−| ---------- | -------------------------------------------------------------------------------------- |
250−| PowerShell | `New-Item -ItemType Junction -Target "runtime" -Path "$Env:AppData\helix\runtime"` |
251−| Cmd | `cd %appdata%\helix` <br/> `mklink /D runtime "%userprofile%\src\helix\runtime"` |
252−
253−> 💡 On Windows, creating a symbolic link may require running PowerShell or
254−> Cmd as an administrator.
255−
256−#### Multiple runtime directories
257−
258−When Helix finds multiple runtime directories it will search through them for files in the
259−following order:
260−
261−1. `runtime/` sibling directory to `$CARGO_MANIFEST_DIR` directory (this is intended for
262− developing and testing helix only).
263−2. `runtime/` subdirectory of OS-dependent helix user config directory.
264−3. `$HELIX_RUNTIME`
265−4. Distribution-specific fallback directory (set at compile time—not run time—
266− with the `HELIX_DEFAULT_RUNTIME` environment variable)
267−5. `runtime/` subdirectory of path to Helix executable.
268−
269−This order also sets the priority for selecting which file will be used if multiple runtime
270−directories have files with the same name.
271
40
272−#### Note to packagers
273−
274−If you are making a package of Helix for end users, to provide a good out of
275−the box experience, you should set the `HELIX_DEFAULT_RUNTIME` environment
276−variable at build time (before invoking `cargo build`) to a directory which
277−will store the final runtime files after installation. For example, say you want
278−to package the runtime into `/usr/lib/helix/runtime`. The rough steps a build
279−script could follow are:
280−
281−1. `export HELIX_DEFAULT_RUNTIME=/usr/lib/helix/runtime`
282−1. `cargo build --profile opt --locked --path helix-term`
283−1. `cp -r runtime $BUILD_DIR/usr/lib/helix/`
284−1. `cp target/opt/hx $BUILD_DIR/usr/bin/hx`
285−
286−This way the resulting `hx` binary will always look for its runtime directory in
287−`/usr/lib/helix/runtime` if the user has no custom runtime in `~/.config/helix`
288−or `HELIX_RUNTIME`.
289−
290−### Validating the installation
291−
292−To make sure everything is set up as expected you should run the Helix health
293−check:
294−
295−```sh
296−hx --health
297```
41```
298−
299−For more information on the health check results refer to
300−[Health check](https://github.com/helix-editor/helix/wiki/Healthcheck).
42+git clone --recurse-submodules --shallow-submodules -j8 https://github.com/helix-editor/helix
301−
43+cd helix
302−### Configure the desktop shortcut
44+cargo install --path helix-term
303−
304−If your desktop environment supports the
305−[XDG desktop menu](https://specifications.freedesktop.org/menu-spec/menu-spec-latest.html)
306−you can configure Helix to show up in the application menu by copying the
307−provided `.desktop` and icon files to their correct folders:
308−
309−```sh
310−cp contrib/Helix.desktop ~/.local/share/applications
311−cp contrib/helix.png ~/.icons # or ~/.local/share/icons
312```
45```
313
46
314−To use another terminal than the system default, you can modify the `.desktop`
47+This will install the `hx` binary to `$HOME/.cargo/bin`.
315−file. For example, to use `kitty`:
316
48
317−```sh
49+Helix also needs it's runtime files so make sure to copy/symlink the `runtime/` directory into the
318−sed -i "s|Exec=hx %F|Exec=kitty hx %F|g" ~/.local/share/applications/Helix.desktop
50+config directory (for example `~/.config/helix/runtime` on Linux/macOS). This location can be overriden
319−sed -i "s|Terminal=true|Terminal=false|g" ~/.local/share/applications/Helix.desktop
51+via the `HELIX_RUNTIME` environment variable.
320−```
book/src/keymap.md+199−319
@@ -1,63 +1,48 @@
1# Keymap
1# Keymap
2
2
3−- [Normal mode](#normal-mode)
4− - [Movement](#movement)
5− - [Changes](#changes)
6− - [Shell](#shell)
7− - [Selection manipulation](#selection-manipulation)
8− - [Search](#search)
9− - [Minor modes](#minor-modes)
10− - [View mode](#view-mode)
11− - [Goto mode](#goto-mode)
12− - [Match mode](#match-mode)
13− - [Window mode](#window-mode)
14− - [Space mode](#space-mode)
15− - [Popup](#popup)
16− - [Unimpaired](#unimpaired)
17−- [Insert mode](#insert-mode)
18−- [Select / extend mode](#select--extend-mode)
19−- [Picker](#picker)
20−- [Prompt](#prompt)
21−
22−> 💡 Mappings marked (**LSP**) require an active language server for the file.
3+- Mappings marked (**LSP**) require an active language server for the file.
23−
24−> 💡 Mappings marked (**TS**) require a tree-sitter grammar for the file type.
4+- Mappings marked (**TS**) require a tree-sitter grammar for the filetype.
25
5
26## Normal mode
6## Normal mode
27
7
28−Normal mode is the default mode when you launch helix. You can return to it from other modes by pressing the `Escape` key.
29−
30### Movement
8### Movement
31
9
32−> NOTE: Unlike Vim, `f`, `F`, `t` and `T` are not confined to the current line.
10+> NOTE: Unlike vim, `f`, `F`, `t` and `T` are not confined to the current line.
33−
11+
34−| Key | Description | Command |
12+| Key | Description | Command |
35−| ----- | ----------- | ------- |
13+| ----- | ----------- | ------- |
36−| `h`, `Left` | Move left | `move_char_left` |
14+| `h`/`Left` | Move left | `move_char_left` |
37−| `j`, `Down` | Move down | `move_visual_line_down` |
15+| `j`/`Down` | Move down | `move_line_down` |
38−| `k`, `Up` | Move up | `move_visual_line_up` |
16+| `k`/`Up` | Move up | `move_line_up` |
39−| `l`, `Right` | Move right | `move_char_right` |
17+| `l`/`Right` | Move right | `move_char_right` |
40−| `w` | Move next word start | `move_next_word_start` |
18+| `w` | Move next word start | `move_next_word_start` |
41−| `b` | Move previous word start | `move_prev_word_start` |
19+| `b` | Move previous word start | `move_prev_word_start` |
42−| `e` | Move next word end | `move_next_word_end` |
20+| `e` | Move next word end | `move_next_word_end` |
43−| `W` | Move next WORD start | `move_next_long_word_start` |
21+| `W` | Move next WORD start | `move_next_long_word_start` |
44−| `B` | Move previous WORD start | `move_prev_long_word_start` |
22+| `B` | Move previous WORD start | `move_prev_long_word_start` |
45−| `E` | Move next WORD end | `move_next_long_word_end` |
23+| `E` | Move next WORD end | `move_next_long_word_end` |
46−| `t` | Find 'till next char | `find_till_char` |
24+| `t` | Find 'till next char | `find_till_char` |
47−| `f` | Find next char | `find_next_char` |
25+| `f` | Find next char | `find_next_char` |
48−| `T` | Find 'till previous char | `till_prev_char` |
26+| `T` | Find 'till previous char | `till_prev_char` |
49−| `F` | Find previous char | `find_prev_char` |
27+| `F` | Find previous char | `find_prev_char` |
50−| `G` | Go to line number `<n>` | `goto_line` |
51−| `Alt-.` | Repeat last motion (`f`, `t` or `m`) | `repeat_last_motion` |
28+| `Alt-.` | Repeat last motion (`f`, `t` or `m`) | `repeat_last_motion` |
52−| `Home` | Move to the start of the line | `goto_line_start` |
29+| `Home` | Move to the start of the line | `goto_line_start` |
53−| `End` | Move to the end of the line | `goto_line_end` |
30+| `End` | Move to the end of the line | `goto_line_end` |
54−| `Ctrl-b`, `PageUp` | Move page up | `page_up` |
31+| `PageUp` | Move page up | `page_up` |
55−| `Ctrl-f`, `PageDown` | Move page down | `page_down` |
32+| `PageDown` | Move page down | `page_down` |
56−| `Ctrl-u` | Move half page up | `half_page_up` |
33+| `Ctrl-u` | Move half page up | `half_page_up` |
57−| `Ctrl-d` | Move half page down | `half_page_down` |
34+| `Ctrl-d` | Move half page down | `half_page_down` |
58−| `Ctrl-i` | Jump forward on the jumplist | `jump_forward` |
35+| `Ctrl-i` | Jump forward on the jumplist | `jump_forward` |
59−| `Ctrl-o` | Jump backward on the jumplist | `jump_backward` |
36+| `Ctrl-o` | Jump backward on the jumplist | `jump_backward` |
60−| `Ctrl-s` | Save the current selection to the jumplist | `save_selection` |
37+| `Ctrl-s` | Save the current selection to the jumplist | `save_selection` |
38+| `v` | Enter [select (extend) mode](#select--extend-mode) | `select_mode` |
39+| `g` | Enter [goto mode](#goto-mode) | N/A |
40+| `m` | Enter [match mode](#match-mode) | N/A |
41+| `:` | Enter command mode | `command_mode` |
42+| `z` | Enter [view mode](#view-mode) | N/A |
43+| `Z` | Enter sticky [view mode](#view-mode) | N/A |
44+| `Ctrl-w` | Enter [window mode](#window-mode) | N/A |
45+| `Space` | Enter [space mode](#space-mode) | N/A |
61
46
62### Changes
47### Changes
63
48
@@ -70,11 +55,11 @@ Normal mode is the default mode when you launch helix. You can return to it from
70| `` Alt-` `` | Set the selected text to upper case | `switch_to_uppercase` |
55| `` Alt-` `` | Set the selected text to upper case | `switch_to_uppercase` |
71| `i` | Insert before selection | `insert_mode` |
56| `i` | Insert before selection | `insert_mode` |
72| `a` | Insert after selection (append) | `append_mode` |
57| `a` | Insert after selection (append) | `append_mode` |
73−| `I` | Insert at the start of the line | `insert_at_line_start` |
58+| `I` | Insert at the start of the line | `prepend_to_line` |
74−| `A` | Insert at the end of the line | `insert_at_line_end` |
59+| `A` | Insert at the end of the line | `append_to_line` |
75| `o` | Open new line below selection | `open_below` |
60| `o` | Open new line below selection | `open_below` |
76| `O` | Open new line above selection | `open_above` |
61| `O` | Open new line above selection | `open_above` |
77−| `.` | Repeat last insert | N/A |
62+| `.` | Repeat last change | N/A |
78| `u` | Undo change | `undo` |
63| `u` | Undo change | `undo` |
79| `U` | Redo change | `redo` |
64| `U` | Redo change | `redo` |
80| `Alt-u` | Move backward in history | `earlier` |
65| `Alt-u` | Move backward in history | `earlier` |
@@ -97,54 +82,45 @@ Normal mode is the default mode when you launch helix. You can return to it from
97
82
98#### Shell
83#### Shell
99
84
100−| Key | Description | Command |
85+| Key | Description | Command |
101−| ------ | ----------- | ------- |
86+| ------ | ----------- | ------- |
102−| <code>&#124;</code> | Pipe each selection through shell command, replacing with output | `shell_pipe` |
87+| <code>&#124;</code> | Pipe each selection through shell command, replacing with output | `shell_pipe` |
103−| <code>Alt-&#124;</code> | Pipe each selection into shell command, ignoring output | `shell_pipe_to` |
88+| <code>Alt-&#124;</code> | Pipe each selection into shell command, ignoring output | `shell_pipe_to` |
104−| `!` | Run shell command, inserting output before each selection | `shell_insert_output` |
89+| `!` | Run shell command, inserting output before each selection | `shell_insert_output` |
105−| `Alt-!` | Run shell command, appending output after each selection | `shell_append_output` |
90+| `Alt-!` | Run shell command, appending output after each selection | `shell_append_output` |
106−| `$` | Pipe each selection into shell command, keep selections where command returned 0 | `shell_keep_pipe` |
107
91
108
92
109### Selection manipulation
93### Selection manipulation
110
94
111−| Key | Description | Command |
95+| Key | Description | Command |
112−| ----- | ----------- | ------- |
96+| ----- | ----------- | ------- |
113−| `s` | Select all regex matches inside selections | `select_regex` |
97+| `s` | Select all regex matches inside selections | `select_regex` |
114−| `S` | Split selection into sub selections on regex matches | `split_selection` |
98+| `S` | Split selection into subselections on regex matches | `split_selection` |
115−| `Alt-s` | Split selection on newlines | `split_selection_on_newline` |
99+| `Alt-s` | Split selection on newlines | `split_selection_on_newline` |
116−| `Alt-minus` | Merge selections | `merge_selections` |
117−| `Alt-_` | Merge consecutive selections | `merge_consecutive_selections` |
118−| `&` | Align selection in columns | `align_selections` |
100+| `&` | Align selection in columns | `align_selections` |
119−| `_` | Trim whitespace from the selection | `trim_selections` |
101+| `_` | Trim whitespace from the selection | `trim_selections` |
120−| `;` | Collapse selection onto a single cursor | `collapse_selection` |
102+| `;` | Collapse selection onto a single cursor | `collapse_selection` |
121−| `Alt-;` | Flip selection cursor and anchor | `flip_selections` |
103+| `Alt-;` | Flip selection cursor and anchor | `flip_selections` |
122−| `Alt-:` | Ensures the selection is in forward direction | `ensure_selections_forward` |
123−| `,` | Keep only the primary selection | `keep_primary_selection` |
104+| `,` | Keep only the primary selection | `keep_primary_selection` |
124−| `Alt-,` | Remove the primary selection | `remove_primary_selection` |
105+| `Alt-,` | Remove the primary selection | `remove_primary_selection` |
125−| `C` | Copy selection onto the next line (Add cursor below) | `copy_selection_on_next_line` |
106+| `C` | Copy selection onto the next line (Add cursor below) | `copy_selection_on_next_line` |
126−| `Alt-C` | Copy selection onto the previous line (Add cursor above) | `copy_selection_on_prev_line` |
107+| `Alt-C` | Copy selection onto the previous line (Add cursor above) | `copy_selection_on_prev_line` |
127−| `(` | Rotate main selection backward | `rotate_selections_backward` |
108+| `(` | Rotate main selection backward | `rotate_selections_backward` |
128−| `)` | Rotate main selection forward | `rotate_selections_forward` |
109+| `)` | Rotate main selection forward | `rotate_selections_forward` |
129−| `Alt-(` | Rotate selection contents backward | `rotate_selection_contents_backward` |
110+| `Alt-(` | Rotate selection contents backward | `rotate_selection_contents_backward` |
130−| `Alt-)` | Rotate selection contents forward | `rotate_selection_contents_forward` |
111+| `Alt-)` | Rotate selection contents forward | `rotate_selection_contents_forward` |
131−| `%` | Select entire file | `select_all` |
112+| `%` | Select entire file | `select_all` |
132−| `x` | Select current line, if already selected, extend to next line | `extend_line_below` |
113+| `x` | Select current line, if already selected, extend to next line | `extend_line` |
133−| `X` | Extend selection to line bounds (line-wise selection) | `extend_to_line_bounds` |
114+| `X` | Extend selection to line bounds (line-wise selection) | `extend_to_line_bounds` |
134−| `Alt-x` | Shrink selection to line bounds (line-wise selection) | `shrink_to_line_bounds` |
115+| | Expand selection to parent syntax node TODO: pick a key (**TS**) | `expand_selection` |
135−| `J` | Join lines inside selection | `join_selections` |
116+| `J` | Join lines inside selection | `join_selections` |
136−| `Alt-J` | Join lines inside selection and select the inserted space | `join_selections_space` |
137−| `K` | Keep selections matching the regex | `keep_selections` |
117+| `K` | Keep selections matching the regex | `keep_selections` |
138−| `Alt-K` | Remove selections matching the regex | `remove_selections` |
118+| `Alt-K` | Remove selections matching the regex | `remove_selections` |
119+| `$` | Pipe each selection into shell command, keep selections where command returned 0 | `shell_keep_pipe` |
139−| `Ctrl-c` | Comment/uncomment the selections | `toggle_comments` |
120+| `Ctrl-c` | Comment/uncomment the selections | `toggle_comments` |
140−| `Alt-o`, `Alt-up` | Expand selection to parent syntax node (**TS**) | `expand_selection` |
141−| `Alt-i`, `Alt-down` | Shrink syntax tree object selection (**TS**) | `shrink_selection` |
142−| `Alt-p`, `Alt-left` | Select previous sibling node in syntax tree (**TS**) | `select_prev_sibling` |
143−| `Alt-n`, `Alt-right` | Select next sibling node in syntax tree (**TS**) | `select_next_sibling` |
144
121
145### Search
122### Search
146
123
147−Search commands all operate on the `/` register by default. To use a different register, use `"<char>`.
148
124
149| Key | Description | Command |
125| Key | Description | Command |
150| ----- | ----------- | ------- |
126| ----- | ----------- | ------- |
@@ -158,47 +134,29 @@ Search commands all operate on the `/` register by default. To use a different r
158
134
159These sub-modes are accessible from normal mode and typically switch back to normal mode after a command.
135These sub-modes are accessible from normal mode and typically switch back to normal mode after a command.
160
136
161−| Key | Description | Command |
162−| ----- | ----------- | ------- |
163−| `v` | Enter [select (extend) mode](#select--extend-mode) | `select_mode` |
164−| `g` | Enter [goto mode](#goto-mode) | N/A |
165−| `m` | Enter [match mode](#match-mode) | N/A |
166−| `:` | Enter command mode | `command_mode` |
167−| `z` | Enter [view mode](#view-mode) | N/A |
168−| `Z` | Enter sticky [view mode](#view-mode) | N/A |
169−| `Ctrl-w` | Enter [window mode](#window-mode) | N/A |
170−| `Space` | Enter [space mode](#space-mode) | N/A |
171−
172−These modes (except command mode) can be configured by
173−[remapping keys](https://docs.helix-editor.com/remapping.html#minor-modes).
174−
175#### View mode
137#### View mode
176
138
177−Accessed by typing `z` in [normal mode](#normal-mode).
178−
179View mode is intended for scrolling and manipulating the view without changing
139View mode is intended for scrolling and manipulating the view without changing
180−the selection. The "sticky" variant of this mode (accessed by typing `Z` in
140+the selection. The "sticky" variant of this mode is persistent; use the Escape
181−normal mode) is persistent and can be exited using the escape key. This is
141+key to return to normal mode after usage (useful when you're simply looking
182−useful when you're simply looking over text and not actively editing it.
142+over text and not actively editing it).
183−
143+
184−
144+
185−| Key | Description | Command |
145+| Key | Description | Command |
186−| ----- | ----------- | ------- |
146+| ----- | ----------- | ------- |
187−| `z`, `c` | Vertically center the line | `align_view_center` |
147+| `z` , `c` | Vertically center the line | `align_view_center` |
188−| `t` | Align the line to the top of the screen | `align_view_top` |
148+| `t` | Align the line to the top of the screen | `align_view_top` |
189−| `b` | Align the line to the bottom of the screen | `align_view_bottom` |
149+| `b` | Align the line to the bottom of the screen | `align_view_bottom` |
190−| `m` | Align the line to the middle of the screen (horizontally) | `align_view_middle` |
150+| `m` | Align the line to the middle of the screen (horizontally) | `align_view_middle` |
191−| `j`, `down` | Scroll the view downwards | `scroll_down` |
151+| `j` , `down` | Scroll the view downwards | `scroll_down` |
192−| `k`, `up` | Scroll the view upwards | `scroll_up` |
152+| `k` , `up` | Scroll the view upwards | `scroll_up` |
193−| `Ctrl-f`, `PageDown` | Move page down | `page_down` |
153+| `f` | Move page down | `page_down` |
194−| `Ctrl-b`, `PageUp` | Move page up | `page_up` |
154+| `b` | Move page up | `page_up` |
195−| `Ctrl-d` | Move half page down | `half_page_down` |
155+| `d` | Move half page down | `half_page_down` |
196−| `Ctrl-u` | Move half page up | `half_page_up` |
156+| `u` | Move half page up | `half_page_up` |
197
157
198#### Goto mode
158#### Goto mode
199
159
200−Accessed by typing `g` in [normal mode](#normal-mode).
201−
202Jumps to various locations.
160Jumps to various locations.
203
161
204| Key | Description | Command |
162| Key | Description | Command |
@@ -221,15 +179,12 @@ Jumps to various locations.
221| `n` | Go to next buffer | `goto_next_buffer` |
179| `n` | Go to next buffer | `goto_next_buffer` |
222| `p` | Go to previous buffer | `goto_previous_buffer` |
180| `p` | Go to previous buffer | `goto_previous_buffer` |
223| `.` | Go to last modification in current file | `goto_last_modification` |
181| `.` | Go to last modification in current file | `goto_last_modification` |
224−| `j` | Move down textual (instead of visual) line | `move_line_down` |
225−| `k` | Move up textual (instead of visual) line | `move_line_up` |
226
182
227#### Match mode
183#### Match mode
228
184
229−Accessed by typing `m` in [normal mode](#normal-mode).
185+Enter this mode using `m` from normal mode. See the relavant section
230−
231−See the relevant section in [Usage](./usage.md) for an explanation about
186+in [Usage](./usage.md) for an explanation about [surround](./usage.md#surround)
232−[surround](./usage.md#surround) and [textobject](./usage.md#navigating-using-tree-sitter-textobjects) usage.
187+and [textobject](./usage.md#textobject) usage.
233
188
234| Key | Description | Command |
189| Key | Description | Command |
235| ----- | ----------- | ------- |
190| ----- | ----------- | ------- |
@@ -244,60 +199,46 @@ TODO: Mappings for selecting syntax nodes (a superset of `[`).
244
199
245#### Window mode
200#### Window mode
246
201
247−Accessed by typing `Ctrl-w` in [normal mode](#normal-mode).
248−
249−This layer is similar to Vim keybindings as Kakoune does not support windows.
202+This layer is similar to vim keybindings as kakoune does not support window.
250−
203+
251−| Key | Description | Command |
204+| Key | Description | Command |
252−| ----- | ------------- | ------- |
205+| ----- | ------------- | ------- |
253−| `w`, `Ctrl-w` | Switch to next window | `rotate_view` |
206+| `w`, `Ctrl-w` | Switch to next window | `rotate_view` |
254−| `v`, `Ctrl-v` | Vertical right split | `vsplit` |
207+| `v`, `Ctrl-v` | Vertical right split | `vsplit` |
255−| `s`, `Ctrl-s` | Horizontal bottom split | `hsplit` |
208+| `s`, `Ctrl-s` | Horizontal bottom split | `hsplit` |
209+| `h`, `Ctrl-h`, `left` | Move to left split | `jump_view_left` |
256−| `f` | Go to files in the selection in horizontal splits | `goto_file` |
210+| `f` | Go to files in the selection in horizontal splits | `goto_file` |
257−| `F` | Go to files in the selection in vertical splits | `goto_file` |
211+| `F` | Go to files in the selection in vertical splits | `goto_file` |
258−| `h`, `Ctrl-h`, `Left` | Move to left split | `jump_view_left` |
259−| `j`, `Ctrl-j`, `Down` | Move to split below | `jump_view_down` |
212+| `j`, `Ctrl-j`, `down` | Move to split below | `jump_view_down` |
260−| `k`, `Ctrl-k`, `Up` | Move to split above | `jump_view_up` |
213+| `k`, `Ctrl-k`, `up` | Move to split above | `jump_view_up` |
261−| `l`, `Ctrl-l`, `Right` | Move to right split | `jump_view_right` |
214+| `l`, `Ctrl-l`, `right` | Move to right split | `jump_view_right` |
262−| `q`, `Ctrl-q` | Close current window | `wclose` |
215+| `q`, `Ctrl-q` | Close current window | `wclose` |
263−| `o`, `Ctrl-o` | Only keep the current window, closing all the others | `wonly` |
216+| `o`, `Ctrl-o` | Only keep the current window, closing all the others | `wonly` |
264−| `H` | Swap window to the left | `swap_view_left` |
265−| `J` | Swap window downwards | `swap_view_down` |
266−| `K` | Swap window upwards | `swap_view_up` |
267−| `L` | Swap window to the right | `swap_view_right` |
268
217
269#### Space mode
218#### Space mode
270
219
271−Accessed by typing `Space` in [normal mode](#normal-mode).
272−
273This layer is a kludge of mappings, mostly pickers.
220This layer is a kludge of mappings, mostly pickers.
274
221
222+
275−| Key | Description | Command |
223+| Key | Description | Command |
276−| ----- | ----------- | ------- |
224+| ----- | ----------- | ------- |
277−| `f` | Open file picker | `file_picker` |
225+| `f` | Open file picker | `file_picker` |
278−| `F` | Open file picker at current working directory | `file_picker_in_current_directory` |
279−| `b` | Open buffer picker | `buffer_picker` |
226+| `b` | Open buffer picker | `buffer_picker` |
280−| `j` | Open jumplist picker | `jumplist_picker` |
281−| `g` | Debug (experimental) | N/A |
282−| `k` | Show documentation for item under cursor in a [popup](#popup) (**LSP**) | `hover` |
227+| `k` | Show documentation for item under cursor in a [popup](#popup) (**LSP**) | `hover` |
283−| `s` | Open document symbol picker (**LSP**) | `symbol_picker` |
228+| `s` | Open document symbol picker (**LSP**) | `symbol_picker` |
284−| `S` | Open workspace symbol picker (**LSP**) | `workspace_symbol_picker` |
229+| `S` | Open workspace symbol picker (**LSP**) | `workspace_symbol_picker` |
285−| `d` | Open document diagnostics picker (**LSP**) | `diagnostics_picker` |
286−| `D` | Open workspace diagnostics picker (**LSP**) | `workspace_diagnostics_picker` |
287−| `r` | Rename symbol (**LSP**) | `rename_symbol` |
230+| `r` | Rename symbol (**LSP**) | `rename_symbol` |
288−| `a` | Apply code action (**LSP**) | `code_action` |
231+| `a` | Apply code action (**LSP**) | `code_action` |
289−| `h` | Select symbol references (**LSP**) | `select_references_to_symbol_under_cursor` |
290−| `'` | Open last fuzzy picker | `last_picker` |
232+| `'` | Open last fuzzy picker | `last_picker` |
291−| `w` | Enter [window mode](#window-mode) | N/A |
233+| `w` | Enter [window mode](#window-mode) | N/A |
292−| `p` | Paste system clipboard after selections | `paste_clipboard_after` |
234+| `p` | Paste system clipboard after selections | `paste_clipboard_after` |
293−| `P` | Paste system clipboard before selections | `paste_clipboard_before` |
235+| `P` | Paste system clipboard before selections | `paste_clipboard_before` |
294−| `y` | Yank selections to clipboard | `yank_to_clipboard` |
236+| `y` | Join and yank selections to clipboard | `yank_joined_to_clipboard` |
295−| `Y` | Yank main selection to clipboard | `yank_main_selection_to_clipboard` |
237+| `Y` | Yank main selection to clipboard | `yank_main_selection_to_clipboard` |
296−| `R` | Replace selections by clipboard contents | `replace_selections_with_clipboard` |
238+| `R` | Replace selections by clipboard contents | `replace_selections_with_clipboard` |
297−| `/` | Global search in workspace folder | `global_search` |
239+| `/` | Global search in workspace folder | `global_search` |
298−| `?` | Open command palette | `command_palette` |
240+
299−
300−> 💡 Global search displays results in a fuzzy picker, use `Space + '` to bring it back up after opening a file.
241+> TIP: Global search displays results in a fuzzy picker, use `space + '` to bring it back up after opening a file.
301
242
302##### Popup
243##### Popup
303
244
@@ -307,148 +248,87 @@ Displays documentation for item under cursor.
307| ---- | ----------- |
248| ---- | ----------- |
308| `Ctrl-u` | Scroll up |
249| `Ctrl-u` | Scroll up |
309| `Ctrl-d` | Scroll down |
250| `Ctrl-d` | Scroll down |
310−
251+
311#### Unimpaired
252#### Unimpaired
312
253
313−These mappings are in the style of [vim-unimpaired](https://github.com/tpope/vim-unimpaired).
254+Mappings in the style of [vim-unimpaired](https://github.com/tpope/vim-unimpaired).
314−
255+
315−| Key | Description | Command |
256+| Key | Description | Command |
316−| ----- | ----------- | ------- |
257+| ----- | ----------- | ------- |
317−| `]d` | Go to next diagnostic (**LSP**) | `goto_next_diag` |
318−| `[d` | Go to previous diagnostic (**LSP**) | `goto_prev_diag` |
258+| `[d` | Go to previous diagnostic (**LSP**) | `goto_prev_diag` |
319−| `]D` | Go to last diagnostic in document (**LSP**) | `goto_last_diag` |
259+| `]d` | Go to next diagnostic (**LSP**) | `goto_next_diag` |
320−| `[D` | Go to first diagnostic in document (**LSP**) | `goto_first_diag` |
260+| `[D` | Go to first diagnostic in document (**LSP**) | `goto_first_diag` |
321−| `]f` | Go to next function (**TS**) | `goto_next_function` |
261+| `]D` | Go to last diagnostic in document (**LSP**) | `goto_last_diag` |
322−| `[f` | Go to previous function (**TS**) | `goto_prev_function` |
262+| `[space` | Add newline above | `add_newline_above` |
323−| `]t` | Go to next type definition (**TS**) | `goto_next_class` |
324−| `[t` | Go to previous type definition (**TS**) | `goto_prev_class` |
325−| `]a` | Go to next argument/parameter (**TS**) | `goto_next_parameter` |
326−| `[a` | Go to previous argument/parameter (**TS**) | `goto_prev_parameter` |
327−| `]c` | Go to next comment (**TS**) | `goto_next_comment` |
328−| `[c` | Go to previous comment (**TS**) | `goto_prev_comment` |
329−| `]T` | Go to next test (**TS**) | `goto_next_test` |
330−| `[T` | Go to previous test (**TS**) | `goto_prev_test` |
331−| `]p` | Go to next paragraph | `goto_next_paragraph` |
332−| `[p` | Go to previous paragraph | `goto_prev_paragraph` |
333−| `]g` | Go to next change | `goto_next_change` |
334−| `[g` | Go to previous change | `goto_prev_change` |
335−| `]G` | Go to last change | `goto_last_change` |
336−| `[G` | Go to first change | `goto_first_change` |
337−| `]Space` | Add newline below | `add_newline_below` |
263+| `]space` | Add newline below | `add_newline_below` |
338−| `[Space` | Add newline above | `add_newline_above` |
264+
339−
340−## Insert mode
265+## Insert Mode
341−
266+
342−Accessed by typing `i` in [normal mode](#normal-mode).
343−
344−Insert mode bindings are minimal by default. Helix is designed to
345−be a modal editor, and this is reflected in the user experience and internal
346−mechanics. Changes to the text are only saved for undos when
347−escaping from insert mode to normal mode.
348−
349−> 💡 New users are strongly encouraged to learn the modal editing paradigm
350−> to get the smoothest experience.
351−
352−| Key | Description | Command |
267+| Key | Description | Command |
353−| ----- | ----------- | ------- |
268+| ----- | ----------- | ------- |
354−| `Escape` | Switch to normal mode | `normal_mode` |
269+| `Escape` | Switch to normal mode | `normal_mode` |
355−| `Ctrl-s` | Commit undo checkpoint | `commit_undo_checkpoint` |
356−| `Ctrl-x` | Autocomplete | `completion` |
270+| `Ctrl-x` | Autocomplete | `completion` |
357−| `Ctrl-r` | Insert a register content | `insert_register` |
271+| `Ctrl-r` | Insert a register content | `insert_register` |
358−| `Ctrl-w`, `Alt-Backspace` | Delete previous word | `delete_word_backward` |
272+| `Ctrl-w` | Delete previous word | `delete_word_backward` |
359−| `Alt-d`, `Alt-Delete` | Delete next word | `delete_word_forward` |
273+| `Alt-d` | Delete next word | `delete_word_forward` |
274+| `Alt-b`, `Alt-Left` | Backward a word | `move_prev_word_end` |
275+| `Ctrl-b`, `Left` | Backward a char | `move_char_left` |
276+| `Alt-f`, `Alt-Right` | Forward a word | `move_next_word_start` |
277+| `Ctrl-f`, `Right` | Forward a char | `move_char_right` |
278+| `Ctrl-e`, `End` | move to line end | `goto_line_end_newline` |
279+| `Ctrl-a`, `Home` | move to line start | `goto_line_start` |
360−| `Ctrl-u` | Delete to start of line | `kill_to_line_start` |
280+| `Ctrl-u` | delete to start of line | `kill_to_line_start` |
361−| `Ctrl-k` | Delete to end of line | `kill_to_line_end` |
281+| `Ctrl-k` | delete to end of line | `kill_to_line_end` |
362−| `Ctrl-h`, `Backspace`, `Shift-Backspace` | Delete previous char | `delete_char_backward` |
282+| `backspace`, `Ctrl-h` | delete previous char | `delete_char_backward` |
363−| `Ctrl-d`, `Delete` | Delete next char | `delete_char_forward` |
283+| `delete`, `Ctrl-d` | delete previous char | `delete_char_forward` |
364−| `Ctrl-j`, `Enter` | Insert new line | `insert_newline` |
365−
366−These keys are not recommended, but are included for new users less familiar
367−with modal editors.
368−
369−| Key | Description | Command |
370−| ----- | ----------- | ------- |
371−| `Up` | Move to previous line | `move_line_up` |
284+| `Ctrl-p`, `Up` | move to previous line | `move_line_up` |
372−| `Down` | Move to next line | `move_line_down` |
285+| `Ctrl-n`, `Down` | move to next line | `move_line_down` |
373−| `Left` | Backward a char | `move_char_left` |
374−| `Right` | Forward a char | `move_char_right` |
375−| `PageUp` | Move one page up | `page_up` |
376−| `PageDown` | Move one page down | `page_down` |
377−| `Home` | Move to line start | `goto_line_start` |
378−| `End` | Move to line end | `goto_line_end_newline` |
379−
380−As you become more comfortable with modal editing, you may want to disable some
381−insert mode bindings. You can do this by editing your `config.toml` file.
382−
383−```toml
384−[keys.insert]
385−up = "no_op"
386−down = "no_op"
387−left = "no_op"
388−right = "no_op"
389−pageup = "no_op"
390−pagedown = "no_op"
391−home = "no_op"
392−end = "no_op"
393−```
394
286
395## Select / extend mode
287## Select / extend mode
396
288
397−Accessed by typing `v` in [normal mode](#normal-mode).
289+I'm still pondering whether to keep this mode or not. It changes movement
290+commands (including goto) to extend the existing selection instead of replacing it.
398
291
399−Select mode echoes Normal mode, but changes any movements to extend
292+> NOTE: It's a bit confusing at the moment because extend hasn't been
400−selections rather than replace them. Goto motions are also changed to
293+> implemented for all movement commands yet.
401−extend, so that `vgl`, for example, extends the selection to the end of
402−the line.
403
294
404−Search is also affected. By default, `n` and `N` will remove the current
405−selection and select the next instance of the search term. Toggling this
406−mode before pressing `n` or `N` makes it possible to keep the current
407−selection. Toggling it on and off during your iterative searching allows
408−you to selectively add search terms to your selections.
409−
410−## Picker
295+# Picker
411
296
412Keys to use within picker. Remapping currently not supported.
297Keys to use within picker. Remapping currently not supported.
413
298
414−| Key | Description |
299+| Key | Description |
415−| ----- | ------------- |
300+| ----- | ------------- |
416−| `Shift-Tab`, `Up`, `Ctrl-p` | Previous entry |
301+| `Up`, `Ctrl-k`, `Ctrl-p` | Previous entry |
417−| `Tab`, `Down`, `Ctrl-n` | Next entry |
302+| `Down`, `Ctrl-j`, `Ctrl-n` | Next entry |
418−| `PageUp`, `Ctrl-u` | Page up |
303+| `Ctrl-space` | Filter options |
419−| `PageDown`, `Ctrl-d` | Page down |
420−| `Home` | Go to first entry |
421−| `End` | Go to last entry |
422−| `Enter` | Open selected |
304+| `Enter` | Open selected |
423−| `Alt-Enter` | Open selected in the background without closing the picker |
424−| `Ctrl-s` | Open horizontally |
305+| `Ctrl-s` | Open horizontally |
425−| `Ctrl-v` | Open vertically |
306+| `Ctrl-v` | Open vertically |
426−| `Ctrl-t` | Toggle preview |
427−| `Escape`, `Ctrl-c` | Close picker |
307+| `Escape`, `Ctrl-c` | Close picker |
428−
308+
429−## Prompt
309+# Prompt
430
310
431Keys to use within prompt, Remapping currently not supported.
311Keys to use within prompt, Remapping currently not supported.
432
312
433−| Key | Description |
313+| Key | Description |
434−| ----- | ------------- |
314+| ----- | ------------- |
435−| `Escape`, `Ctrl-c` | Close prompt |
315+| `Escape`, `Ctrl-c` | Close prompt |
436−| `Alt-b`, `Ctrl-Left` | Backward a word |
316+| `Alt-b`, `Alt-Left` | Backward a word |
437−| `Ctrl-b`, `Left` | Backward a char |
317+| `Ctrl-b`, `Left` | Backward a char |
438−| `Alt-f`, `Ctrl-Right` | Forward a word |
318+| `Alt-f`, `Alt-Right` | Forward a word |
439−| `Ctrl-f`, `Right` | Forward a char |
319+| `Ctrl-f`, `Right` | Forward a char |
440−| `Ctrl-e`, `End` | Move prompt end |
320+| `Ctrl-e`, `End` | Move prompt end |
441−| `Ctrl-a`, `Home` | Move prompt start |
321+| `Ctrl-a`, `Home` | Move prompt start |
442−| `Ctrl-w`, `Alt-Backspace`, `Ctrl-Backspace` | Delete previous word |
322+| `Ctrl-w` | Delete previous word |
443−| `Alt-d`, `Alt-Delete`, `Ctrl-Delete` | Delete next word |
323+| `Alt-d` | Delete next word |
444−| `Ctrl-u` | Delete to start of line |
324+| `Ctrl-u` | Delete to start of line |
445−| `Ctrl-k` | Delete to end of line |
325+| `Ctrl-k` | Delete to end of line |
446−| `Backspace`, `Ctrl-h`, `Shift-Backspace` | Delete previous char |
326+| `backspace`, `Ctrl-h` | Delete previous char |
447−| `Delete`, `Ctrl-d` | Delete next char |
327+| `delete`, `Ctrl-d` | Delete next char |
448−| `Ctrl-s` | Insert a word under doc cursor, may be changed to Ctrl-r Ctrl-w later |
328+| `Ctrl-s` | Insert a word under doc cursor, may be changed to Ctrl-r Ctrl-w later |
449−| `Ctrl-p`, `Up` | Select previous history |
329+| `Ctrl-p`, `Up` | Select previous history |
450−| `Ctrl-n`, `Down` | Select next history |
330+| `Ctrl-n`, `Down` | Select next history |
451−| `Ctrl-r` | Insert the content of the register selected by following input char |
452−| `Tab` | Select next completion item |
331+| `Tab` | Select next completion item |
453−| `BackTab` | Select previous completion item |
332+| `BackTab` | Select previous completion item |
454−| `Enter` | Open selected |
333+| `Enter` | Open selected |
334+
book/src/lang-support.md+5−11
@@ -1,16 +1,10 @@
1# Language Support
1# Language Support
2
2
3−The following languages and Language Servers are supported. To use
3+For more information like arguments passed to default LSP server,
4−Language Server features, you must first [install][lsp-install-wiki] the
4+extensions assosciated with a filetype, custom LSP settings, filetype
5−appropriate Language Server.
5+specific indent settings, etc see the default
6−
6+[`languages.toml`][languages.toml] file.
7−You can check the language support in your installed helix version with `hx --health`.
8−
9−Also see the [Language Configuration][lang-config] docs and the [Adding
10−Languages][adding-languages] guide for more language configuration information.
11
7
12{{#include ./generated/lang-support.md}}
8{{#include ./generated/lang-support.md}}
13
9
14−[lsp-install-wiki]: https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers
10+[languages.toml]: https://github.com/helix-editor/helix/blob/master/languages.toml
15−[lang-config]: ./languages.md
16−[adding-languages]: ./guides/adding_languages.md
book/src/languages.md+5−229
@@ -1,237 +1,13 @@
1# Languages
1# Languages
2
2
3−Language-specific settings and settings for language servers are configured
3+Language-specific settings and settings for particular language servers can be configured in a `languages.toml` file placed in your [configuration directory](./configuration.md). Helix actually uses two `languages.toml` files, the [first one](https://github.com/helix-editor/helix/blob/master/languages.toml) is in the main helix repository; it contains the default settings for each language and is included in the helix binary at compile time. Users who want to see the available settings and options can either reference the helix repo's `languages.toml` file, or consult the table in the [adding languages](./guides/adding_languages.md) section.
4−in `languages.toml` files.
5
4
6−## `languages.toml` files
5+Changes made to the `languages.toml` file in a user's [configuration directory](./configuration.md) are merged with helix's defaults on start-up, such that a user's settings will take precedence over defaults in the event of a collision. For example, the default `languages.toml` sets rust's `auto-format` to `true`. If a user wants to disable auto-format, they can change the `languages.toml` in their [configuration directory](./configuration.md) to make the rust entry read like the example below; the new key/value pair `auto-format = false` will override the default when the two sets of settings are merged on start-up:
7
6
8−There are three possible locations for a `languages.toml` file:
9−
10−1. In the Helix source code, which lives in the
11− [Helix repository](https://github.com/helix-editor/helix/blob/master/languages.toml).
12− It provides the default configurations for languages and language servers.
13−
14−2. In your [configuration directory](./configuration.md). This overrides values
15− from the built-in language configuration. For example, to disable
16− auto-LSP-formatting in Rust:
17−
18− ```toml
19− # in <config_dir>/helix/languages.toml
20−
21− [language-server.mylang-lsp]
22− command = "mylang-lsp"
23−
24− [[language]]
25− name = "rust"
26− auto-format = false
27− ```
28−
29−3. In a `.helix` folder in your project. Language configuration may also be
30− overridden local to a project by creating a `languages.toml` file in a
31− `.helix` folder. Its settings will be merged with the language configuration
32− in the configuration directory and the built-in configuration.
33−
34−## Language configuration
35−
36−Each language is configured by adding a `[[language]]` section to a
37−`languages.toml` file. For example:
38−
39−```toml
40−[[language]]
41−name = "mylang"
42−scope = "source.mylang"
43−injection-regex = "mylang"
44−file-types = ["mylang", "myl"]
45−comment-token = "#"
46−indent = { tab-width = 2, unit = " " }
47−formatter = { command = "mylang-formatter" , args = ["--stdin"] }
48−language-servers = [ "mylang-lsp" ]
49```
7```
8+# in <config_dir>/helix/languages.toml
50
9
51−These configuration keys are available:
52−
53−| Key | Description |
54−| ---- | ----------- |
55−| `name` | The name of the language |
56−| `language-id` | The language-id for language servers, checkout the table at [TextDocumentItem](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentItem) for the right id |
57−| `scope` | A string like `source.js` that identifies the language. Currently, we strive to match the scope names used by popular TextMate grammars and by the Linguist library. Usually `source.<name>` or `text.<name>` in case of markup languages |
58−| `injection-regex` | regex pattern that will be tested against a language name in order to determine whether this language should be used for a potential [language injection][treesitter-language-injection] site. |
59−| `file-types` | The filetypes of the language, for example `["yml", "yaml"]`. See the file-type detection section below. |
60−| `shebangs` | The interpreters from the shebang line, for example `["sh", "bash"]` |
61−| `roots` | A set of marker files to look for when trying to find the workspace root. For example `Cargo.lock`, `yarn.lock` |
62−| `auto-format` | Whether to autoformat this language when saving |
63−| `diagnostic-severity` | Minimal severity of diagnostic for it to be displayed. (Allowed values: `Error`, `Warning`, `Info`, `Hint`) |
64−| `comment-token` | The token to use as a comment-token |
65−| `indent` | The indent to use. Has sub keys `unit` (the text inserted into the document when indenting; usually set to N spaces or `"\t"` for tabs) and `tab-width` (the number of spaces rendered for a tab) |
66−| `language-servers` | The Language Servers used for this language. See below for more information in the section [Configuring Language Servers for a language](#configuring-language-servers-for-a-language) |
67−| `grammar` | The tree-sitter grammar to use (defaults to the value of `name`) |
68−| `formatter` | The formatter for the language, it will take precedence over the lsp when defined. The formatter must be able to take the original file as input from stdin and write the formatted file to stdout |
69−| `soft-wrap` | [editor.softwrap](./configuration.md#editorsoft-wrap-section)
70−| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap-at-text-width` is set, defaults to `editor.text-width` |
71−| `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml`. Overwrites the setting of the same name in `config.toml` if set. |
72−| `persistent-diagnostic-sources` | An array of LSP diagnostic sources assumed unchanged when the language server resends the same set of diagnostics. Helix can track the position for these diagnostics internally instead. Useful for diagnostics that are recomputed on save.
73−
74−### File-type detection and the `file-types` key
75−
76−Helix determines which language configuration to use based on the `file-types` key
77−from the above section. `file-types` is a list of strings or tables, for
78−example:
79−
80−```toml
81−file-types = ["Makefile", "toml", { suffix = ".git/config" }]
82−```
83−
84−When determining a language configuration to use, Helix searches the file-types
85−with the following priorities:
86−
87−1. Exact match: if the filename of a file is an exact match of a string in a
88− `file-types` list, that language wins. In the example above, `"Makefile"`
89− will match against `Makefile` files.
90−2. Extension: if there are no exact matches, any `file-types` string that
91− matches the file extension of a given file wins. In the example above, the
92− `"toml"` matches files like `Cargo.toml` or `languages.toml`.
93−3. Suffix: if there are still no matches, any values in `suffix` tables
94− are checked against the full path of the given file. In the example above,
95− the `{ suffix = ".git/config" }` would match against any `config` files
96− in `.git` directories. Note: `/` is used as the directory separator but is
97− replaced at runtime with the appropriate path separator for the operating
98− system, so this rule would match against `.git\config` files on Windows.
99−
100−## Language Server configuration
101−
102−Language servers are configured separately in the table `language-server` in the same file as the languages `languages.toml`
103−
104−For example:
105−
106−```toml
107−[language-server.mylang-lsp]
108−command = "mylang-lsp"
109−args = ["--stdio"]
110−config = { provideFormatter = true }
111−environment = { "ENV1" = "value1", "ENV2" = "value2" }
112−
113−[language-server.efm-lsp-prettier]
114−command = "efm-langserver"
115−
116−[language-server.efm-lsp-prettier.config]
117−documentFormatting = true
118−languages = { typescript = [ { formatCommand ="prettier --stdin-filepath ${INPUT}", formatStdin = true } ] }
119−```
120−
121−These are the available options for a language server.
122−
123−| Key | Description |
124−| ---- | ----------- |
125−| `command` | The name or path of the language server binary to execute. Binaries must be in `$PATH` |
126−| `args` | A list of arguments to pass to the language server binary |
127−| `config` | LSP initialization options |
128−| `timeout` | The maximum time a request to the language server may take, in seconds. Defaults to `20` |
129−| `environment` | Any environment variables that will be used when starting the language server `{ "KEY1" = "Value1", "KEY2" = "Value2" }` |
130−
131−A `format` sub-table within `config` can be used to pass extra formatting options to
132−[Document Formatting Requests](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_formatting).
133−For example, with typescript:
134−
135−```toml
136−[language-server.typescript-language-server]
137−# pass format options according to https://github.com/typescript-language-server/typescript-language-server#workspacedidchangeconfiguration omitting the "[language].format." prefix.
138−config = { format = { "semicolons" = "insert", "insertSpaceBeforeFunctionParenthesis" = true } }
139−```
140−
141−### Configuring Language Servers for a language
142−
143−The `language-servers` attribute in a language tells helix which language servers are used for this language.
144−
145−They have to be defined in the `[language-server]` table as described in the previous section.
146−
147−Different languages can use the same language server instance, e.g. `typescript-language-server` is used for javascript, jsx, tsx and typescript by default.
148−
149−In case multiple language servers are specified in the `language-servers` attribute of a `language`,
150−it's often useful to only enable/disable certain language-server features for these language servers.
151−
152−As an example, `efm-lsp-prettier` of the previous example is used only with a formatting command `prettier`,
153−so everything else should be handled by the `typescript-language-server` (which is configured by default).
154−The language configuration for typescript could look like this:
155−
156−```toml
157[[language]]
10[[language]]
158−name = "typescript"
11+name = "rust"
159−language-servers = [ { name = "efm-lsp-prettier", only-features = [ "format" ] }, "typescript-language-server" ]
12+auto-format = false
160−```
161−
162−or equivalent:
163−
164−```toml
165−[[language]]
166−name = "typescript"
167−language-servers = [ { name = "typescript-language-server", except-features = [ "format" ] }, "efm-lsp-prettier" ]
168−```
169−
170−Each requested LSP feature is prioritized in the order of the `language-servers` array.
171−For example, the first `goto-definition` supported language server (in this case `typescript-language-server`) will be taken for the relevant LSP request (command `goto_definition`).
172−The features `diagnostics`, `code-action`, `completion`, `document-symbols` and `workspace-symbols` are an exception to that rule, as they are working for all language servers at the same time and are merged together, if enabled for the language.
173−If no `except-features` or `only-features` is given, all features for the language server are enabled.
174−If a language server itself doesn't support a feature, the next language server array entry will be tried (and so on).
175−
176−The list of supported features is:
177−
178−- `format`
179−- `goto-definition`
180−- `goto-declaration`
181−- `goto-type-definition`
182−- `goto-reference`
183−- `goto-implementation`
184−- `signature-help`
185−- `hover`
186−- `document-highlight`
187−- `completion`
188−- `code-action`
189−- `workspace-command`
190−- `document-symbols`
191−- `workspace-symbols`
192−- `diagnostics`
193−- `rename-symbol`
194−- `inlay-hints`
195−
196−## Tree-sitter grammar configuration
197−
198−The source for a language's tree-sitter grammar is specified in a `[[grammar]]`
199−section in `languages.toml`. For example:
200−
201−```toml
202−[[grammar]]
203−name = "mylang"
204−source = { git = "https://github.com/example/mylang", rev = "a250c4582510ff34767ec3b7dcdd3c24e8c8aa68" }
205−```
206−
207−Grammar configuration takes these keys:
208−
209−| Key | Description |
210−| --- | ----------- |
211−| `name` | The name of the tree-sitter grammar |
212−| `source` | The method of fetching the grammar - a table with a schema defined below |
213−
214−Where `source` is a table with either these keys when using a grammar from a
215−git repository:
216−
217−| Key | Description |
218−| --- | ----------- |
219−| `git` | A git remote URL from which the grammar should be cloned |
220−| `rev` | The revision (commit hash or tag) which should be fetched |
221−| `subpath` | A path within the grammar directory which should be built. Some grammar repositories host multiple grammars (for example `tree-sitter-typescript` and `tree-sitter-ocaml`) in subdirectories. This key is used to point `hx --grammar build` to the correct path for compilation. When omitted, the root of repository is used |
222−
223−### Choosing grammars
224−
225−You may use a top-level `use-grammars` key to control which grammars are
226−fetched and built when using `hx --grammar fetch` and `hx --grammar build`.
227−
228−```toml
229−# Note: this key must come **before** the [[language]] and [[grammar]] sections
230−use-grammars = { only = [ "rust", "c", "cpp" ] }
231−# or
232−use-grammars = { except = [ "yaml", "json" ] }
233```
13```
234−
235−When omitted, all grammars are fetched and built.
236−
237−[treesitter-language-injection]: https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection
book/src/remapping.md+17−37
@@ -1,56 +1,31 @@
1−# Key remapping
1+# Key Remapping
2
2
3−Helix currently supports one-way key remapping through a simple TOML configuration
3+One-way key remapping is temporarily supported via a simple TOML configuration
4file. (More powerful solutions such as rebinding via commands will be
4file. (More powerful solutions such as rebinding via commands will be
5available in the future).
5available in the future).
6
6
7−To remap keys, create a `config.toml` file in your `helix` configuration
7+To remap keys, write a `config.toml` file in your `helix` configuration
8−directory (default `~/.config/helix` on Linux systems) with a structure like
8+directory (default `~/.config/helix` in Linux systems) with a structure like
9this:
9this:
10
10
11```toml
11```toml
12# At most one section each of 'keys.normal', 'keys.insert' and 'keys.select'
12# At most one section each of 'keys.normal', 'keys.insert' and 'keys.select'
13[keys.normal]
13[keys.normal]
14−C-s = ":w" # Maps Ctrl-s to the typable command :w which is an alias for :write (save file)
14+C-s = ":w" # Maps the Control-s to the typable command :w which is an alias for :write (save file)
15−C-o = ":open ~/.config/helix/config.toml" # Maps Ctrl-o to opening of the helix config file
15+C-o = ":open ~/.config/helix/config.toml" # Maps the Control-o to opening of the helix config file
16a = "move_char_left" # Maps the 'a' key to the move_char_left command
16a = "move_char_left" # Maps the 'a' key to the move_char_left command
17w = "move_line_up" # Maps the 'w' key move_line_up
17w = "move_line_up" # Maps the 'w' key move_line_up
18−"C-S-esc" = "extend_line" # Maps Ctrl-Shift-Escape to extend_line
18+"C-S-esc" = "extend_line" # Maps Control-Shift-Escape to extend_line
19g = { a = "code_action" } # Maps `ga` to show possible code actions
19g = { a = "code_action" } # Maps `ga` to show possible code actions
20"ret" = ["open_below", "normal_mode"] # Maps the enter key to open_below then re-enter normal mode
20"ret" = ["open_below", "normal_mode"] # Maps the enter key to open_below then re-enter normal mode
21
21
22[keys.insert]
22[keys.insert]
23−"A-x" = "normal_mode" # Maps Alt-X to enter normal mode
23+"A-x" = "normal_mode" # Maps Alt-X to enter normal mode
24j = { k = "normal_mode" } # Maps `jk` to exit insert mode
24j = { k = "normal_mode" } # Maps `jk` to exit insert mode
25```
25```
26+> NOTE: Typable commands can also be remapped, remember to keep the `:` prefix to indicate it's a typable command.
26
27
27−## Minor modes
28−
29−Minor modes are accessed by pressing a key (usually from normal mode), giving access to dedicated bindings. Bindings
30−can be modified or added by nesting definitions.
31−
32−```toml
33−[keys.insert.j]
34−k = "normal_mode" # Maps `jk` to exit insert mode
35−
36−[keys.normal.g]
37−a = "code_action" # Maps `ga` to show possible code actions
38−
39−# invert `j` and `k` in view mode
40−[keys.normal.z]
41−j = "scroll_up"
42−k = "scroll_down"
43−
44−# create a new minor mode bound to `+`
45−[keys.normal."+"]
46−m = ":run-shell-command make"
47−c = ":run-shell-command cargo build"
48−t = ":run-shell-command cargo test"
49−```
50−
51−## Special keys and modifiers
52−
53−Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes
28+Control, Shift and Alt modifiers are encoded respectively with the prefixes
54`C-`, `S-` and `A-`. Special keys are encoded as follows:
29`C-`, `S-` and `A-`. Special keys are encoded as follows:
55
30
56| Key name | Representation |
31| Key name | Representation |
@@ -58,7 +33,12 @@ Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes
58| Backspace | `"backspace"` |
33| Backspace | `"backspace"` |
59| Space | `"space"` |
34| Space | `"space"` |
60| Return/Enter | `"ret"` |
35| Return/Enter | `"ret"` |
36+| < | `"lt"` |
37+| \> | `"gt"` |
38+| \+ | `"plus"` |
61| \- | `"minus"` |
39| \- | `"minus"` |
40+| ; | `"semicolon"` |
41+| % | `"percent"` |
62| Left | `"left"` |
42| Left | `"left"` |
63| Right | `"right"` |
43| Right | `"right"` |
64| Up | `"up"` |
44| Up | `"up"` |
@@ -75,5 +55,5 @@ Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes
75
55
76Keys can be disabled by binding them to the `no_op` command.
56Keys can be disabled by binding them to the `no_op` command.
77
57
78−A list of commands is available in the [Keymap](https://docs.helix-editor.com/keymap.html) documentation
58+Commands can be found at [Keymap](https://docs.helix-editor.com/keymap.html) Commands.
79− and in the source code at [`helix-term/src/commands.rs`](https://github.com/helix-editor/helix/blob/master/helix-term/src/commands.rs) at the invocation of `static_commands!` macro and the `TypableCommandList`.
59+> Commands can also be found in the source code at [`helix-term/src/commands.rs`](https://github.com/helix-editor/helix/blob/master/helix-term/src/commands.rs) at the invocation of `static_commands!` macro and the `TypableCommandList`.
book/src/themes.md+66−183
@@ -1,23 +1,22 @@
1# Themes
1# Themes
2
2
3−To use a theme add `theme = "<name>"` to the top of your [`config.toml`](./configuration.md) file, or select it during runtime using `:theme <name>`.
3+First you'll need to place selected themes in your `themes` directory (i.e `~/.config/helix/themes`), the directory might have to be created beforehand.
4
4
5−## Creating a theme
5+To use a custom theme add `theme = <name>` to your [`config.toml`](./configuration.md) or override it during runtime using `:theme <name>`.
6
6
7−Create a file with the name of your theme as the file name (i.e `mytheme.toml`) and place it in your `themes` directory (i.e `~/.config/helix/themes` or `%AppData%\helix\themes` on Windows). The directory might have to be created beforehand.
7+The default theme.toml can be found [here](https://github.com/helix-editor/helix/blob/master/theme.toml), and user submitted themes [here](https://github.com/helix-editor/helix/blob/master/runtime/themes).
8
8
9−> 💡 The names "default" and "base16_default" are reserved for built-in themes
9+## Creating a theme
10−> and cannot be overridden by user-defined themes.
11
10
12−### Overview
11+First create a file with the name of your theme as file name (i.e `mytheme.toml`) and place it in your `themes` directory (i.e `~/.config/helix/themes`).
13
12
14Each line in the theme file is specified as below:
13Each line in the theme file is specified as below:
15
14
16```toml
15```toml
17−key = { fg = "#ffffff", bg = "#000000", underline = { color = "#ff0000", style = "curl"}, modifiers = ["bold", "italic"] }
16+key = { fg = "#ffffff", bg = "#000000", modifiers = ["bold", "italic"] }
18```
17```
19
18
20−Where `key` represents what you want to style, `fg` specifies the foreground color, `bg` the background color, `underline` the underline `style`/`color`, and `modifiers` is a list of style modifiers. `bg`, `underline` and `modifiers` can be omitted to defer to the defaults.
19+where `key` represents what you want to style, `fg` specifies the foreground color, `bg` the background color, and `modifiers` is a list of style modifiers. `bg` and `modifiers` can be omitted to defer to the defaults.
21
20
22To specify only the foreground color:
21To specify only the foreground color:
23
22
@@ -25,44 +24,29 @@ To specify only the foreground color:
25key = "#ffffff"
24key = "#ffffff"
26```
25```
27
26
28−If the key contains a dot `'.'`, it must be quoted to prevent it being parsed as a [dotted key](https://toml.io/en/v1.0.0#keys).
27+if the key contains a dot `'.'`, it must be quoted to prevent it being parsed as a [dotted key](https://toml.io/en/v1.0.0#keys).
29
28
30```toml
29```toml
31"key.key" = "#ffffff"
30"key.key" = "#ffffff"
32```
31```
33
32
34−For inspiration, you can find the default `theme.toml`
35−[here](https://github.com/helix-editor/helix/blob/master/theme.toml) and
36−user-submitted themes
37−[here](https://github.com/helix-editor/helix/blob/master/runtime/themes).
38−
39−### Using the linter
40−
41−Use the supplied linting tool to check for errors and missing scopes:
42−
43−```sh
44−cargo xtask themelint onedark # replace onedark with <name>
45−```
46−
47−## The details of theme creation
48−
49### Color palettes
33### Color palettes
50
34
51−It's recommended to define a palette of named colors, and refer to them in the
35+It's recommended define a palette of named colors, and refer to them from the
52configuration values in your theme. To do this, add a table called
36configuration values in your theme. To do this, add a table called
53`palette` to your theme file:
37`palette` to your theme file:
54
38
55```toml
39```toml
56−"ui.background" = "white"
40+ui.background = "white"
57−"ui.text" = "black"
41+ui.text = "black"
58
42
59[palette]
43[palette]
60white = "#ffffff"
44white = "#ffffff"
61black = "#000000"
45black = "#000000"
62```
46```
63
47
64−Keep in mind that the `[palette]` table includes all keys after its header,
48+Remember that the `[palette]` table includes all keys after its header,
65−so it should be defined after the normal theme options.
49+so you should define the palette after normal theme options.
66
50
67The default palette uses the terminal's default 16 colors, and the colors names
51The default palette uses the terminal's default 16 colors, and the colors names
68are listed below. The `[palette]` section in the config file takes precedence
52are listed below. The `[palette]` section in the config file takes precedence
@@ -70,7 +54,6 @@ over it and is merged into the default palette.
70
54
71| Color Name |
55| Color Name |
72| --- |
56| --- |
73−| `default` |
74| `black` |
57| `black` |
75| `red` |
58| `red` |
76| `green` |
59| `green` |
@@ -90,77 +73,41 @@ over it and is merged into the default palette.
90
73
91### Modifiers
74### Modifiers
92
75
93−The following values may be used as modifier, provided they are supported by
76+The following values may be used as modifiers.
94−your terminal emulator.
95−
96−| Modifier |
97−| --- |
98−| `bold` |
99−| `dim` |
100−| `italic` |
101−| `underlined` |
102−| `slow_blink` |
103−| `rapid_blink` |
104−| `reversed` |
105−| `hidden` |
106−| `crossed_out` |
107−
108−> 💡 The `underlined` modifier is deprecated and only available for backwards compatibility.
109−> Its behavior is equivalent to setting `underline.style="line"`.
110−
111−### Underline style
112
77
113−One of the following values may be used as a value for `underline.style`, providing it is
114−supported by your terminal emulator.
78+Less common modifiers might not be supported by your terminal emulator.
115
79
116| Modifier |
80| Modifier |
117| --- |
81| --- |
118−| `line` |
82+| `bold` |
119−| `curl` |
83+| `dim` |
120−| `dashed` |
84+| `italic` |
121−| `dotted` |
85+| `underlined` |
122−| `double_line` |
86+| `slow_blink` |
123−
87+| `rapid_blink` |
124−
88+| `reversed` |
125−### Inheritance
89+| `hidden` |
126−
90+| `crossed_out` |
127−Extend other themes by setting the `inherits` property to an existing theme.
128−
129−```toml
130−inherits = "boo_berry"
131−
132−# Override the theming for "keyword"s:
133−"keyword" = { fg = "gold" }
134−
135−# Override colors in the palette:
136−[palette]
137−berry = "#2A2A4D"
138−```
139
91
140### Scopes
92### Scopes
141
93
142−The following is a list of scopes available to use for styling:
94+The following is a list of scopes available to use for styling.
143
95
144#### Syntax highlighting
96#### Syntax highlighting
145
97
146These keys match [tree-sitter scopes](https://tree-sitter.github.io/tree-sitter/syntax-highlighting#theme).
98These keys match [tree-sitter scopes](https://tree-sitter.github.io/tree-sitter/syntax-highlighting#theme).
147
99
148−When determining styling for a highlight, the longest matching theme key will be used. For example, if the highlight is `function.builtin.static`, the key `function.builtin` will be used instead of `function`.
100+For a given highlight produced, styling will be determined based on the longest matching theme key. For example, the highlight `function.builtin.static` would match the key `function.builtin` rather than `function`.
149
101
150We use a similar set of scopes as
102We use a similar set of scopes as
151−[Sublime Text](https://www.sublimetext.com/docs/scope_naming.html). See also
103+[SublimeText](https://www.sublimetext.com/docs/scope_naming.html). See also
152[TextMate](https://macromates.com/manual/en/language_grammars) scopes.
104[TextMate](https://macromates.com/manual/en/language_grammars) scopes.
153
105
154−- `attribute` - Class attributes, HTML tag attributes
155−
156- `type` - Types
106- `type` - Types
157 - `builtin` - Primitive types provided by the language (`int`, `usize`)
107 - `builtin` - Primitive types provided by the language (`int`, `usize`)
158− - `parameter` - Generic type parameters (`T`)
159− - `enum`
160− - `variant`
161- `constructor`
108- `constructor`
162
109
163−- `constant` (TODO: constant.other.placeholder for `%v`)
110+- `constant` (TODO: constant.other.placeholder for %v)
164 - `builtin` Special constants provided by the language (`true`, `false`, `nil` etc)
111 - `builtin` Special constants provided by the language (`true`, `false`, `nil` etc)
165 - `boolean`
112 - `boolean`
166 - `character`
113 - `character`
@@ -178,21 +125,21 @@ We use a similar set of scopes as
178
125
179- `comment` - Code comments
126- `comment` - Code comments
180 - `line` - Single line comments (`//`)
127 - `line` - Single line comments (`//`)
181− - `block` - Block comments (e.g. (`/* */`)
128+ - `block` - Block comments (e.g. (`/* */`)
182 - `documentation` - Documentation comments (e.g. `///` in Rust)
129 - `documentation` - Documentation comments (e.g. `///` in Rust)
183
130
184- `variable` - Variables
131- `variable` - Variables
185− - `builtin` - Reserved language variables (`self`, `this`, `super`, etc.)
132+ - `builtin` - Reserved language variables (`self`, `this`, `super`, etc)
186 - `parameter` - Function parameters
133 - `parameter` - Function parameters
187 - `other`
134 - `other`
188 - `member` - Fields of composite data types (e.g. structs, unions)
135 - `member` - Fields of composite data types (e.g. structs, unions)
136+ - `function` (TODO: ?)
189
137
190- `label`
138- `label`
191
139
192- `punctuation`
140- `punctuation`
193 - `delimiter` - Commas, colons
141 - `delimiter` - Commas, colons
194 - `bracket` - Parentheses, angle brackets, etc.
142 - `bracket` - Parentheses, angle brackets, etc.
195− - `special` - String interpolation brackets.
196
143
197- `keyword`
144- `keyword`
198 - `control`
145 - `control`
@@ -200,13 +147,9 @@ We use a similar set of scopes as
200 - `repeat` - `for`, `while`, `loop`
147 - `repeat` - `for`, `while`, `loop`
201 - `import` - `import`, `export`
148 - `import` - `import`, `export`
202 - `return`
149 - `return`
203− - `exception`
204 - `operator` - `or`, `in`
150 - `operator` - `or`, `in`
205− - `directive` - Preprocessor directives (`#if` in C)
151+ - `directive` - Preprocessor directives (`#if` in C)
206 - `function` - `fn`, `func`
152 - `function` - `fn`, `func`
207− - `storage` - Keywords describing how things are stored
208− - `type` - The type of something, `class`, `function`, `var`, `let`, etc.
209− - `modifier` - Storage modifiers like `static`, `mut`, `const`, `ref`, etc.
210
153
211- `operator` - `||`, `+=`, `>`
154- `operator` - `||`, `+=`, `>`
212
155
@@ -214,31 +157,22 @@ We use a similar set of scopes as
214 - `builtin`
157 - `builtin`
215 - `method`
158 - `method`
216 - `macro`
159 - `macro`
217− - `special` (preprocessor in C)
160+ - `special` (preprocesor in C)
218
161
219- `tag` - Tags (e.g. `<body>` in HTML)
162- `tag` - Tags (e.g. `<body>` in HTML)
220− - `builtin`
221
163
222- `namespace`
164- `namespace`
223
165
224−- `special`
225−
226- `markup`
166- `markup`
227 - `heading`
167 - `heading`
228− - `marker`
229− - `1`, `2`, `3`, `4`, `5`, `6` - heading text for h1 through h6
230 - `list`
168 - `list`
231 - `unnumbered`
169 - `unnumbered`
232 - `numbered`
170 - `numbered`
233− - `checked`
234− - `unchecked`
235 - `bold`
171 - `bold`
236 - `italic`
172 - `italic`
237− - `strikethrough`
238 - `link`
173 - `link`
239− - `url` - URLs pointed to by links
174+ - `url`
240− - `label` - non-URL link references
175+ - `label`
241− - `text` - URL and image descriptions in links
242 - `quote`
176 - `quote`
243 - `raw`
177 - `raw`
244 - `inline`
178 - `inline`
@@ -246,92 +180,41 @@ We use a similar set of scopes as
246
180
247- `diff` - version control changes
181- `diff` - version control changes
248 - `plus` - additions
182 - `plus` - additions
249− - `gutter` - gutter indicator
250 - `minus` - deletions
183 - `minus` - deletions
251− - `gutter` - gutter indicator
252 - `delta` - modifications
184 - `delta` - modifications
253 - `moved` - renamed or moved files/changes
185 - `moved` - renamed or moved files/changes
254− - `gutter` - gutter indicator
255
186
256#### Interface
187#### Interface
257
188
258−These scopes are used for theming the editor interface:
189+These scopes are used for theming the editor interface.
190+
191+
192+| Key | Notes |
193+| --- | --- |
194+| `ui.background` | |
195+| `ui.cursor` | |
196+| `ui.cursor.insert` | |
197+| `ui.cursor.select` | |
198+| `ui.cursor.match` | Matching bracket etc. |
199+| `ui.cursor.primary` | Cursor with primary selection |
200+| `ui.linenr` | |
201+| `ui.linenr.selected` | |
202+| `ui.statusline` | Statusline |
203+| `ui.statusline.inactive` | Statusline (unfocused document) |
204+| `ui.popup` | |
205+| `ui.window` | |
206+| `ui.help` | |
207+| `ui.text` | |
208+| `ui.text.focus` | |
209+| `ui.info` | |
210+| `ui.info.text` | |
211+| `ui.menu` | |
212+| `ui.menu.selected` | |
213+| `ui.selection` | For selections in the editing area |
214+| `ui.selection.primary` | |
215+| `warning` | Diagnostics warning (gutter) |
216+| `error` | Diagnostics error (gutter) |
217+| `info` | Diagnostics info (gutter) |
218+| `hint` | Diagnostics hint (gutter) |
219+| `diagnostic` | For text in editing area |
259
220
260−- `markup`
261− - `normal`
262− - `completion` - for completion doc popup UI
263− - `hover` - for hover popup UI
264− - `heading`
265− - `completion` - for completion doc popup UI
266− - `hover` - for hover popup UI
267− - `raw`
268− - `inline`
269− - `completion` - for completion doc popup UI
270− - `hover` - for hover popup UI
271−
272−
273−| Key | Notes |
274−| --- | --- |
275−| `ui.background` | |
276−| `ui.background.separator` | Picker separator below input line |
277−| `ui.cursor` | |
278−| `ui.cursor.normal` | |
279−| `ui.cursor.insert` | |
280−| `ui.cursor.select` | |
281−| `ui.cursor.match` | Matching bracket etc. |
282−| `ui.cursor.primary` | Cursor with primary selection |
283−| `ui.cursor.primary.normal` | |
284−| `ui.cursor.primary.insert` | |
285−| `ui.cursor.primary.select` | |
286−| `ui.debug.breakpoint` | Breakpoint indicator, found in the gutter |
287−| `ui.debug.active` | Indicator for the line at which debugging execution is paused at, found in the gutter |
288−| `ui.gutter` | Gutter |
289−| `ui.gutter.selected` | Gutter for the line the cursor is on |
290−| `ui.highlight.frameline` | Line at which debugging execution is paused at |
291−| `ui.linenr` | Line numbers |
292−| `ui.linenr.selected` | Line number for the line the cursor is on |
293−| `ui.statusline` | Statusline |
294−| `ui.statusline.inactive` | Statusline (unfocused document) |
295−| `ui.statusline.normal` | Statusline mode during normal mode ([only if `editor.color-modes` is enabled][editor-section]) |
296−| `ui.statusline.insert` | Statusline mode during insert mode ([only if `editor.color-modes` is enabled][editor-section]) |
297−| `ui.statusline.select` | Statusline mode during select mode ([only if `editor.color-modes` is enabled][editor-section]) |
298−| `ui.statusline.separator` | Separator character in statusline |
299−| `ui.bufferline` | Style for the buffer line |
300−| `ui.bufferline.active` | Style for the active buffer in buffer line |
301−| `ui.bufferline.background` | Style for bufferline background |
302−| `ui.popup` | Documentation popups (e.g. Space + k) |
303−| `ui.popup.info` | Prompt for multiple key options |
304−| `ui.window` | Borderlines separating splits |
305−| `ui.help` | Description box for commands |
306−| `ui.text` | Default text style, command prompts, popup text, etc. |
307−| `ui.text.focus` | The currently selected line in the picker |
308−| `ui.text.inactive` | Same as `ui.text` but when the text is inactive (e.g. suggestions) |
309−| `ui.text.info` | The key: command text in `ui.popup.info` boxes |
310−| `ui.virtual.ruler` | Ruler columns (see the [`editor.rulers` config][editor-section]) |
311−| `ui.virtual.whitespace` | Visible whitespace characters |
312−| `ui.virtual.indent-guide` | Vertical indent width guides |
313−| `ui.virtual.inlay-hint` | Default style for inlay hints of all kinds |
314−| `ui.virtual.inlay-hint.parameter` | Style for inlay hints of kind `parameter` (LSPs are not required to set a kind) |
315−| `ui.virtual.inlay-hint.type` | Style for inlay hints of kind `type` (LSPs are not required to set a kind) |
316−| `ui.virtual.wrap` | Soft-wrap indicator (see the [`editor.soft-wrap` config][editor-section]) |
317−| `ui.menu` | Code and command completion menus |
318−| `ui.menu.selected` | Selected autocomplete item |
319−| `ui.menu.scroll` | `fg` sets thumb color, `bg` sets track color of scrollbar |
320−| `ui.selection` | For selections in the editing area |
321−| `ui.selection.primary` | |
322−| `ui.highlight` | Highlighted lines in the picker preview |
323−| `ui.cursorline.primary` | The line of the primary cursor ([if cursorline is enabled][editor-section]) |
324−| `ui.cursorline.secondary` | The lines of any other cursors ([if cursorline is enabled][editor-section]) |
325−| `ui.cursorcolumn.primary` | The column of the primary cursor ([if cursorcolumn is enabled][editor-section]) |
326−| `ui.cursorcolumn.secondary` | The columns of any other cursors ([if cursorcolumn is enabled][editor-section]) |
327−| `warning` | Diagnostics warning (gutter) |
328−| `error` | Diagnostics error (gutter) |
329−| `info` | Diagnostics info (gutter) |
330−| `hint` | Diagnostics hint (gutter) |
331−| `diagnostic` | Diagnostics fallback style (editing area) |
332−| `diagnostic.hint` | Diagnostics hint (editing area) |
333−| `diagnostic.info` | Diagnostics info (editing area) |
334−| `diagnostic.warning` | Diagnostics warning (editing area) |
335−| `diagnostic.error` | Diagnostics error (editing area) |
336−
337−[editor-section]: ./configuration.md#editor-section
book/src/title-page.mddeleted−17
@@ -1,17 +0,0 @@
1−# Helix
2−
3−Docs for bleeding edge master can be found at
4−[https://docs.helix-editor.com/master](https://docs.helix-editor.com/master).
5−
6−See the [usage] section for a quick overview of the editor, [keymap]
7−section for all available keybindings and the [configuration] section
8−for defining custom keybindings, setting themes, etc.
9−For everything else (e.g., how to install supported language servers), see the [Helix Wiki].
10−
11−Refer the [FAQ] for common questions.
12−
13−[FAQ]: https://github.com/helix-editor/helix/wiki/FAQ
14−[usage]: ./usage.md
15−[keymap]: ./keymap.md
16−[configuration]: ./configuration.md
17−[Helix Wiki]: https://github.com/helix-editor/helix/wiki
book/src/usage.md+35−167
@@ -1,208 +1,76 @@
1−# Using Helix
1+# Usage
2
2
3−<!--toc:start-->
3+(Currently not fully documented, see the [keymappings](./keymap.md) list for more.)
4−- [Registers](#registers)
5− - [User-defined registers](#user-defined-registers)
6− - [Special registers](#special-registers)
7−- [Surround](#surround)
8−- [Selecting and manipulating text with textobjects](#selecting-and-manipulating-text-with-textobjects)
9−- [Navigating using tree-sitter textobjects](#navigating-using-tree-sitter-textobjects)
10−- [Moving the selection with syntax-aware motions](#moving-the-selection-with-syntax-aware-motions)
11−<!--toc:end-->
12
4
13−For a full interactive introduction to Helix, refer to the
14−[tutor](https://github.com/helix-editor/helix/blob/master/runtime/tutor) which
5+See [tutor.txt](https://github.com/helix-editor/helix/blob/master/runtime/tutor.txt) (accessible via `hx --tutor` or `:tutor`) for a vimtutor-like introduction.
15−can be accessed via the command `hx --tutor` or `:tutor`.
16−
17−> 💡 Currently, not all functionality is fully documented, please refer to the
18−> [key mappings](./keymap.md) list.
19
6
20## Registers
7## Registers
21
8
22−In Helix, registers are storage locations for text and other data, such as the
9+Vim-like registers can be used to yank and store text to be pasted later. Usage is similar, with `"` being used to select a register:
23−result of a search. Registers can be used to cut, copy, and paste text, similar
24−to the clipboard in other text editors. Usage is similar to Vim, with `"` being
25−used to select a register.
26−
27−### User-defined registers
28−
29−Helix allows you to create your own named registers for storing text, for
30−example:
31
10
32- `"ay` - Yank the current selection to register `a`.
11- `"ay` - Yank the current selection to register `a`.
33- `"op` - Paste the text in register `o` after the selection.
12- `"op` - Paste the text in register `o` after the selection.
34
13
35−If a register is selected before invoking a change or delete command, the selection will be stored in the register and the action will be carried out:
14+If there is a selected register before invoking a change or delete command, the selection will be stored in the register and the action will be carried out:
36
15
37- `"hc` - Store the selection in register `h` and then change it (delete and enter insert mode).
16- `"hc` - Store the selection in register `h` and then change it (delete and enter insert mode).
38- `"md` - Store the selection in register `m` and delete it.
17- `"md` - Store the selection in register `m` and delete it.
39
18
40−### Default registers
19+### Special Registers
41−
42−Commands that use registers, like yank (`y`), use a default register if none is specified.
43−These registers are used as defaults:
44
20
45| Register character | Contains |
21| Register character | Contains |
46| --- | --- |
22| --- | --- |
47| `/` | Last search |
23| `/` | Last search |
48| `:` | Last executed command |
24| `:` | Last executed command |
49| `"` | Last yanked text |
25| `"` | Last yanked text |
50−| `@` | Last recorded macro |
26+| `_` | Black hole |
51−
52−### Special registers
53−
54−Some registers have special behavior when read from and written to.
55−
56−| Register character | When read | When written |
57−| --- | --- | --- |
58−| `_` | No values are returned | All values are discarded |
59−| `#` | Selection indices (first selection is `1`, second is `2`, etc.) | This register is not writable |
60−| `.` | Contents of the current selections | This register is not writable |
61−| `%` | Name of the current file | This register is not writable |
62−| `+` | Reads from the system clipboard | Joins and yanks to the system clipboard |
63−| `*` | Reads from the primary clipboard | Joins and yanks to the primary clipboard |
64
27
65−When yanking multiple selections to the clipboard registers, the selections
28+> There is no special register for copying to system clipboard, instead special commands and keybindings are provided. See the [keymap](keymap.md#space-mode) for the specifics.
66−are joined with newlines. Pasting from these registers will paste multiple
29+> The black hole register works as a no-op register, meaning no data will be written to / read from it.
67−selections if the clipboard was last yanked to by the Helix session. Otherwise
68−the clipboard contents are pasted as one selection.
69
30
70## Surround
31## Surround
71
32
72−Helix includes built-in functionality similar to [vim-surround](https://github.com/tpope/vim-surround).
33+Functionality similar to [vim-surround](https://github.com/tpope/vim-surround) is built into
73−The keymappings have been inspired from [vim-sandwich](https://github.com/machakann/vim-sandwich):
34+helix. The keymappings have been inspired from [vim-sandwich](https://github.com/machakann/vim-sandwich):
74
35
75−![Surround demo](https://user-images.githubusercontent.com/23398472/122865801-97073180-d344-11eb-8142-8f43809982c6.gif)
36+![surround demo](https://user-images.githubusercontent.com/23398472/122865801-97073180-d344-11eb-8142-8f43809982c6.gif)
76
37
77−| Key Sequence | Action |
78−| --------------------------------- | --------------------------------------- |
79−| `ms<char>` (after selecting text) | Add surround characters to selection |
38+- `ms` - Add surround characters
80−| `mr<char_to_replace><new_char>` | Replace the closest surround characters |
39+- `mr` - Replace surround characters
81−| `md<char_to_delete>` | Delete the closest surround characters |
40+- `md` - Delete surround characters
82
41
42+`ms` acts on a selection, so select the text first and use `ms<char>`. `mr` and `md` work
83−You can use counts to act on outer pairs.
43+on the closest pairs found and selections are not required; use counts to act in outer pairs.
84
44
85−Surround can also act on multiple selections. For example, to change every occurrence of `(use)` to `[use]`:
45+It can also act on multiple seletions (yay!). For example, to change every occurance of `(use)` to `[use]`:
86
46
87−1. `%` to select the whole file
47+- `%` to select the whole file
88−2. `s` to split the selections on a search term
48+- `s` to split the selections on a search term
89−3. Input `use` and hit Enter
49+- Input `use` and hit Enter
90−4. `mr([` to replace the parentheses with square brackets
50+- `mr([` to replace the parens with square brackets
91
51
92−Multiple characters are currently not supported, but planned for future release.
52+Multiple characters are currently not supported, but planned.
93
53
94−## Selecting and manipulating text with textobjects
54+## Textobjects
95
55
96−In Helix, textobjects are a way to select, manipulate and operate on a piece of
56+Currently supported: `word`, `surround`, `function`, `class`, `parameter`.
97−text in a structured way. They allow you to refer to blocks of text based on
98−their structure or purpose, such as a word, sentence, paragraph, or even a
99−function or block of code.
100
57
101−![Textobject demo](https://user-images.githubusercontent.com/23398472/124231131-81a4bb00-db2d-11eb-9d10-8e577ca7b177.gif)
58+![textobject-demo](https://user-images.githubusercontent.com/23398472/124231131-81a4bb00-db2d-11eb-9d10-8e577ca7b177.gif)
102−![Textobject tree-sitter demo](https://user-images.githubusercontent.com/23398472/132537398-2a2e0a54-582b-44ab-a77f-eb818942203d.gif)
59+![textobject-treesitter-demo](https://user-images.githubusercontent.com/23398472/132537398-2a2e0a54-582b-44ab-a77f-eb818942203d.gif)
103
60
104−- `ma` - Select around the object (`va` in Vim, `<alt-a>` in Kakoune)
61+- `ma` - Select around the object (`va` in vim, `<alt-a>` in kakoune)
105−- `mi` - Select inside the object (`vi` in Vim, `<alt-i>` in Kakoune)
62+- `mi` - Select inside the object (`vi` in vim, `<alt-i>` in kakoune)
106
63
107| Key after `mi` or `ma` | Textobject selected |
64| Key after `mi` or `ma` | Textobject selected |
108| --- | --- |
65| --- | --- |
109| `w` | Word |
66| `w` | Word |
110| `W` | WORD |
67| `W` | WORD |
111−| `p` | Paragraph |
112−| `(`, `[`, `'`, etc. | Specified surround pairs |
68+| `(`, `[`, `'`, etc | Specified surround pairs |
113−| `m` | The closest surround pair |
114| `f` | Function |
69| `f` | Function |
115−| `t` | Type (or Class) |
70+| `c` | Class |
116−| `a` | Argument/parameter |
71+| `p` | Parameter |
117−| `c` | Comment |
118−| `T` | Test |
119−| `g` | Change |
120
72
121−> 💡 `f`, `t`, etc. need a tree-sitter grammar active for the current
73+Note: `f`, `c`, etc need a tree-sitter grammar active for the current
122document and a special tree-sitter query file to work properly. [Only
74document and a special tree-sitter query file to work properly. [Only
75+some grammars](https://github.com/search?q=repo%3Ahelix-editor%2Fhelix+filename%3Atextobjects.scm&type=Code&ref=advsearch&l=&l=)
123−some grammars][lang-support] currently have the query file implemented.
76+currently have the query file implemented. Contributions are welcome !
124−Contributions are welcome!
125−
126−## Navigating using tree-sitter textobjects
127−
128−Navigating between functions, classes, parameters, and other elements is
129−possible using tree-sitter and textobject queries. For
130−example to move to the next function use `]f`, to move to previous
131−type use `[t`, and so on.
132−
133−![Tree-sitter-nav-demo][tree-sitter-nav-demo]
134−
135−For the full reference see the [unimpaired][unimpaired-keybinds] section of the key bind
136−documentation.
137−
138−> 💡 This feature relies on tree-sitter textobjects
139−> and requires the corresponding query file to work properly.
140−
141−## Moving the selection with syntax-aware motions
142−
143−`Alt-p`, `Alt-o`, `Alt-i`, and `Alt-n` (or `Alt` and arrow keys) allow you to move the
144−selection according to its location in the syntax tree. For example, many languages have the
145−following syntax for function calls:
146−
147−```js
148−func(arg1, arg2, arg3);
149−```
150−
151−A function call might be parsed by tree-sitter into a tree like the following.
152−
153−```tsq
154−(call
155− function: (identifier) ; func
156− arguments:
157− (arguments ; (arg1, arg2, arg3)
158− (identifier) ; arg1
159− (identifier) ; arg2
160− (identifier))) ; arg3
161−```
162−
163−Use `:tree-sitter-subtree` to view the syntax tree of the primary selection. In
164−a more intuitive tree format:
165−
166−```
167− ┌────┐
168− │call│
169− ┌─────┴────┴─────┐
170− │ │
171−┌─────▼────┐ ┌────▼────┐
172−│identifier│ │arguments│
173−│ "func" │ ┌────┴───┬─────┴───┐
174−└──────────┘ │ │ │
175− │ │ │
176− ┌─────────▼┐ ┌────▼─────┐ ┌▼─────────┐
177− │identifier│ │identifier│ │identifier│
178− │ "arg1" │ │ "arg2" │ │ "arg3" │
179− └──────────┘ └──────────┘ └──────────┘
180−```
181−
182−If you have a selection that wraps `arg1` (see the tree above), and you use
183−`Alt-n`, it will select the next sibling in the syntax tree: `arg2`.
184−
185−```js
186−// before
187−func([arg1], arg2, arg3)
188−// after
189−func(arg1, [arg2], arg3);
190−```
191−
192−Similarly, `Alt-o` will expand the selection to the parent node, in this case, the
193−arguments node.
194−
195−```js
196−func[(arg1, arg2, arg3)];
197−```
198−
199−There is also some nuanced behavior that prevents you from getting stuck on a
200−node with no sibling. When using `Alt-p` with a selection on `arg1`, the previous
201−child node will be selected. In the event that `arg1` does not have a previous
202−sibling, the selection will move up the syntax tree and select the previous
203−element. As a result, using `Alt-p` with a selection on `arg1` will move the
204−selection to the "func" `identifier`.
205−
206−[lang-support]: ./lang-support.md
207−[unimpaired-keybinds]: ./keymap.md#unimpaired
208−[tree-sitter-nav-demo]: https://user-images.githubusercontent.com/23398472/152332550-7dfff043-36a2-4aec-b8f2-77c13eb56d6f.gif
book/theme/book.jsnew file+660
@@ -0,0 +1,660 @@
1+"use strict";
2+
3+// Fix back button cache problem
4+window.onunload = function () { };
5+
6+// Global variable, shared between modules
7+function playground_text(playground) {
8+ let code_block = playground.querySelector("code");
9+
10+ if (window.ace && code_block.classList.contains("editable")) {
11+ let editor = window.ace.edit(code_block);
12+ return editor.getValue();
13+ } else {
14+ return code_block.textContent;
15+ }
16+}
17+
18+(function codeSnippets() {
19+ function fetch_with_timeout(url, options, timeout = 6000) {
20+ return Promise.race([
21+ fetch(url, options),
22+ new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
23+ ]);
24+ }
25+
26+ var playgrounds = Array.from(document.querySelectorAll(".playground"));
27+ if (playgrounds.length > 0) {
28+ fetch_with_timeout("https://play.rust-lang.org/meta/crates", {
29+ headers: {
30+ 'Content-Type': "application/json",
31+ },
32+ method: 'POST',
33+ mode: 'cors',
34+ })
35+ .then(response => response.json())
36+ .then(response => {
37+ // get list of crates available in the rust playground
38+ let playground_crates = response.crates.map(item => item["id"]);
39+ playgrounds.forEach(block => handle_crate_list_update(block, playground_crates));
40+ });
41+ }
42+
43+ function handle_crate_list_update(playground_block, playground_crates) {
44+ // update the play buttons after receiving the response
45+ update_play_button(playground_block, playground_crates);
46+
47+ // and install on change listener to dynamically update ACE editors
48+ if (window.ace) {
49+ let code_block = playground_block.querySelector("code");
50+ if (code_block.classList.contains("editable")) {
51+ let editor = window.ace.edit(code_block);
52+ editor.addEventListener("change", function (e) {
53+ update_play_button(playground_block, playground_crates);
54+ });
55+ // add Ctrl-Enter command to execute rust code
56+ editor.commands.addCommand({
57+ name: "run",
58+ bindKey: {
59+ win: "Ctrl-Enter",
60+ mac: "Ctrl-Enter"
61+ },
62+ exec: _editor => run_rust_code(playground_block)
63+ });
64+ }
65+ }
66+ }
67+
68+ // updates the visibility of play button based on `no_run` class and
69+ // used crates vs ones available on http://play.rust-lang.org
70+ function update_play_button(pre_block, playground_crates) {
71+ var play_button = pre_block.querySelector(".play-button");
72+
73+ // skip if code is `no_run`
74+ if (pre_block.querySelector('code').classList.contains("no_run")) {
75+ play_button.classList.add("hidden");
76+ return;
77+ }
78+
79+ // get list of `extern crate`'s from snippet
80+ var txt = playground_text(pre_block);
81+ var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g;
82+ var snippet_crates = [];
83+ var item;
84+ while (item = re.exec(txt)) {
85+ snippet_crates.push(item[1]);
86+ }
87+
88+ // check if all used crates are available on play.rust-lang.org
89+ var all_available = snippet_crates.every(function (elem) {
90+ return playground_crates.indexOf(elem) > -1;
91+ });
92+
93+ if (all_available) {
94+ play_button.classList.remove("hidden");
95+ } else {
96+ play_button.classList.add("hidden");
97+ }
98+ }
99+
100+ function run_rust_code(code_block) {
101+ var result_block = code_block.querySelector(".result");
102+ if (!result_block) {
103+ result_block = document.createElement('code');
104+ result_block.className = 'result hljs language-bash';
105+
106+ code_block.append(result_block);
107+ }
108+
109+ let text = playground_text(code_block);
110+ let classes = code_block.querySelector('code').classList;
111+ let has_2018 = classes.contains("edition2018");
112+ let edition = has_2018 ? "2018" : "2015";
113+
114+ var params = {
115+ version: "stable",
116+ optimize: "0",
117+ code: text,
118+ edition: edition
119+ };
120+
121+ if (text.indexOf("#![feature") !== -1) {
122+ params.version = "nightly";
123+ }
124+
125+ result_block.innerText = "Running...";
126+
127+ fetch_with_timeout("https://play.rust-lang.org/evaluate.json", {
128+ headers: {
129+ 'Content-Type': "application/json",
130+ },
131+ method: 'POST',
132+ mode: 'cors',
133+ body: JSON.stringify(params)
134+ })
135+ .then(response => response.json())
136+ .then(response => result_block.innerText = response.result)
137+ .catch(error => result_block.innerText = "Playground Communication: " + error.message);
138+ }
139+
140+ // Syntax highlighting Configuration
141+ hljs.configure({
142+ tabReplace: ' ', // 4 spaces
143+ languages: [], // Languages used for auto-detection
144+ });
145+
146+ let code_nodes = Array
147+ .from(document.querySelectorAll('code'))
148+ // Don't highlight `inline code` blocks in headers.
149+ .filter(function (node) {return !node.parentElement.classList.contains("header"); });
150+
151+ if (window.ace) {
152+ // language-rust class needs to be removed for editable
153+ // blocks or highlightjs will capture events
154+ Array
155+ .from(document.querySelectorAll('code.editable'))
156+ .forEach(function (block) { block.classList.remove('language-rust'); });
157+
158+ Array
159+ .from(document.querySelectorAll('code:not(.editable)'))
160+ .forEach(function (block) { hljs.highlightBlock(block); });
161+ } else {
162+ code_nodes.forEach(function (block) { hljs.highlightBlock(block); });
163+ }
164+
165+ // Adding the hljs class gives code blocks the color css
166+ // even if highlighting doesn't apply
167+ code_nodes.forEach(function (block) { block.classList.add('hljs'); });
168+
169+ Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) {
170+
171+ var lines = Array.from(block.querySelectorAll('.boring'));
172+ // If no lines were hidden, return
173+ if (!lines.length) { return; }
174+ block.classList.add("hide-boring");
175+
176+ var buttons = document.createElement('div');
177+ buttons.className = 'buttons';
178+ buttons.innerHTML = "<button class=\"fa fa-eye\" title=\"Show hidden lines\" aria-label=\"Show hidden lines\"></button>";
179+
180+ // add expand button
181+ var pre_block = block.parentNode;
182+ pre_block.insertBefore(buttons, pre_block.firstChild);
183+
184+ pre_block.querySelector('.buttons').addEventListener('click', function (e) {
185+ if (e.target.classList.contains('fa-eye')) {
186+ e.target.classList.remove('fa-eye');
187+ e.target.classList.add('fa-eye-slash');
188+ e.target.title = 'Hide lines';
189+ e.target.setAttribute('aria-label', e.target.title);
190+
191+ block.classList.remove('hide-boring');
192+ } else if (e.target.classList.contains('fa-eye-slash')) {
193+ e.target.classList.remove('fa-eye-slash');
194+ e.target.classList.add('fa-eye');
195+ e.target.title = 'Show hidden lines';
196+ e.target.setAttribute('aria-label', e.target.title);
197+
198+ block.classList.add('hide-boring');
199+ }
200+ });
201+ });
202+
203+ if (window.playground_copyable) {
204+ Array.from(document.querySelectorAll('pre code')).forEach(function (block) {
205+ var pre_block = block.parentNode;
206+ if (!pre_block.classList.contains('playground')) {
207+ var buttons = pre_block.querySelector(".buttons");
208+ if (!buttons) {
209+ buttons = document.createElement('div');
210+ buttons.className = 'buttons';
211+ pre_block.insertBefore(buttons, pre_block.firstChild);
212+ }
213+
214+ var clipButton = document.createElement('button');
215+ clipButton.className = 'fa fa-copy clip-button';
216+ clipButton.title = 'Copy to clipboard';
217+ clipButton.setAttribute('aria-label', clipButton.title);
218+ clipButton.innerHTML = '<i class=\"tooltiptext\"></i>';
219+
220+ buttons.insertBefore(clipButton, buttons.firstChild);
221+ }
222+ });
223+ }
224+
225+ // Process playground code blocks
226+ Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) {
227+ // Add play button
228+ var buttons = pre_block.querySelector(".buttons");
229+ if (!buttons) {
230+ buttons = document.createElement('div');
231+ buttons.className = 'buttons';
232+ pre_block.insertBefore(buttons, pre_block.firstChild);
233+ }
234+
235+ var runCodeButton = document.createElement('button');
236+ runCodeButton.className = 'fa fa-play play-button';
237+ runCodeButton.hidden = true;
238+ runCodeButton.title = 'Run this code';
239+ runCodeButton.setAttribute('aria-label', runCodeButton.title);
240+
241+ buttons.insertBefore(runCodeButton, buttons.firstChild);
242+ runCodeButton.addEventListener('click', function (e) {
243+ run_rust_code(pre_block);
244+ });
245+
246+ if (window.playground_copyable) {
247+ var copyCodeClipboardButton = document.createElement('button');
248+ copyCodeClipboardButton.className = 'fa fa-copy clip-button';
249+ copyCodeClipboardButton.innerHTML = '<i class="tooltiptext"></i>';
250+ copyCodeClipboardButton.title = 'Copy to clipboard';
251+ copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title);
252+
253+ buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild);
254+ }
255+
256+ let code_block = pre_block.querySelector("code");
257+ if (window.ace && code_block.classList.contains("editable")) {
258+ var undoChangesButton = document.createElement('button');
259+ undoChangesButton.className = 'fa fa-history reset-button';
260+ undoChangesButton.title = 'Undo changes';
261+ undoChangesButton.setAttribute('aria-label', undoChangesButton.title);
262+
263+ buttons.insertBefore(undoChangesButton, buttons.firstChild);
264+
265+ undoChangesButton.addEventListener('click', function () {
266+ let editor = window.ace.edit(code_block);
267+ editor.setValue(editor.originalCode);
268+ editor.clearSelection();
269+ });
270+ }
271+ });
272+})();
273+
274+(function themes() {
275+ var html = document.querySelector('html');
276+ var themeToggleButton = document.getElementById('theme-toggle');
277+ var themePopup = document.getElementById('theme-list');
278+ var themeColorMetaTag = document.querySelector('meta[name="theme-color"]');
279+ var stylesheets = {
280+ ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"),
281+ tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"),
282+ highlight: document.querySelector("[href$='highlight.css']"),
283+ };
284+
285+ function showThemes() {
286+ themePopup.style.display = 'block';
287+ themeToggleButton.setAttribute('aria-expanded', true);
288+ themePopup.querySelector("button#" + get_theme()).focus();
289+ }
290+
291+ function hideThemes() {
292+ themePopup.style.display = 'none';
293+ themeToggleButton.setAttribute('aria-expanded', false);
294+ themeToggleButton.focus();
295+ }
296+
297+ function get_theme() {
298+ var theme;
299+ try { theme = localStorage.getItem('mdbook-theme'); } catch (e) { }
300+ if (theme === null || theme === undefined) {
301+ return default_theme;
302+ } else {
303+ return theme;
304+ }
305+ }
306+
307+ function set_theme(theme, store = true) {
308+ let ace_theme;
309+
310+ if (theme == 'coal' || theme == 'navy') {
311+ stylesheets.ayuHighlight.disabled = true;
312+ stylesheets.tomorrowNight.disabled = false;
313+ stylesheets.highlight.disabled = true;
314+
315+ ace_theme = "ace/theme/tomorrow_night";
316+ } else if (theme == 'ayu') {
317+ stylesheets.ayuHighlight.disabled = false;
318+ stylesheets.tomorrowNight.disabled = true;
319+ stylesheets.highlight.disabled = true;
320+ ace_theme = "ace/theme/tomorrow_night";
321+ } else {
322+ stylesheets.ayuHighlight.disabled = true;
323+ stylesheets.tomorrowNight.disabled = true;
324+ stylesheets.highlight.disabled = false;
325+ ace_theme = "ace/theme/dawn";
326+ }
327+
328+ setTimeout(function () {
329+ themeColorMetaTag.content = getComputedStyle(document.body).backgroundColor;
330+ }, 1);
331+
332+ if (window.ace && window.editors) {
333+ window.editors.forEach(function (editor) {
334+ editor.setTheme(ace_theme);
335+ });
336+ }
337+
338+ var previousTheme = get_theme();
339+
340+ if (store) {
341+ try { localStorage.setItem('mdbook-theme', theme); } catch (e) { }
342+ }
343+
344+ html.classList.remove(previousTheme);
345+ html.classList.add(theme);
346+ }
347+
348+ // Set theme
349+ var theme = get_theme();
350+
351+ set_theme(theme, false);
352+
353+ themeToggleButton.addEventListener('click', function () {
354+ if (themePopup.style.display === 'block') {
355+ hideThemes();
356+ } else {
357+ showThemes();
358+ }
359+ });
360+
361+ themePopup.addEventListener('click', function (e) {
362+ var theme = e.target.id || e.target.parentElement.id;
363+ set_theme(theme);
364+ });
365+
366+ themePopup.addEventListener('focusout', function(e) {
367+ // e.relatedTarget is null in Safari and Firefox on macOS (see workaround below)
368+ if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) {
369+ hideThemes();
370+ }
371+ });
372+
373+ // Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628
374+ document.addEventListener('click', function(e) {
375+ if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) {
376+ hideThemes();
377+ }
378+ });
379+
380+ document.addEventListener('keydown', function (e) {
381+ if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
382+ if (!themePopup.contains(e.target)) { return; }
383+
384+ switch (e.key) {
385+ case 'Escape':
386+ e.preventDefault();
387+ hideThemes();
388+ break;
389+ case 'ArrowUp':
390+ e.preventDefault();
391+ var li = document.activeElement.parentElement;
392+ if (li && li.previousElementSibling) {
393+ li.previousElementSibling.querySelector('button').focus();
394+ }
395+ break;
396+ case 'ArrowDown':
397+ e.preventDefault();
398+ var li = document.activeElement.parentElement;
399+ if (li && li.nextElementSibling) {
400+ li.nextElementSibling.querySelector('button').focus();
401+ }
402+ break;
403+ case 'Home':
404+ e.preventDefault();
405+ themePopup.querySelector('li:first-child button').focus();
406+ break;
407+ case 'End':
408+ e.preventDefault();
409+ themePopup.querySelector('li:last-child button').focus();
410+ break;
411+ }
412+ });
413+})();
414+
415+(function sidebar() {
416+ var html = document.querySelector("html");
417+ var sidebar = document.getElementById("sidebar");
418+ var sidebarLinks = document.querySelectorAll('#sidebar a');
419+ var sidebarToggleButton = document.getElementById("sidebar-toggle");
420+ var sidebarResizeHandle = document.getElementById("sidebar-resize-handle");
421+ var firstContact = null;
422+
423+ function showSidebar() {
424+ html.classList.remove('sidebar-hidden')
425+ html.classList.add('sidebar-visible');
426+ Array.from(sidebarLinks).forEach(function (link) {
427+ link.setAttribute('tabIndex', 0);
428+ });
429+ sidebarToggleButton.setAttribute('aria-expanded', true);
430+ sidebar.setAttribute('aria-hidden', false);
431+ try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { }
432+ }
433+
434+
435+ var sidebarAnchorToggles = document.querySelectorAll('#sidebar a.toggle');
436+
437+ function toggleSection(ev) {
438+ ev.currentTarget.parentElement.classList.toggle('expanded');
439+ }
440+
441+ Array.from(sidebarAnchorToggles).forEach(function (el) {
442+ el.addEventListener('click', toggleSection);
443+ });
444+
445+ function hideSidebar() {
446+ html.classList.remove('sidebar-visible')
447+ html.classList.add('sidebar-hidden');
448+ Array.from(sidebarLinks).forEach(function (link) {
449+ link.setAttribute('tabIndex', -1);
450+ });
451+ sidebarToggleButton.setAttribute('aria-expanded', false);
452+ sidebar.setAttribute('aria-hidden', true);
453+ try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { }
454+ }
455+
456+ // Toggle sidebar
457+ sidebarToggleButton.addEventListener('click', function sidebarToggle() {
458+ if (html.classList.contains("sidebar-hidden")) {
459+ var current_width = parseInt(
460+ document.documentElement.style.getPropertyValue('--sidebar-width'), 10);
461+ if (current_width < 150) {
462+ document.documentElement.style.setProperty('--sidebar-width', '150px');
463+ }
464+ showSidebar();
465+ } else if (html.classList.contains("sidebar-visible")) {
466+ hideSidebar();
467+ } else {
468+ if (getComputedStyle(sidebar)['transform'] === 'none') {
469+ hideSidebar();
470+ } else {
471+ showSidebar();
472+ }
473+ }
474+ });
475+
476+ sidebarResizeHandle.addEventListener('mousedown', initResize, false);
477+
478+ function initResize(e) {
479+ window.addEventListener('mousemove', resize, false);
480+ window.addEventListener('mouseup', stopResize, false);
481+ html.classList.add('sidebar-resizing');
482+ }
483+ function resize(e) {
484+ var pos = (e.clientX - sidebar.offsetLeft);
485+ if (pos < 20) {
486+ hideSidebar();
487+ } else {
488+ if (html.classList.contains("sidebar-hidden")) {
489+ showSidebar();
490+ }
491+ pos = Math.min(pos, window.innerWidth - 100);
492+ document.documentElement.style.setProperty('--sidebar-width', pos + 'px');
493+ }
494+ }
495+ //on mouseup remove windows functions mousemove & mouseup
496+ function stopResize(e) {
497+ html.classList.remove('sidebar-resizing');
498+ window.removeEventListener('mousemove', resize, false);
499+ window.removeEventListener('mouseup', stopResize, false);
500+ }
501+
502+ document.addEventListener('touchstart', function (e) {
503+ firstContact = {
504+ x: e.touches[0].clientX,
505+ time: Date.now()
506+ };
507+ }, { passive: true });
508+
509+ document.addEventListener('touchmove', function (e) {
510+ if (!firstContact)
511+ return;
512+
513+ var curX = e.touches[0].clientX;
514+ var xDiff = curX - firstContact.x,
515+ tDiff = Date.now() - firstContact.time;
516+
517+ if (tDiff < 250 && Math.abs(xDiff) >= 150) {
518+ if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300))
519+ showSidebar();
520+ else if (xDiff < 0 && curX < 300)
521+ hideSidebar();
522+
523+ firstContact = null;
524+ }
525+ }, { passive: true });
526+
527+ // Scroll sidebar to current active section
528+ var activeSection = document.getElementById("sidebar").querySelector(".active");
529+ if (activeSection) {
530+ // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
531+ activeSection.scrollIntoView({ block: 'center' });
532+ }
533+})();
534+
535+(function chapterNavigation() {
536+ document.addEventListener('keydown', function (e) {
537+ if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
538+ if (window.search && window.search.hasFocus()) { return; }
539+
540+ switch (e.key) {
541+ case 'ArrowRight':
542+ e.preventDefault();
543+ var nextButton = document.querySelector('.nav-chapters.next');
544+ if (nextButton) {
545+ window.location.href = nextButton.href;
546+ }
547+ break;
548+ case 'ArrowLeft':
549+ e.preventDefault();
550+ var previousButton = document.querySelector('.nav-chapters.previous');
551+ if (previousButton) {
552+ window.location.href = previousButton.href;
553+ }
554+ break;
555+ }
556+ });
557+})();
558+
559+(function clipboard() {
560+ var clipButtons = document.querySelectorAll('.clip-button');
561+
562+ function hideTooltip(elem) {
563+ elem.firstChild.innerText = "";
564+ elem.className = 'fa fa-copy clip-button';
565+ }
566+
567+ function showTooltip(elem, msg) {
568+ elem.firstChild.innerText = msg;
569+ elem.className = 'fa fa-copy tooltipped';
570+ }
571+
572+ var clipboardSnippets = new ClipboardJS('.clip-button', {
573+ text: function (trigger) {
574+ hideTooltip(trigger);
575+ let playground = trigger.closest("pre");
576+ return playground_text(playground);
577+ }
578+ });
579+
580+ Array.from(clipButtons).forEach(function (clipButton) {
581+ clipButton.addEventListener('mouseout', function (e) {
582+ hideTooltip(e.currentTarget);
583+ });
584+ });
585+
586+ clipboardSnippets.on('success', function (e) {
587+ e.clearSelection();
588+ showTooltip(e.trigger, "Copied!");
589+ });
590+
591+ clipboardSnippets.on('error', function (e) {
592+ showTooltip(e.trigger, "Clipboard error!");
593+ });
594+})();
595+
596+(function scrollToTop () {
597+ var menuTitle = document.querySelector('.menu-title');
598+
599+ menuTitle.addEventListener('click', function () {
600+ document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' });
601+ });
602+})();
603+
604+(function controllMenu() {
605+ var menu = document.getElementById('menu-bar');
606+
607+ (function controllPosition() {
608+ var scrollTop = document.scrollingElement.scrollTop;
609+ var prevScrollTop = scrollTop;
610+ var minMenuY = -menu.clientHeight - 50;
611+ // When the script loads, the page can be at any scroll (e.g. if you reforesh it).
612+ menu.style.top = scrollTop + 'px';
613+ // Same as parseInt(menu.style.top.slice(0, -2), but faster
614+ var topCache = menu.style.top.slice(0, -2);
615+ menu.classList.remove('sticky');
616+ var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster
617+ document.addEventListener('scroll', function () {
618+ scrollTop = Math.max(document.scrollingElement.scrollTop, 0);
619+ // `null` means that it doesn't need to be updated
620+ var nextSticky = null;
621+ var nextTop = null;
622+ var scrollDown = scrollTop > prevScrollTop;
623+ var menuPosAbsoluteY = topCache - scrollTop;
624+ if (scrollDown) {
625+ nextSticky = false;
626+ if (menuPosAbsoluteY > 0) {
627+ nextTop = prevScrollTop;
628+ }
629+ } else {
630+ if (menuPosAbsoluteY > 0) {
631+ nextSticky = true;
632+ } else if (menuPosAbsoluteY < minMenuY) {
633+ nextTop = prevScrollTop + minMenuY;
634+ }
635+ }
636+ if (nextSticky === true && stickyCache === false) {
637+ menu.classList.add('sticky');
638+ stickyCache = true;
639+ } else if (nextSticky === false && stickyCache === true) {
640+ menu.classList.remove('sticky');
641+ stickyCache = false;
642+ }
643+ if (nextTop !== null) {
644+ menu.style.top = nextTop + 'px';
645+ topCache = nextTop;
646+ }
647+ prevScrollTop = scrollTop;
648+ }, { passive: true });
649+ })();
650+ (function controllBorder() {
651+ menu.classList.remove('bordered');
652+ document.addEventListener('scroll', function () {
653+ if (menu.offsetTop === 0) {
654+ menu.classList.remove('bordered');
655+ } else {
656+ menu.classList.add('bordered');
657+ }
658+ }, { passive: true });
659+ })();
660+})();
book/theme/css/chrome.cssnew file+499
@@ -0,0 +1,499 @@
1+/* CSS for UI elements (a.k.a. chrome) */
2+
3+@import 'variables.css';
4+
5+::-webkit-scrollbar {
6+ background: var(--bg);
7+}
8+::-webkit-scrollbar-thumb {
9+ background: var(--scrollbar);
10+}
11+html {
12+ scrollbar-color: var(--scrollbar) var(--bg);
13+}
14+#searchresults a,
15+.content a:link,
16+a:visited,
17+a > .hljs {
18+ color: var(--links);
19+}
20+.content a:hover {
21+ text-decoration: underline;
22+}
23+
24+/* Menu Bar */
25+
26+#menu-bar,
27+#menu-bar-hover-placeholder {
28+ z-index: 101;
29+ margin: auto calc(0px - var(--page-padding));
30+}
31+#menu-bar {
32+ position: relative;
33+ display: flex;
34+ flex-wrap: wrap;
35+ background-color: var(--bg);
36+ border-bottom-color: var(--bg);
37+ border-bottom-width: 1px;
38+ border-bottom-style: solid;
39+}
40+#menu-bar.sticky,
41+.js #menu-bar-hover-placeholder:hover + #menu-bar,
42+.js #menu-bar:hover,
43+.js.sidebar-visible #menu-bar {
44+ position: -webkit-sticky;
45+ position: sticky;
46+ top: 0 !important;
47+}
48+#menu-bar-hover-placeholder {
49+ position: sticky;
50+ position: -webkit-sticky;
51+ top: 0;
52+ height: var(--menu-bar-height);
53+}
54+#menu-bar.bordered {
55+ border-bottom-color: var(--table-border-color);
56+}
57+#menu-bar i, #menu-bar .icon-button {
58+ position: relative;
59+ padding: 0 8px;
60+ z-index: 10;
61+ line-height: var(--menu-bar-height);
62+ cursor: pointer;
63+ transition: color 0.5s;
64+}
65+@media only screen and (max-width: 420px) {
66+ #menu-bar i, #menu-bar .icon-button {
67+ padding: 0 5px;
68+ }
69+}
70+
71+.icon-button {
72+ border: none;
73+ background: none;
74+ padding: 0;
75+ color: inherit;
76+}
77+.icon-button i {
78+ margin: 0;
79+}
80+
81+.right-buttons {
82+ margin: 0 15px;
83+}
84+.right-buttons a {
85+ text-decoration: none;
86+}
87+
88+.left-buttons {
89+ display: flex;
90+ margin: 0 5px;
91+}
92+.no-js .left-buttons {
93+ display: none;
94+}
95+
96+.menu-title {
97+ display: inline-block;
98+ font-weight: 200;
99+ font-size: 2.4rem;
100+ line-height: var(--menu-bar-height);
101+ text-align: center;
102+ margin: 0;
103+ flex: 1;
104+ white-space: nowrap;
105+ overflow: hidden;
106+ text-overflow: ellipsis;
107+}
108+.js .menu-title {
109+ cursor: pointer;
110+}
111+
112+.menu-bar,
113+.menu-bar:visited,
114+.nav-chapters,
115+.nav-chapters:visited,
116+.mobile-nav-chapters,
117+.mobile-nav-chapters:visited,
118+.menu-bar .icon-button,
119+.menu-bar a i {
120+ color: var(--icons);
121+}
122+
123+.menu-bar i:hover,
124+.menu-bar .icon-button:hover,
125+.nav-chapters:hover,
126+.mobile-nav-chapters i:hover {
127+ color: var(--icons-hover);
128+}
129+
130+/* Nav Icons */
131+
132+.nav-chapters {
133+ font-size: 2.5em;
134+ text-align: center;
135+ text-decoration: none;
136+
137+ position: fixed;
138+ top: 0;
139+ bottom: 0;
140+ margin: 0;
141+ max-width: 150px;
142+ min-width: 90px;
143+
144+ display: flex;
145+ justify-content: center;
146+ align-content: center;
147+ flex-direction: column;
148+
149+ transition: color 0.5s, background-color 0.5s;
150+}
151+
152+.nav-chapters:hover {
153+ text-decoration: none;
154+ background-color: var(--theme-hover);
155+ transition: background-color 0.15s, color 0.15s;
156+}
157+
158+.nav-wrapper {
159+ margin-top: 50px;
160+ display: none;
161+}
162+
163+.mobile-nav-chapters {
164+ font-size: 2.5em;
165+ text-align: center;
166+ text-decoration: none;
167+ width: 90px;
168+ border-radius: 5px;
169+ background-color: var(--sidebar-bg);
170+}
171+
172+.previous {
173+ float: left;
174+}
175+
176+.next {
177+ float: right;
178+ right: var(--page-padding);
179+}
180+
181+@media only screen and (max-width: 1080px) {
182+ .nav-wide-wrapper { display: none; }
183+ .nav-wrapper { display: block; }
184+}
185+
186+@media only screen and (max-width: 1380px) {
187+ .sidebar-visible .nav-wide-wrapper { display: none; }
188+ .sidebar-visible .nav-wrapper { display: block; }
189+}
190+
191+/* Inline code */
192+
193+:not(pre) > .hljs {
194+ display: inline;
195+ padding: 0.1em 0.3em;
196+ border-radius: 3px;
197+}
198+
199+:not(pre):not(a):not(td):not(p) > .hljs {
200+ color: var(--inline-code-color);
201+ overflow-x: initial;
202+}
203+
204+a:hover > .hljs {
205+ text-decoration: underline;
206+}
207+
208+pre {
209+ position: relative;
210+}
211+pre > .buttons {
212+ position: absolute;
213+ z-index: 100;
214+ right: 5px;
215+ top: 5px;
216+
217+ color: var(--sidebar-fg);
218+ cursor: pointer;
219+}
220+pre > .buttons :hover {
221+ color: var(--sidebar-active);
222+}
223+pre > .buttons i {
224+ margin-left: 8px;
225+}
226+pre > .buttons button {
227+ color: inherit;
228+ background: transparent;
229+ border: none;
230+ cursor: inherit;
231+}
232+pre > .result {
233+ margin-top: 10px;
234+}
235+
236+/* Search */
237+
238+#searchresults a {
239+ text-decoration: none;
240+}
241+
242+mark {
243+ border-radius: 2px;
244+ padding: 0 3px 1px 3px;
245+ margin: 0 -3px -1px -3px;
246+ background-color: var(--search-mark-bg);
247+ transition: background-color 300ms linear;
248+ cursor: pointer;
249+}
250+
251+mark.fade-out {
252+ background-color: rgba(0,0,0,0) !important;
253+ cursor: auto;
254+}
255+
256+.searchbar-outer {
257+ margin-left: auto;
258+ margin-right: auto;
259+ max-width: var(--content-max-width);
260+}
261+
262+#searchbar {
263+ width: 100%;
264+ margin: 5px auto 0px auto;
265+ padding: 10px 16px;
266+ transition: box-shadow 300ms ease-in-out;
267+ border: 1px solid var(--searchbar-border-color);
268+ border-radius: 3px;
269+ background-color: var(--searchbar-bg);
270+ color: var(--searchbar-fg);
271+}
272+#searchbar:focus,
273+#searchbar.active {
274+ box-shadow: 0 0 3px var(--searchbar-shadow-color);
275+}
276+
277+.searchresults-header {
278+ font-weight: bold;
279+ font-size: 1em;
280+ padding: 18px 0 0 5px;
281+ color: var(--searchresults-header-fg);
282+}
283+
284+.searchresults-outer {
285+ margin-left: auto;
286+ margin-right: auto;
287+ max-width: var(--content-max-width);
288+ border-bottom: 1px dashed var(--searchresults-border-color);
289+}
290+
291+ul#searchresults {
292+ list-style: none;
293+ padding-left: 20px;
294+}
295+ul#searchresults li {
296+ margin: 10px 0px;
297+ padding: 2px;
298+ border-radius: 2px;
299+}
300+ul#searchresults li.focus {
301+ background-color: var(--searchresults-li-bg);
302+}
303+ul#searchresults span.teaser {
304+ display: block;
305+ clear: both;
306+ margin: 5px 0 0 20px;
307+ font-size: 0.8em;
308+}
309+ul#searchresults span.teaser em {
310+ font-weight: bold;
311+ font-style: normal;
312+}
313+
314+/* Sidebar */
315+
316+.sidebar {
317+ position: fixed;
318+ left: 0;
319+ top: 0;
320+ bottom: 0;
321+ width: var(--sidebar-width);
322+ font-size: 0.875em;
323+ box-sizing: border-box;
324+ -webkit-overflow-scrolling: touch;
325+ overscroll-behavior-y: contain;
326+ background-color: var(--sidebar-bg);
327+ color: var(--sidebar-fg);
328+}
329+.sidebar-resizing {
330+ -moz-user-select: none;
331+ -webkit-user-select: none;
332+ -ms-user-select: none;
333+ user-select: none;
334+}
335+.js:not(.sidebar-resizing) .sidebar {
336+ transition: transform 0.3s; /* Animation: slide away */
337+}
338+.sidebar code {
339+ line-height: 2em;
340+}
341+.sidebar .sidebar-scrollbox {
342+ overflow-y: auto;
343+ position: absolute;
344+ top: 0;
345+ bottom: 0;
346+ left: 0;
347+ right: 0;
348+}
349+.sidebar .sidebar-resize-handle {
350+ position: absolute;
351+ cursor: col-resize;
352+ width: 0;
353+ right: 0;
354+ top: 0;
355+ bottom: 0;
356+}
357+.js .sidebar .sidebar-resize-handle {
358+ cursor: col-resize;
359+ width: 5px;
360+}
361+.sidebar-hidden .sidebar {
362+ transform: translateX(calc(0px - var(--sidebar-width)));
363+}
364+.sidebar::-webkit-scrollbar {
365+ background: var(--sidebar-bg);
366+}
367+.sidebar::-webkit-scrollbar-thumb {
368+ background: var(--scrollbar);
369+}
370+
371+.sidebar-visible .page-wrapper {
372+ transform: translateX(var(--sidebar-width));
373+}
374+@media only screen and (min-width: 620px) {
375+ .sidebar-visible .page-wrapper {
376+ transform: none;
377+ margin-left: var(--sidebar-width);
378+ }
379+}
380+
381+.chapter {
382+ list-style: none outside none;
383+ padding-left: 0;
384+ margin: .25rem 0;
385+}
386+
387+.chapter ol {
388+ width: 100%;
389+}
390+
391+.chapter li {
392+ display: flex;
393+ color: var(--sidebar-non-existant);
394+}
395+.chapter li a {
396+ display: block;
397+ text-decoration: none;
398+ color: var(--sidebar-fg);
399+}
400+
401+.chapter li a:hover {
402+ color: var(--sidebar-active);
403+}
404+
405+.chapter li a.active {
406+ color: var(--sidebar-active);
407+}
408+
409+.chapter li > a.toggle {
410+ cursor: pointer;
411+ display: block;
412+ margin-left: auto;
413+ padding: 0 10px;
414+ user-select: none;
415+ opacity: 0.68;
416+}
417+
418+.chapter li > a.toggle div {
419+ transition: transform 0.5s;
420+}
421+
422+/* collapse the section */
423+.chapter li:not(.expanded) + li > ol {
424+ display: none;
425+}
426+
427+.chapter li.chapter-item {
428+ padding: 1rem 1.5rem;
429+}
430+
431+.chapter .section li.chapter-item {
432+ padding: .5rem .5rem 0 .5rem;
433+}
434+
435+.chapter li.expanded > a.toggle div {
436+ transform: rotate(90deg);
437+}
438+
439+.spacer {
440+ width: 100%;
441+ height: 3px;
442+ margin: 5px 0px;
443+}
444+.chapter .spacer {
445+ background-color: var(--sidebar-spacer);
446+}
447+
448+@media (-moz-touch-enabled: 1), (pointer: coarse) {
449+ .chapter li a { padding: 5px 0; }
450+ .spacer { margin: 10px 0; }
451+}
452+
453+.section {
454+ list-style: none outside none;
455+ padding-left: 2rem;
456+ line-height: 1.9em;
457+}
458+
459+/* Theme Menu Popup */
460+
461+.theme-popup {
462+ position: absolute;
463+ left: 10px;
464+ top: var(--menu-bar-height);
465+ z-index: 1000;
466+ border-radius: 4px;
467+ font-size: 0.7em;
468+ color: var(--fg);
469+ background: var(--theme-popup-bg);
470+ border: 1px solid var(--theme-popup-border);
471+ margin: 0;
472+ padding: 0;
473+ list-style: none;
474+ display: none;
475+}
476+.theme-popup .default {
477+ color: var(--icons);
478+}
479+.theme-popup .theme {
480+ width: 100%;
481+ border: 0;
482+ margin: 0;
483+ padding: 2px 10px;
484+ line-height: 25px;
485+ white-space: nowrap;
486+ text-align: left;
487+ cursor: pointer;
488+ color: inherit;
489+ background: inherit;
490+ font-size: inherit;
491+}
492+.theme-popup .theme:hover {
493+ background-color: var(--theme-hover);
494+}
495+.theme-popup .theme:hover:first-child,
496+.theme-popup .theme:hover:last-child {
497+ border-top-left-radius: inherit;
498+ border-top-right-radius: inherit;
499+}
book/theme/css/general.cssnew file+233
@@ -0,0 +1,233 @@
1+/* Base styles and content styles */
2+
3+@import 'variables.css';
4+
5+:root {
6+ /* Browser default font-size is 16px, this way 1 rem = 10px */
7+ font-size: 62.5%;
8+}
9+
10+/* TODO: replace with self hosted fonts */
11+
12+html {
13+ font-family: "Inter", sans-serif;
14+ color: var(--fg);
15+ background-color: var(--bg);
16+ text-size-adjust: none;
17+}
18+
19+/* @supports (font-variation-settings: normal) { */
20+/* html { font-family: 'Inter var', sans-serif; } */
21+/* } */
22+
23+body {
24+ margin: 0;
25+ font-size: 1.6rem;
26+ overflow-x: hidden;
27+}
28+
29+code {
30+ font-family: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace !important;
31+ font-size: 0.875em; /* please adjust the ace font size accordingly in editor.js */
32+}
33+
34+/* Don't change font size in headers. */
35+h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
36+ font-size: unset;
37+}
38+
39+.left { float: left; }
40+.right { float: right; }
41+.boring { opacity: 0.6; }
42+.hide-boring .boring { display: none; }
43+.hidden { display: none !important; }
44+
45+h2, h3 { margin-top: 2.5em; }
46+h4, h5 { margin-top: 2em; }
47+
48+.header + .header h3,
49+.header + .header h4,
50+.header + .header h5 {
51+ margin-top: 1em;
52+}
53+
54+h1:target::before,
55+h2:target::before,
56+h3:target::before,
57+h4:target::before,
58+h5:target::before,
59+h6:target::before {
60+ display: inline-block;
61+ content: "»";
62+ margin-left: -30px;
63+ width: 30px;
64+}
65+
66+/* This is broken on Safari as of version 14, but is fixed
67+ in Safari Technology Preview 117 which I think will be Safari 14.2.
68+ https://bugs.webkit.org/show_bug.cgi?id=218076
69+*/
70+:target {
71+ scroll-margin-top: calc(var(--menu-bar-height) + 0.5em);
72+}
73+
74+.page {
75+ outline: 0;
76+ padding: 0 var(--page-padding);
77+ margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */
78+}
79+.page-wrapper {
80+ box-sizing: border-box;
81+}
82+.js:not(.sidebar-resizing) .page-wrapper {
83+ transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */
84+}
85+
86+.content {
87+ overflow-y: auto;
88+ padding: 0 15px;
89+ padding-bottom: 50px;
90+}
91+.content main {
92+ margin-left: auto;
93+ margin-right: auto;
94+ max-width: var(--content-max-width);
95+}
96+
97+
98+/* 2 1.75 1.5 1.25 1 .875 */
99+
100+.content h1 { font-size: 2em }
101+.content h2 { font-size: 1.75em }
102+.content h3 { font-size: 1.5em }
103+.content h4 { font-size: 1.25em }
104+.content h5 { font-size: 1em }
105+.content h6 { font-size: .875em }
106+
107+.content h1, .content h2, .content h3, .content h4 {
108+ font-weight: 500;
109+ margin-top: 1.275em;
110+ margin-bottom: .875em;
111+}
112+.content p, .content ol, .content ul, .content table {
113+ margin-top: 0;
114+ margin-bottom: .875em;
115+}
116+
117+.content ul li {
118+margin-bottom: .25rem;
119+}
120+.content ul {
121+ list-style-type: square;
122+}
123+.content ul ul, .content ol ul {
124+ margin-bottom: .5rem;
125+}
126+.content li p {
127+ margin-bottom: .5em;
128+}
129+
130+.content p { line-height: 1.45em; }
131+.content ol { line-height: 1.45em; }
132+.content ul { line-height: 1.45em; }
133+.content a { text-decoration: none; }
134+.content a:hover { text-decoration: underline; }
135+.content img { max-width: 100%; }
136+.content .header:link,
137+.content .header:visited {
138+ color: var(--fg);
139+ color: var(--heading-fg);
140+}
141+.content .header:link,
142+.content .header:visited:hover {
143+ text-decoration: none;
144+}
145+
146+table {
147+ margin: 0 auto;
148+ border-collapse: collapse;
149+ width: 100%;
150+}
151+table td {
152+ padding: .75rem;
153+ width: auto;
154+}
155+table thead {
156+ background: var(--table-header-bg);
157+}
158+table thead td {
159+ font-weight: 700;
160+ border: none;
161+}
162+table thead th {
163+ padding: .75rem;
164+ text-align: left;
165+ font-weight: 500;
166+ line-height: 1.5;
167+ width: auto;
168+}
169+table thead tr {
170+ border-bottom: 2px var(--table-border-color) solid;
171+}
172+table tbody tr {
173+ border-bottom: 1px var(--table-border-line) solid;
174+}
175+/* Alternate background colors for rows */
176+table tbody tr:nth-child(2n) {
177+ /* background: var(--table-alternate-bg); */
178+}
179+
180+
181+blockquote {
182+ margin: 1.5rem 0;
183+ padding: 1rem 1.5rem;
184+ color: var(--fg);
185+ opacity: .9;
186+ background-color: var(--quote-bg);
187+ border-left: 4px solid var(--quote-border);
188+}
189+blockquote *:last-child {
190+ margin-bottom: 0;
191+}
192+
193+
194+:not(.footnote-definition) + .footnote-definition,
195+.footnote-definition + :not(.footnote-definition) {
196+ margin-top: 2em;
197+}
198+.footnote-definition {
199+ font-size: 0.9em;
200+ margin: 0.5em 0;
201+}
202+.footnote-definition p {
203+ display: inline;
204+}
205+
206+.tooltiptext {
207+ position: absolute;
208+ visibility: hidden;
209+ color: #fff;
210+ background-color: #333;
211+ transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */
212+ left: -8px; /* Half of the width of the icon */
213+ top: -35px;
214+ font-size: 0.8em;
215+ text-align: center;
216+ border-radius: 6px;
217+ padding: 5px 8px;
218+ margin: 5px;
219+ z-index: 1000;
220+}
221+.tooltipped .tooltiptext {
222+ visibility: visible;
223+}
224+
225+.chapter li.part-title {
226+ color: var(--sidebar-fg);
227+ margin: 5px 0px;
228+ font-weight: bold;
229+}
230+
231+.result-no-output {
232+ font-style: italic;
233+}
book/theme/css/print.cssnew file+54
@@ -0,0 +1,54 @@
1+
2+#sidebar,
3+#menu-bar,
4+.nav-chapters,
5+.mobile-nav-chapters {
6+ display: none;
7+}
8+
9+#page-wrapper.page-wrapper {
10+ transform: none;
11+ margin-left: 0px;
12+ overflow-y: initial;
13+}
14+
15+#content {
16+ max-width: none;
17+ margin: 0;
18+ padding: 0;
19+}
20+
21+.page {
22+ overflow-y: initial;
23+}
24+
25+code {
26+ background-color: #666666;
27+ border-radius: 5px;
28+
29+ /* Force background to be printed in Chrome */
30+ -webkit-print-color-adjust: exact;
31+}
32+
33+pre > .buttons {
34+ z-index: 2;
35+}
36+
37+a, a:visited, a:active, a:hover {
38+ color: #4183c4;
39+ text-decoration: none;
40+}
41+
42+h1, h2, h3, h4, h5, h6 {
43+ page-break-inside: avoid;
44+ page-break-after: avoid;
45+}
46+
47+pre, code {
48+ page-break-inside: avoid;
49+ white-space: pre-wrap;
50+}
51+
52+.fa {
53+ display: none !important;
54+}
book/theme/css/variables.cssnew file+342
@@ -0,0 +1,342 @@
1+
2+/* Globals */
3+
4+:root {
5+ --sidebar-width: 300px;
6+ --page-padding: 15px;
7+ --content-max-width: 750px;
8+ --menu-bar-height: 50px;
9+}
10+
11+/* Themes */
12+
13+.ayu {
14+ --bg: hsl(210, 25%, 8%);
15+ --fg: #c5c5c5;
16+
17+ --sidebar-bg: #14191f;
18+ --sidebar-fg: #c8c9db;
19+ --sidebar-non-existant: #5c6773;
20+ --sidebar-active: #ffb454;
21+ --sidebar-spacer: #2d334f;
22+
23+ --scrollbar: var(--sidebar-fg);
24+
25+ --icons: #737480;
26+ --icons-hover: #b7b9cc;
27+
28+ --links: #0096cf;
29+
30+ --inline-code-color: #ffb454;
31+
32+ --theme-popup-bg: #14191f;
33+ --theme-popup-border: #5c6773;
34+ --theme-hover: #191f26;
35+
36+ --quote-bg: hsl(226, 15%, 17%);
37+ --quote-border: hsl(226, 15%, 22%);
38+
39+ --table-border-color: hsl(210, 25%, 13%);
40+ --table-header-bg: hsl(210, 25%, 28%);
41+ --table-alternate-bg: hsl(210, 25%, 11%);
42+
43+ --searchbar-border-color: #848484;
44+ --searchbar-bg: #424242;
45+ --searchbar-fg: #fff;
46+ --searchbar-shadow-color: #d4c89f;
47+ --searchresults-header-fg: #666;
48+ --searchresults-border-color: #888;
49+ --searchresults-li-bg: #252932;
50+ --search-mark-bg: #e3b171;
51+}
52+
53+.coal {
54+ --bg: hsl(200, 7%, 8%);
55+ --fg: #98a3ad;
56+
57+ --sidebar-bg: #292c2f;
58+ --sidebar-fg: #a1adb8;
59+ --sidebar-non-existant: #505254;
60+ --sidebar-active: #3473ad;
61+ --sidebar-spacer: #393939;
62+
63+ --scrollbar: var(--sidebar-fg);
64+
65+ --icons: #43484d;
66+ --icons-hover: #b3c0cc;
67+
68+ --links: #2b79a2;
69+
70+ --inline-code-color: #c5c8c6;
71+
72+ --theme-popup-bg: #141617;
73+ --theme-popup-border: #43484d;
74+ --theme-hover: #1f2124;
75+
76+ --quote-bg: hsl(234, 21%, 18%);
77+ --quote-border: hsl(234, 21%, 23%);
78+
79+ --table-border-color: hsl(200, 7%, 13%);
80+ --table-header-bg: hsl(200, 7%, 28%);
81+ --table-alternate-bg: hsl(200, 7%, 11%);
82+
83+ --searchbar-border-color: #aaa;
84+ --searchbar-bg: #b7b7b7;
85+ --searchbar-fg: #000;
86+ --searchbar-shadow-color: #aaa;
87+ --searchresults-header-fg: #666;
88+ --searchresults-border-color: #98a3ad;
89+ --searchresults-li-bg: #2b2b2f;
90+ --search-mark-bg: #355c7d;
91+}
92+
93+.light {
94+ --bg: hsl(0, 0%, 100%);
95+ --fg: hsl(0, 0%, 0%);
96+
97+ --sidebar-bg: #fafafa;
98+ --sidebar-fg: hsl(0, 0%, 0%);
99+ --sidebar-non-existant: #aaaaaa;
100+ --sidebar-active: #1f1fff;
101+ --sidebar-spacer: #f4f4f4;
102+
103+ --scrollbar: #8F8F8F;
104+
105+ --icons: #747474;
106+ --icons-hover: #000000;
107+
108+ --links: #20609f;
109+
110+ --inline-code-color: #301900;
111+
112+ --theme-popup-bg: #fafafa;
113+ --theme-popup-border: #cccccc;
114+ --theme-hover: #e6e6e6;
115+
116+ --quote-bg: hsl(197, 37%, 96%);
117+ --quote-border: hsl(197, 37%, 91%);
118+
119+ --table-border-color: hsl(0, 0%, 95%);
120+ --table-header-bg: hsl(0, 0%, 80%);
121+ --table-alternate-bg: hsl(0, 0%, 97%);
122+
123+ --searchbar-border-color: #aaa;
124+ --searchbar-bg: #fafafa;
125+ --searchbar-fg: #000;
126+ --searchbar-shadow-color: #aaa;
127+ --searchresults-header-fg: #666;
128+ --searchresults-border-color: #888;
129+ --searchresults-li-bg: #e4f2fe;
130+ --search-mark-bg: #a2cff5;
131+}
132+
133+.navy {
134+ --bg: hsl(226, 23%, 11%);
135+ --fg: #bcbdd0;
136+
137+ --sidebar-bg: #282d3f;
138+ --sidebar-fg: #c8c9db;
139+ --sidebar-non-existant: #505274;
140+ --sidebar-active: #2b79a2;
141+ --sidebar-spacer: #2d334f;
142+
143+ --scrollbar: var(--sidebar-fg);
144+
145+ --icons: #737480;
146+ --icons-hover: #b7b9cc;
147+
148+ --links: #2b79a2;
149+
150+ --inline-code-color: #c5c8c6;
151+
152+ --theme-popup-bg: #161923;
153+ --theme-popup-border: #737480;
154+ --theme-hover: #282e40;
155+
156+ --quote-bg: hsl(226, 15%, 17%);
157+ --quote-border: hsl(226, 15%, 22%);
158+
159+ --table-border-color: hsl(226, 23%, 16%);
160+ --table-header-bg: hsl(226, 23%, 31%);
161+ --table-alternate-bg: hsl(226, 23%, 14%);
162+
163+ --searchbar-border-color: #aaa;
164+ --searchbar-bg: #aeaec6;
165+ --searchbar-fg: #000;
166+ --searchbar-shadow-color: #aaa;
167+ --searchresults-header-fg: #5f5f71;
168+ --searchresults-border-color: #5c5c68;
169+ --searchresults-li-bg: #242430;
170+ --search-mark-bg: #a2cff5;
171+}
172+
173+.rust {
174+ --bg: hsl(60, 9%, 87%);
175+ --fg: #262625;
176+
177+ --sidebar-bg: #3b2e2a;
178+ --sidebar-fg: #c8c9db;
179+ --sidebar-non-existant: #505254;
180+ --sidebar-active: #e69f67;
181+ --sidebar-spacer: #45373a;
182+
183+ --scrollbar: var(--sidebar-fg);
184+
185+ --icons: #737480;
186+ --icons-hover: #262625;
187+
188+ --links: #2b79a2;
189+
190+ --inline-code-color: #6e6b5e;
191+
192+ --theme-popup-bg: #e1e1db;
193+ --theme-popup-border: #b38f6b;
194+ --theme-hover: #99908a;
195+
196+ --quote-bg: hsl(60, 5%, 75%);
197+ --quote-border: hsl(60, 5%, 70%);
198+
199+ --table-border-color: hsl(60, 9%, 82%);
200+ --table-header-bg: #b3a497;
201+ --table-alternate-bg: hsl(60, 9%, 84%);
202+
203+ --searchbar-border-color: #aaa;
204+ --searchbar-bg: #fafafa;
205+ --searchbar-fg: #000;
206+ --searchbar-shadow-color: #aaa;
207+ --searchresults-header-fg: #666;
208+ --searchresults-border-color: #888;
209+ --searchresults-li-bg: #dec2a2;
210+ --search-mark-bg: #e69f67;
211+}
212+
213+@media (prefers-color-scheme: dark) {
214+ .light.no-js {
215+ --bg: hsl(200, 7%, 8%);
216+ --fg: #98a3ad;
217+
218+ --sidebar-bg: #292c2f;
219+ --sidebar-fg: #a1adb8;
220+ --sidebar-non-existant: #505254;
221+ --sidebar-active: #3473ad;
222+ --sidebar-spacer: #393939;
223+
224+ --scrollbar: var(--sidebar-fg);
225+
226+ --icons: #43484d;
227+ --icons-hover: #b3c0cc;
228+
229+ --links: #2b79a2;
230+
231+ --inline-code-color: #c5c8c6;
232+
233+ --theme-popup-bg: #141617;
234+ --theme-popup-border: #43484d;
235+ --theme-hover: #1f2124;
236+
237+ --quote-bg: hsl(234, 21%, 18%);
238+ --quote-border: hsl(234, 21%, 23%);
239+
240+ --table-border-color: hsl(200, 7%, 13%);
241+ --table-header-bg: hsl(200, 7%, 28%);
242+ --table-alternate-bg: hsl(200, 7%, 11%);
243+
244+ --searchbar-border-color: #aaa;
245+ --searchbar-bg: #b7b7b7;
246+ --searchbar-fg: #000;
247+ --searchbar-shadow-color: #aaa;
248+ --searchresults-header-fg: #666;
249+ --searchresults-border-color: #98a3ad;
250+ --searchresults-li-bg: #2b2b2f;
251+ --search-mark-bg: #355c7d;
252+ }
253+}
254+
255+.colibri {
256+ --bg: #3b224c;
257+ --fg: #bcbdd0;
258+ --heading-fg: #fff;
259+
260+ --sidebar-bg: #281733;
261+ --sidebar-fg: #c8c9db;
262+ --sidebar-non-existant: #505274;
263+ --sidebar-active: #a4a0e8;
264+ --sidebar-spacer: #2d334f;
265+
266+ --scrollbar: var(--sidebar-fg);
267+
268+ --icons: #737480;
269+ --icons-hover: #b7b9cc;
270+
271+ /* --links: #a4a0e8; */
272+ --links: #ECCDBA;
273+
274+ --inline-code-color: hsl(48.7, 7.8%, 70%);
275+
276+ --theme-popup-bg: #161923;
277+ --theme-popup-border: #737480;
278+ --theme-hover: rgba(0,0,0, .2);
279+
280+ --quote-bg: #281733;
281+ --quote-border: hsl(226, 15%, 22%);
282+
283+ --table-border-color: hsl(226, 23%, 76%);
284+ --table-header-bg: hsla(226, 23%, 31%, 0);
285+ --table-alternate-bg: hsl(226, 23%, 14%);
286+ --table-border-line: hsla(201deg, 20%, 92%, 0.2);
287+
288+ --searchbar-border-color: #aaa;
289+ --searchbar-bg: #aeaec6;
290+ --searchbar-fg: #000;
291+ --searchbar-shadow-color: #aaa;
292+ --searchresults-header-fg: #5f5f71;
293+ --searchresults-border-color: #5c5c68;
294+ --searchresults-li-bg: #242430;
295+ --search-mark-bg: #a2cff5;
296+}
297+
298+.colibri {
299+/*
300+ --bg: #ffffff;
301+ --fg: #452859;
302+ --fg: #5a5977;
303+ --heading-fg: #281733;
304+
305+ --sidebar-bg: #281733;
306+ --sidebar-fg: #c8c9db;
307+ --sidebar-non-existant: #505274;
308+ --sidebar-active: #a4a0e8;
309+ --sidebar-spacer: #2d334f;
310+
311+ --scrollbar: var(--sidebar-fg);
312+
313+ --icons: #737480;
314+ --icons-hover: #b7b9cc;
315+
316+ --links: #6F44F0;
317+
318+ --inline-code-color: #a39e9b;
319+
320+ --theme-popup-bg: #161923;
321+ --theme-popup-border: #737480;
322+ --theme-hover: rgba(0,0,0, .2);
323+
324+ --quote-bg: rgba(0, 0, 0, 0);
325+ --quote-border: hsl(226, 15%, 75%);
326+
327+ --table-border-color: #5a5977;
328+ --table-border-color: hsl(201deg 10% 67%);
329+ --table-header-bg: hsl(0, 0%, 100%);
330+ --table-alternate-bg: hsl(0, 0%, 97%);
331+ --table-border-line: hsl(201deg, 20%, 92%);
332+
333+ --searchbar-border-color: #aaa;
334+ --searchbar-bg: #aeaec6;
335+ --searchbar-fg: #000;
336+ --searchbar-shadow-color: #aaa;
337+ --searchresults-header-fg: #5f5f71;
338+ --searchresults-border-color: #5c5c68;
339+ --searchresults-li-bg: #242430;
340+ --search-mark-bg: #a2cff5;
341+*/
342+}
book/theme/favicon.png

Binary file not shown.

book/theme/favicon.svg+22−1
@@ -1 +1,22 @@
1−<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;" viewBox="663.38 37.57 575.35 903.75"> <g transform="matrix(1,0,0,1,-31352.7,-1817.25)"> <g transform="matrix(1,0,0,1,31062.7,-20.8972)"> <g transform="matrix(1,0,0,1,-130.173,0.00185558)"> <path d="M1083.58,1875.72L1635.06,2194.12C1649.8,2202.63 1658.88,2218.37 1658.88,2235.39C1658.88,2264.98 1658.88,2311.74 1658.88,2341.33C1658.88,2349.84 1656.61,2358.03 1652.5,2365.16C1652.5,2365.16 1214.7,2112.4 1107.2,2050.33C1092.58,2041.89 1083.58,2026.29 1083.58,2009.41C1083.58,1963.5 1083.58,1875.72 1083.58,1875.72Z" style="fill:#706bc8;"></path> </g> <g transform="matrix(1,0,0,1,-130.173,0.00185558)"> <path d="M1635.26,2604.84C1649.88,2613.28 1658.88,2628.87 1658.88,2645.75C1658.88,2691.67 1658.88,2779.44 1658.88,2779.44L1107.41,2461.05C1092.66,2452.53 1083.58,2436.8 1083.58,2419.78C1083.58,2390.19 1083.58,2343.42 1083.58,2313.84C1083.58,2305.32 1085.85,2297.13 1089.96,2290.01C1089.96,2290.01 1527.76,2542.77 1635.26,2604.84Z" style="fill:#55c5e4;"></path> </g> <g transform="matrix(1,0,0,1,216.062,984.098)"> <path d="M790.407,1432.56C785.214,1435.55 780.717,1439.9 777.509,1445.46C767.862,1462.16 773.473,1483.76 790.004,1493.59L789.998,1493.59L761.173,1476.95C746.427,1468.44 737.344,1452.71 737.344,1435.68C737.344,1406.09 737.344,1359.33 737.344,1329.74C737.344,1312.71 746.427,1296.98 761.173,1288.47L1259.59,1000.74L1259.83,1000.6C1264.92,997.617 1269.33,993.314 1272.48,987.844C1282.13,971.136 1276.52,949.544 1259.99,939.707L1260,939.707L1288.82,956.349C1303.57,964.862 1312.65,980.595 1312.65,997.622C1312.65,1027.21 1312.65,1073.97 1312.65,1103.56C1312.65,1120.59 1303.57,1136.32 1288.82,1144.83L1259.19,1161.94L1259.59,1161.68L790.407,1432.56Z" style="fill:#84ddea;"></path> </g> <g transform="matrix(1,0,0,1,216.062,984.098)"> <path d="M790.407,1686.24C785.214,1689.23 780.717,1693.58 777.509,1699.13C767.862,1715.84 773.473,1737.43 790.004,1747.27L789.998,1747.27L761.173,1730.63C746.427,1722.12 737.344,1706.38 737.344,1689.36C737.344,1659.77 737.344,1613.01 737.344,1583.42C737.344,1566.39 746.427,1550.66 761.173,1542.15L1259.59,1254.42L1259.83,1254.28C1264.92,1251.29 1269.33,1246.99 1272.48,1241.52C1282.13,1224.81 1276.52,1203.22 1259.99,1193.38L1260,1193.38L1288.82,1210.03C1303.57,1218.54 1312.65,1234.27 1312.65,1251.3C1312.65,1280.89 1312.65,1327.65 1312.65,1357.24C1312.65,1374.26 1303.57,1390 1288.82,1398.51L1259.19,1415.61L1259.59,1415.36L790.407,1686.24Z" style="fill:#997bc8;"></path></g></g></g> </svg>
1+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 199.7 184.2">
2+ <style>
3+ @media (prefers-color-scheme: dark) {
4+ svg { fill: white; }
5+ }
6+ </style>
7+<path d="M189.5,36.8c0.2,2.8,0,5.1-0.6,6.8L153,162c-0.6,2.1-2,3.7-4.2,5c-2.2,1.2-4.4,1.9-6.7,1.9H31.4c-9.6,0-15.3-2.8-17.3-8.4
8+ c-0.8-2.2-0.8-3.9,0.1-5.2c0.9-1.2,2.4-1.8,4.6-1.8H123c7.4,0,12.6-1.4,15.4-4.1s5.7-8.9,8.6-18.4l32.9-108.6
9+ c1.8-5.9,1-11.1-2.2-15.6S169.9,0,164,0H72.7c-1,0-3.1,0.4-6.1,1.1l0.1-0.4C64.5,0.2,62.6,0,61,0.1s-3,0.5-4.3,1.4
10+ c-1.3,0.9-2.4,1.8-3.2,2.8S52,6.5,51.2,8.1c-0.8,1.6-1.4,3-1.9,4.3s-1.1,2.7-1.8,4.2c-0.7,1.5-1.3,2.7-2,3.7c-0.5,0.6-1.2,1.5-2,2.5
11+ s-1.6,2-2.2,2.8s-0.9,1.5-1.1,2.2c-0.2,0.7-0.1,1.8,0.2,3.2c0.3,1.4,0.4,2.4,0.4,3.1c-0.3,3-1.4,6.9-3.3,11.6
12+ c-1.9,4.7-3.6,8.1-5.1,10.1c-0.3,0.4-1.2,1.3-2.6,2.7c-1.4,1.4-2.3,2.6-2.6,3.7c-0.3,0.4-0.3,1.5-0.1,3.4c0.3,1.8,0.4,3.1,0.3,3.8
13+ c-0.3,2.7-1.3,6.3-3,10.8c-1.7,4.5-3.4,8.2-5,11c-0.2,0.5-0.9,1.4-2,2.8c-1.1,1.4-1.8,2.5-2,3.4c-0.2,0.6-0.1,1.8,0.1,3.4
14+ c0.2,1.6,0.2,2.8-0.1,3.6c-0.6,3-1.8,6.7-3.6,11c-1.8,4.3-3.6,7.9-5.4,11c-0.5,0.8-1.1,1.7-2,2.8c-0.8,1.1-1.5,2-2,2.8
15+ s-0.8,1.6-1,2.5c-0.1,0.5,0,1.3,0.4,2.3c0.3,1.1,0.4,1.9,0.4,2.6c-0.1,1.1-0.2,2.6-0.5,4.4c-0.2,1.8-0.4,2.9-0.4,3.2
16+ c-1.8,4.8-1.7,9.9,0.2,15.2c2.2,6.2,6.2,11.5,11.9,15.8c5.7,4.3,11.7,6.4,17.8,6.4h110.7c5.2,0,10.1-1.7,14.7-5.2s7.7-7.8,9.2-12.9
17+ l33-108.6c1.8-5.8,1-10.9-2.2-15.5C194.9,39.7,192.6,38,189.5,36.8z M59.6,122.8L73.8,80c0,0,7,0,10.8,0s28.8-1.7,25.4,17.5
18+ c-3.4,19.2-18.8,25.2-36.8,25.4S59.6,122.8,59.6,122.8z M78.6,116.8c4.7-0.1,18.9-2.9,22.1-17.1S89.2,86.3,89.2,86.3l-8.9,0
19+ l-10.2,30.5C70.2,116.9,74,116.9,78.6,116.8z M75.3,68.7L89,26.2h9.8l0.8,34l23.6-34h9.9l-13.6,42.5h-7.1l12.5-35.4l-24.5,35.4h-6.8
20+ l-0.8-35L82,68.7H75.3z"/>
21+</svg>
22+<!-- Original image Copyright Dave Gandy — CC BY 4.0 License -->
book/theme/highlight.cssnew file+56
@@ -0,0 +1,56 @@
1+pre code.hljs {
2+ display:block;
3+ overflow-x:auto;
4+ padding:1em
5+}
6+code.hljs {
7+ padding:3px 5px
8+}
9+.hljs {
10+ background:#2f1e2e;
11+ color:#a39e9b
12+}
13+.hljs-comment,
14+.hljs-quote {
15+ color:#8d8687
16+}
17+.hljs-link,
18+.hljs-meta,
19+.hljs-name,
20+.hljs-regexp,
21+.hljs-selector-class,
22+.hljs-selector-id,
23+.hljs-tag,
24+.hljs-template-variable,
25+.hljs-variable {
26+ color:#ef6155
27+}
28+.hljs-built_in,
29+.hljs-deletion,
30+.hljs-literal,
31+.hljs-number,
32+.hljs-params,
33+.hljs-type {
34+ color:#f99b15
35+}
36+.hljs-attribute,
37+.hljs-section,
38+.hljs-title {
39+ color:#fec418
40+}
41+.hljs-addition,
42+.hljs-bullet,
43+.hljs-string,
44+.hljs-symbol {
45+ color:#48b685
46+}
47+.hljs-keyword,
48+.hljs-selector-tag {
49+ color:#815ba4
50+}
51+.hljs-emphasis {
52+ font-style:italic
53+}
54+.hljs-strong {
55+ font-weight:700
56+}
book/theme/highlight.jsnew file+6
@@ -0,0 +1,6 @@
1+/*
2+ Highlight.js 10.1.1 (93fd0d73)
3+ License: BSD-3-Clause
4+ Copyright (c) 2006-2020, Ivan Sagalaev
5+*/
6+var hljs=function(){"use strict";function e(n){Object.freeze(n);var t="function"==typeof n;return Object.getOwnPropertyNames(n).forEach((function(r){!Object.hasOwnProperty.call(n,r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r])})),n}class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}ignoreMatch(){this.ignore=!0}}function t(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")}function r(e,...n){var t={};for(const n in e)t[n]=e[n];return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}function a(e){return e.nodeName.toLowerCase()}var i=Object.freeze({__proto__:null,escapeHTML:t,inherit:r,nodeStream:function(e){var n=[];return function e(t,r){for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?r+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:r,node:i}),r=e(i,r),a(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:r,node:i}));return r}(e,0),n},mergeStreams:function(e,n,r){var i=0,s="",o=[];function l(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset<n[0].offset?e:n:"start"===n[0].event?e:n:e.length?e:n}function c(e){s+="<"+a(e)+[].map.call(e.attributes,(function(e){return" "+e.nodeName+'="'+t(e.value)+'"'})).join("")+">"}function u(e){s+="</"+a(e)+">"}function d(e){("start"===e.event?c:u)(e.node)}for(;e.length||n.length;){var g=l();if(s+=t(r.substring(i,g[0].offset)),i=g[0].offset,g===e){o.reverse().forEach(u);do{d(g.splice(0,1)[0]),g=l()}while(g===e&&g.length&&g[0].offset===i);o.reverse().forEach(c)}else"start"===g[0].event?o.push(g[0].node):o.pop(),d(g.splice(0,1)[0])}return s+t(r.substr(i))}});const s="</span>",o=e=>!!e.kind;class l{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=t(e)}openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){o(e)&&(this.buffer+=s)}value(){return this.buffer}span(e){this.buffer+=`<span class="${e}">`}}class c{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(e=>"string"==typeof e)?e.children=[e.children.join("")]:e.children.forEach(e=>{c._collapse(e)}))}}class u extends c{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new l(this,this.options).value()}finalize(){return!0}}function d(e){return e?"string"==typeof e?e:e.source:null}const g="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",h={begin:"\\\\[\\s\\S]",relevance:0},f={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[h]},p={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[h]},b={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},m=function(e,n,t={}){var a=r({className:"comment",begin:e,end:n,contains:[]},t);return a.contains.push(b),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a},v=m("//","$"),x=m("/\\*","\\*/"),E=m("#","$");var _=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:g,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){return e.map(e=>d(e)).join("")}(n,/.*\b/,e.binary,/\b.*/)),r({className:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:h,APOS_STRING_MODE:f,QUOTE_STRING_MODE:p,PHRASAL_WORDS_MODE:b,COMMENT:m,C_LINE_COMMENT_MODE:v,C_BLOCK_COMMENT_MODE:x,HASH_COMMENT_MODE:E,NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?",relevance:0},C_NUMBER_MODE:{className:"number",begin:g,relevance:0},BINARY_NUMBER_MODE:{className:"number",begin:"\\b(0b[01]+)",relevance:0},CSS_NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[h,{begin:/\[/,end:/\]/,relevance:0,contains:[h]}]}]},TITLE_MODE:{className:"title",begin:"[a-zA-Z]\\w*",relevance:0},UNDERSCORE_TITLE_MODE:{className:"title",begin:"[a-zA-Z_]\\w*",relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:function(e){return Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})}}),N="of and for in not or if then".split(" ");function w(e,n){return n?+n:function(e){return N.includes(e.toLowerCase())}(e)?0:1}const R=t,y=r,{nodeStream:k,mergeStreams:O}=i,M=Symbol("nomatch");return function(t){var a=[],i={},s={},o=[],l=!0,c=/(^(<[^>]+>|\t|)+|\n)/gm,g="Could not find the language '{}', did you forget to load/include a language module?";const h={disableAutodetect:!0,name:"Plain text",contains:[]};var f={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:u};function p(e){return f.noHighlightRe.test(e)}function b(e,n,t,r){var a={code:n,language:e};S("before:highlight",a);var i=a.result?a.result:m(a.language,a.code,t,r);return i.code=a.code,S("after:highlight",i),i}function m(e,t,a,s){var o=t;function c(e,n){var t=E.case_insensitive?n[0].toLowerCase():n[0];return Object.prototype.hasOwnProperty.call(e.keywords,t)&&e.keywords[t]}function u(){null!=y.subLanguage?function(){if(""!==A){var e=null;if("string"==typeof y.subLanguage){if(!i[y.subLanguage])return void O.addText(A);e=m(y.subLanguage,A,!0,k[y.subLanguage]),k[y.subLanguage]=e.top}else e=v(A,y.subLanguage.length?y.subLanguage:null);y.relevance>0&&(I+=e.relevance),O.addSublanguage(e.emitter,e.language)}}():function(){if(!y.keywords)return void O.addText(A);let e=0;y.keywordPatternRe.lastIndex=0;let n=y.keywordPatternRe.exec(A),t="";for(;n;){t+=A.substring(e,n.index);const r=c(y,n);if(r){const[e,a]=r;O.addText(t),t="",I+=a,O.addKeyword(n[0],e)}else t+=n[0];e=y.keywordPatternRe.lastIndex,n=y.keywordPatternRe.exec(A)}t+=A.substr(e),O.addText(t)}(),A=""}function h(e){return e.className&&O.openNode(e.className),y=Object.create(e,{parent:{value:y}})}function p(e){return 0===y.matcher.regexIndex?(A+=e[0],1):(L=!0,0)}var b={};function x(t,r){var i=r&&r[0];if(A+=t,null==i)return u(),0;if("begin"===b.type&&"end"===r.type&&b.index===r.index&&""===i){if(A+=o.slice(r.index,r.index+1),!l){const n=Error("0 width match regex");throw n.languageName=e,n.badRule=b.rule,n}return 1}if(b=r,"begin"===r.type)return function(e){var t=e[0],r=e.rule;const a=new n(r),i=[r.__beforeBegin,r["on:begin"]];for(const n of i)if(n&&(n(e,a),a.ignore))return p(t);return r&&r.endSameAsBegin&&(r.endRe=RegExp(t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),r.skip?A+=t:(r.excludeBegin&&(A+=t),u(),r.returnBegin||r.excludeBegin||(A=t)),h(r),r.returnBegin?0:t.length}(r);if("illegal"===r.type&&!a){const e=Error('Illegal lexeme "'+i+'" for mode "'+(y.className||"<unnamed>")+'"');throw e.mode=y,e}if("end"===r.type){var s=function(e){var t=e[0],r=o.substr(e.index),a=function e(t,r,a){let i=function(e,n){var t=e&&e.exec(n);return t&&0===t.index}(t.endRe,a);if(i){if(t["on:end"]){const e=new n(t);t["on:end"](r,e),e.ignore&&(i=!1)}if(i){for(;t.endsParent&&t.parent;)t=t.parent;return t}}if(t.endsWithParent)return e(t.parent,r,a)}(y,e,r);if(!a)return M;var i=y;i.skip?A+=t:(i.returnEnd||i.excludeEnd||(A+=t),u(),i.excludeEnd&&(A=t));do{y.className&&O.closeNode(),y.skip||y.subLanguage||(I+=y.relevance),y=y.parent}while(y!==a.parent);return a.starts&&(a.endSameAsBegin&&(a.starts.endRe=a.endRe),h(a.starts)),i.returnEnd?0:t.length}(r);if(s!==M)return s}if("illegal"===r.type&&""===i)return 1;if(B>1e5&&B>3*r.index)throw Error("potential infinite loop, way more iterations than matches");return A+=i,i.length}var E=T(e);if(!E)throw console.error(g.replace("{}",e)),Error('Unknown language: "'+e+'"');var _=function(e){function n(n,t){return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class t{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const e=this.regexes.map(e=>e[1]);this.matcherRe=n(function(e,n="|"){for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i<e.length;i++){var s=r+=1,o=d(e[i]);for(i>0&&(a+=n),a+="(";o.length>0;){var l=t.exec(o);if(null==l){a+=o;break}a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length),"\\"===l[0][0]&&l[1]?a+="\\"+(+l[1]+s):(a+=l[0],"("===l[0]&&r++)}a+=")"}return a}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e);if(!n)return null;const t=n.findIndex((e,n)=>n>0&&void 0!==e),r=this.matchIndexes[t];return n.splice(0,t),Object.assign(n,r)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;const t=n.exec(e);return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&(this.regexIndex=0)),t}}function i(e,n){const t=e.input[e.index-1],r=e.input[e.index+e[0].length];"."!==t&&"."!==r||n.ignoreMatch()}if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return function t(s,o){const l=s;if(s.compiled)return l;s.compiled=!0,s.__beforeBegin=null,s.keywords=s.keywords||s.beginKeywords;let c=null;if("object"==typeof s.keywords&&(c=s.keywords.$pattern,delete s.keywords.$pattern),s.keywords&&(s.keywords=function(e,n){var t={};return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){r(n,e[n])})),t;function r(e,r){n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|");t[r[0]]=[e,w(r[0],r[1])]}))}}(s.keywords,e.case_insensitive)),s.lexemes&&c)throw Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return l.keywordPatternRe=n(s.lexemes||c||/\w+/,!0),o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)",s.__beforeBegin=i),s.begin||(s.begin=/\B|\b/),l.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(l.endRe=n(s.end)),l.terminator_end=d(s.end)||"",s.endsWithParent&&o.terminator_end&&(l.terminator_end+=(s.end?"|":"")+o.terminator_end)),s.illegal&&(l.illegalRe=n(s.illegal)),void 0===s.relevance&&(s.relevance=1),s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((function(e){return function(e){return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){return r(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:function e(n){return!!n&&(n.endsWithParent||e(n.starts))}(e)?r(e,{starts:e.starts?r(e.starts):null}):Object.isFrozen(e)?r(e):e}("self"===e?s:e)}))),s.contains.forEach((function(e){t(e,l)})),s.starts&&t(s.starts,o),l.matcher=function(e){const n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminator_end&&n.addRule(e.terminator_end,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(l),l}(e)}(E),N="",y=s||_,k={},O=new f.__emitter(f);!function(){for(var e=[],n=y;n!==E;n=n.parent)n.className&&e.unshift(n.className);e.forEach(e=>O.openNode(e))}();var A="",I=0,S=0,B=0,L=!1;try{for(y.matcher.considerAll();;){B++,L?L=!1:(y.matcher.lastIndex=S,y.matcher.considerAll());const e=y.matcher.exec(o);if(!e)break;const n=x(o.substring(S,e.index),e);S=e.index+n}return x(o.substr(S)),O.closeAllNodes(),O.finalize(),N=O.toHTML(),{relevance:I,value:N,language:e,illegal:!1,emitter:O,top:y}}catch(n){if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:n.message,context:o.slice(S-100,S+100),mode:n.mode},sofar:N,relevance:0,value:R(o),emitter:O};if(l)return{illegal:!1,relevance:0,value:R(o),emitter:O,language:e,top:y,errorRaised:n};throw n}}function v(e,n){n=n||f.languages||Object.keys(i);var t=function(e){const n={relevance:0,emitter:new f.__emitter(f),value:R(e),illegal:!1,top:h};return n.emitter.addText(e),n}(e),r=t;return n.filter(T).filter(I).forEach((function(n){var a=m(n,e,!1);a.language=n,a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a)})),r.language&&(t.second_best=r),t}function x(e){return f.tabReplace||f.useBR?e.replace(c,e=>"\n"===e?f.useBR?"<br>":e:f.tabReplace?e.replace(/\t/g,f.tabReplace):e):e}function E(e){let n=null;const t=function(e){var n=e.className+" ";n+=e.parentNode?e.parentNode.className:"";const t=f.languageDetectRe.exec(n);if(t){var r=T(t[1]);return r||(console.warn(g.replace("{}",t[1])),console.warn("Falling back to no-highlight mode for this block.",e)),r?t[1]:"no-highlight"}return n.split(/\s+/).find(e=>p(e)||T(e))}(e);if(p(t))return;S("before:highlightBlock",{block:e,language:t}),f.useBR?(n=document.createElement("div")).innerHTML=e.innerHTML.replace(/\n/g,"").replace(/<br[ /]*>/g,"\n"):n=e;const r=n.textContent,a=t?b(t,r,!0):v(r),i=k(n);if(i.length){const e=document.createElement("div");e.innerHTML=a.value,a.value=O(i,k(e),r)}a.value=x(a.value),S("after:highlightBlock",{block:e,result:a}),e.innerHTML=a.value,e.className=function(e,n,t){var r=n?s[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),e.includes(r)||a.push(r),a.join(" ").trim()}(e.className,t,a.language),e.result={language:a.language,re:a.relevance,relavance:a.relevance},a.second_best&&(e.second_best={language:a.second_best.language,re:a.second_best.relevance,relavance:a.second_best.relevance})}const N=()=>{if(!N.called){N.called=!0;var e=document.querySelectorAll("pre code");a.forEach.call(e,E)}};function T(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}function A(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach(e=>{s[e]=n})}function I(e){var n=T(e);return n&&!n.disableAutodetect}function S(e,n){var t=e;o.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(t,{highlight:b,highlightAuto:v,fixMarkup:x,highlightBlock:E,configure:function(e){f=y(f,e)},initHighlighting:N,initHighlightingOnLoad:function(){window.addEventListener("DOMContentLoaded",N,!1)},registerLanguage:function(e,n){var r=null;try{r=n(t)}catch(n){if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)),!l)throw n;console.error(n),r=h}r.name||(r.name=e),i[e]=r,r.rawDefinition=n.bind(null,t),r.aliases&&A(r.aliases,{languageName:e})},listLanguages:function(){return Object.keys(i)},getLanguage:T,registerAliases:A,requireLanguage:function(e){var n=T(e);if(n)return n;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:I,inherit:y,addPlugin:function(e){o.push(e)}}),t.debugMode=function(){l=!1},t.safeMode=function(){l=!0},t.versionString="10.1.1";for(const n in _)"object"==typeof _[n]&&e(_[n]);return Object.assign(t,_),t}({})}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);hljs.registerLanguage("php",function(){"use strict";return function(e){var r={begin:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},t={className:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{begin:/\?>/}]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:'b"',end:'"'},{begin:"b'",end:"'"},e.inherit(e.APOS_STRING_MODE,{illegal:null}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null})]},n={variants:[e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]},i={keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list new object or private protected public real return string switch throw trait try unset use var void while xor yield",literal:"false null true",built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Throwable Traversable WeakReference Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"};return{aliases:["php","php3","php4","php5","php6","php7"],case_insensitive:!0,keywords:i,contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t]}),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0,keywords:"__halt_compiler"}),{className:"string",begin:/<<<['"]?\w+['"]?$/,end:/^\w+;?$/,contains:[e.BACKSLASH_ESCAPE,{className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}]}]},t,{className:"keyword",begin:/\$this\b/},r,{begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function",beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]",contains:[e.UNDERSCORE_TITLE_MODE,{className:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:i,contains:["self",r,e.C_BLOCK_COMMENT_MODE,a,n]}]},{className:"class",beginKeywords:"class interface",end:"{",excludeEnd:!0,illegal:/[:\(\$"]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",end:";",illegal:/[\.']/,contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",end:";",contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"=>"},a,n]}}}());hljs.registerLanguage("nginx",function(){"use strict";return function(e){var n={className:"variable",variants:[{begin:/\$\d+/},{begin:/\$\{/,end:/}/},{begin:"[\\$\\@]"+e.UNDERSCORE_IDENT_RE}]},a={endsWithParent:!0,keywords:{$pattern:"[a-z/_]+",literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},relevance:0,illegal:"=>",contains:[e.HASH_COMMENT_MODE,{className:"string",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:/"/,end:/"/},{begin:/'/,end:/'/}]},{begin:"([a-z]+):/",end:"\\s",endsWithParent:!0,excludeEnd:!0,contains:[n]},{className:"regexp",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:"\\s\\^",end:"\\s|{|;",returnEnd:!0},{begin:"~\\*?\\s+",end:"\\s|{|;",returnEnd:!0},{begin:"\\*(\\.[a-z\\-]+)+"},{begin:"([a-z\\-]+\\.)+\\*"}]},{className:"number",begin:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{className:"number",begin:"\\b\\d+[kKmMgGdshdwy]*\\b",relevance:0},n]};return{name:"Nginx config",aliases:["nginxconf"],contains:[e.HASH_COMMENT_MODE,{begin:e.UNDERSCORE_IDENT_RE+"\\s+{",returnBegin:!0,end:"{",contains:[{className:"section",begin:e.UNDERSCORE_IDENT_RE}],relevance:0},{begin:e.UNDERSCORE_IDENT_RE+"\\s",end:";|{",returnBegin:!0,contains:[{className:"attribute",begin:e.UNDERSCORE_IDENT_RE,starts:a}],relevance:0}],illegal:"[^\\s\\}]"}}}());hljs.registerLanguage("csharp",function(){"use strict";return function(e){var n={keyword:"abstract as base bool break byte case catch char checked const continue decimal default delegate do double enum event explicit extern finally fixed float for foreach goto if implicit in int interface internal is lock long object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this try typeof uint ulong unchecked unsafe ushort using virtual void volatile while add alias ascending async await by descending dynamic equals from get global group into join let nameof on orderby partial remove select set value var when where yield",literal:"null false true"},i=e.inherit(e.TITLE_MODE,{begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]},t=e.inherit(s,{illegal:/\n/}),l={className:"subst",begin:"{",end:"}",keywords:n},r=e.inherit(l,{illegal:/\n/}),c={className:"string",begin:/\$"/,end:'"',illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},e.BACKSLASH_ESCAPE,r]},o={className:"string",begin:/\$@"/,end:'"',contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},l]},g=e.inherit(o,{illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},r]});l.contains=[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE],r.contains=[g,c,t,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{illegal:/\n/})];var d={variants:[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},E={begin:"<",end:">",contains:[{beginKeywords:"in out"},i]},_=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",b={begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{begin:"\x3c!--|--\x3e"},{begin:"</?",end:">"}]}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",end:"$",keywords:{"meta-keyword":"if else elif endif define undef warning error line region endregion pragma checksum"}},d,a,{beginKeywords:"class interface",end:/[{;=]/,illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"},i,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",end:/[{;=]/,illegal:/[^\s:]/,contains:[i,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",begin:"^\\s*\\[",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{className:"meta-string",begin:/"/,end:/"/}]},{beginKeywords:"new return throw await else",relevance:0},{className:"function",begin:"("+_+"\\s+)+"+e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{begin:e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,contains:[e.TITLE_MODE,E],relevance:0},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,contains:[d,a,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},b]}}}());hljs.registerLanguage("perl",function(){"use strict";return function(e){var n={$pattern:/[\w.]+/,keyword:"getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qq fileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmget sub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedir ioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when"},t={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:n},s={begin:"->{",end:"}"},r={variants:[{begin:/\$\d/},{begin:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{begin:/[\$%@][^\s\w{]/,relevance:0}]},i=[e.BACKSLASH_ESCAPE,t,r],a=[r,e.HASH_COMMENT_MODE,e.COMMENT("^\\=\\w","\\=cut",{endsWithParent:!0}),s,{className:"string",contains:i,variants:[{begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*\\<",end:"\\>",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE]},{begin:"{\\w+}",contains:[],relevance:0},{begin:"-?\\w+\\s*\\=\\>",contains:[],relevance:0}]},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",keywords:"split return print reverse grep",relevance:0,contains:[e.HASH_COMMENT_MODE,{className:"regexp",begin:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",relevance:10},{className:"regexp",begin:"(m|qr)?/",end:"/[a-z]*",contains:[e.BACKSLASH_ESCAPE],relevance:0}]},{className:"function",beginKeywords:"sub",end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]}];return t.contains=a,s.contains=a,{name:"Perl",aliases:["pl","pm"],keywords:n,contains:a}}}());hljs.registerLanguage("swift",function(){"use strict";return function(e){var i={keyword:"#available #colorLiteral #column #else #elseif #endif #file #fileLiteral #function #if #imageLiteral #line #selector #sourceLocation _ __COLUMN__ __FILE__ __FUNCTION__ __LINE__ Any as as! as? associatedtype associativity break case catch class continue convenience default defer deinit didSet do dynamic dynamicType else enum extension fallthrough false fileprivate final for func get guard if import in indirect infix init inout internal is lazy left let mutating nil none nonmutating open operator optional override postfix precedence prefix private protocol Protocol public repeat required rethrows return right self Self set static struct subscript super switch throw throws true try try! try? Type typealias unowned var weak where while willSet",literal:"true false nil",built_in:"abs advance alignof alignofValue anyGenerator assert assertionFailure bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC bridgeToObjectiveCUnconditional c compactMap contains count countElements countLeadingZeros debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords enumerate equal fatalError filter find getBridgedObjectiveCType getVaList indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC isUniquelyReferenced isUniquelyReferencedNonObjC join lazy lexicographicalCompare map max maxElement min minElement numericCast overlaps partition posix precondition preconditionFailure print println quickSort readLine reduce reflect reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split startsWith stride strideof strideofValue swap toString transcode underestimateCount unsafeAddressOf unsafeBitCast unsafeDowncast unsafeUnwrap unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer withUnsafePointerToObject withUnsafeMutablePointer withUnsafeMutablePointers withUnsafePointer withUnsafePointers withVaList zip"},n=e.COMMENT("/\\*","\\*/",{contains:["self"]}),t={className:"subst",begin:/\\\(/,end:"\\)",keywords:i,contains:[]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:/"""/,end:/"""/},{begin:/"/,end:/"/}]},r={className:"number",begin:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",relevance:0};return t.contains=[r],{name:"Swift",keywords:i,contains:[a,e.C_LINE_COMMENT_MODE,n,{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*[!?]"},{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*",relevance:0},r,{className:"function",beginKeywords:"func",end:"{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][0-9A-Za-z$_]*/}),{begin:/</,end:/>/},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:i,contains:["self",r,a,e.C_BLOCK_COMMENT_MODE,{begin:":"}],illegal:/["']/}],illegal:/\[|%/},{className:"class",beginKeywords:"struct protocol class extension enum",keywords:i,end:"\\{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/})]},{className:"meta",begin:"(@discardableResult|@warn_unused_result|@exported|@lazy|@noescape|@NSCopying|@NSManaged|@objc|@objcMembers|@convention|@required|@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|@infix|@prefix|@postfix|@autoclosure|@testable|@available|@nonobjc|@NSApplicationMain|@UIApplicationMain|@dynamicMemberLookup|@propertyWrapper)\\b"},{beginKeywords:"import",end:/$/,contains:[e.C_LINE_COMMENT_MODE,n]}]}}}());hljs.registerLanguage("makefile",function(){"use strict";return function(e){var i={className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%<?\^\+\*]/}]},n={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,i]},a={className:"variable",begin:/\$\([\w-]+\s/,end:/\)/,keywords:{built_in:"subst patsubst strip findstring filter filter-out sort word wordlist firstword lastword dir notdir suffix basename addsuffix addprefix join wildcard realpath abspath error warning shell origin flavor foreach if or and call eval file value"},contains:[i]},r={begin:"^"+e.UNDERSCORE_IDENT_RE+"\\s*(?=[:+?]?=)"},s={className:"section",begin:/^[^\s]+:/,end:/$/,contains:[i]};return{name:"Makefile",aliases:["mk","mak"],keywords:{$pattern:/[\w-]+/,keyword:"define endef undefine ifdef ifndef ifeq ifneq else endif include -include sinclude override export unexport private vpath"},contains:[e.HASH_COMMENT_MODE,i,n,a,r,{className:"meta",begin:/^\.PHONY:/,end:/$/,keywords:{$pattern:/[\.\w]+/,"meta-keyword":".PHONY"}},s]}}}());hljs.registerLanguage("css",function(){"use strict";return function(e){var n={begin:/(?:[A-Z\_\.\-]+|--[a-zA-Z0-9_-]+)\s*:/,returnBegin:!0,end:";",endsWithParent:!0,contains:[{className:"attribute",begin:/\S/,end:":",excludeEnd:!0,starts:{endsWithParent:!0,excludeEnd:!0,contains:[{begin:/[\w-]+\(/,returnBegin:!0,contains:[{className:"built_in",begin:/[\w-]+/},{begin:/\(/,end:/\)/,contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.CSS_NUMBER_MODE]}]},e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{className:"number",begin:"#[0-9A-Fa-f]+"},{className:"meta",begin:"!important"}]}}]};return{name:"CSS",case_insensitive:!0,illegal:/[=\/|'\$]/,contains:[e.C_BLOCK_COMMENT_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/},{className:"selector-class",begin:/\.[A-Za-z0-9_-]+/},{className:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},{className:"selector-pseudo",begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"@(page|font-face)",lexemes:"@[a-z-]+",keywords:"@page @font-face"},{begin:"@",end:"[{;]",illegal:/:/,returnBegin:!0,contains:[{className:"keyword",begin:/@\-?\w[\w]*(\-\w+)*/},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:"and or not only",contains:[{begin:/[a-z-]+:/,className:"attribute"},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.CSS_NUMBER_MODE]}]},{className:"selector-tag",begin:"[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0},{begin:"{",end:"}",illegal:/\S/,contains:[e.C_BLOCK_COMMENT_MODE,n]}]}}}());hljs.registerLanguage("xml",function(){"use strict";return function(e){var n={className:"symbol",begin:"&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;"},a={begin:"\\s",contains:[{className:"meta-keyword",begin:"#?[a-z_][a-z1-9_-]+",illegal:"\\n"}]},s=e.inherit(a,{begin:"\\(",end:"\\)"}),t=e.inherit(e.APOS_STRING_MODE,{className:"meta-string"}),i=e.inherit(e.QUOTE_STRING_MODE,{className:"meta-string"}),c={endsWithParent:!0,illegal:/</,relevance:0,contains:[{className:"attr",begin:"[A-Za-z0-9\\._:-]+",relevance:0},{begin:/=\s*/,relevance:0,contains:[{className:"string",endsParent:!0,variants:[{begin:/"/,end:/"/,contains:[n]},{begin:/'/,end:/'/,contains:[n]},{begin:/[^\s"'=<>`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin:"<![a-z]",end:">",relevance:10,contains:[a,i,t,s,{begin:"\\[",end:"\\]",contains:[{className:"meta",begin:"<![a-z]",end:">",contains:[a,s,i,t]}]}]},e.COMMENT("\x3c!--","--\x3e",{relevance:10}),{begin:"<\\!\\[CDATA\\[",end:"\\]\\]>",relevance:10},n,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:"<style(?=\\s|>)",end:">",keywords:{name:"style"},contains:[c],starts:{end:"</style>",returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:"<script(?=\\s|>)",end:">",keywords:{name:"script"},contains:[c],starts:{end:"<\/script>",returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:"</?",end:"/?>",contains:[{className:"name",begin:/[^\/><\s]+/,relevance:0},c]}]}}}());hljs.registerLanguage("bash",function(){"use strict";return function(e){const s={};Object.assign(s,{className:"variable",variants:[{begin:/\$[\w\d#@][\w\d_]*/},{begin:/\$\{/,end:/\}/,contains:[{begin:/:-/,contains:[s]}]}]});const t={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},n={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,t]};t.contains.push(n);const a={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,s]},i=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b-?[a-z\._]+\b/,keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},contains:[i,e.SHEBANG(),c,a,e.HASH_COMMENT_MODE,n,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},s]}}}());hljs.registerLanguage("c-like",function(){"use strict";return function(e){function t(e){return"(?:"+e+")?"}var n="(decltype\\(auto\\)|"+t("[a-zA-Z_]\\w*::")+"[a-zA-Z_]\\w*"+t("<.*?>")+")",r={className:"keyword",begin:"\\b[a-z\\d_]*_t\\b"},a={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},i={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{"meta-keyword":"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(a,{className:"meta-string"}),{className:"meta-string",begin:/<.*?>/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},o={className:"title",begin:t("[a-zA-Z_]\\w*::")+e.IDENT_RE,relevance:0},c=t("[a-zA-Z_]\\w*::")+e.IDENT_RE+"\\s*\\(",l={keyword:"int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid wchar_t short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignas alignof constexpr consteval constinit decltype concept co_await co_return co_yield requires noexcept static_assert thread_local restrict final override atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr _Bool complex _Complex imaginary _Imaginary",literal:"true false nullptr NULL"},d=[r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,i,a],_={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:l,contains:d.concat([{begin:/\(/,end:/\)/,keywords:l,contains:d.concat(["self"]),relevance:0}]),relevance:0},u={className:"function",begin:"("+n+"[\\*&\\s]+)+"+c,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:l,illegal:/[^\w\s\*&:<>]/,contains:[{begin:"decltype\\(auto\\)",keywords:l,relevance:0},{begin:c,returnBegin:!0,contains:[o],relevance:0},{className:"params",begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r,{begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:["self",e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r]}]},r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s]};return{aliases:["c","cc","h","c++","h++","hpp","hh","hxx","cxx"],keywords:l,disableAutodetect:!0,illegal:"</",contains:[].concat(_,u,d,[s,{begin:"\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",end:">",keywords:l,contains:["self",r]},{begin:e.IDENT_RE+"::",keywords:l},{className:"class",beginKeywords:"class struct",end:/[{;:]/,contains:[{begin:/</,end:/>/,contains:["self"]},e.TITLE_MODE]}]),exports:{preprocessor:s,strings:a,keywords:l}}}}());hljs.registerLanguage("coffeescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={keyword:e.concat(["then","unless","until","loop","by","when","and","or","is","isnt","not"]).filter((e=>n=>!e.includes(n))(["var","const","let","function","static"])).join(" "),literal:n.concat(["yes","no","on","off"]).join(" "),built_in:a.concat(["npm","print"]).join(" ")},i="[A-Za-z$_][0-9A-Za-z$_]*",s={className:"subst",begin:/#\{/,end:/}/,keywords:t},o=[r.BINARY_NUMBER_MODE,r.inherit(r.C_NUMBER_MODE,{starts:{end:"(\\s*/)?",relevance:0}}),{className:"string",variants:[{begin:/'''/,end:/'''/,contains:[r.BACKSLASH_ESCAPE]},{begin:/'/,end:/'/,contains:[r.BACKSLASH_ESCAPE]},{begin:/"""/,end:/"""/,contains:[r.BACKSLASH_ESCAPE,s]},{begin:/"/,end:/"/,contains:[r.BACKSLASH_ESCAPE,s]}]},{className:"regexp",variants:[{begin:"///",end:"///",contains:[s,r.HASH_COMMENT_MODE]},{begin:"//[gim]{0,3}(?=\\W)",relevance:0},{begin:/\/(?![ *]).*?(?![\\]).\/[gim]{0,3}(?=\W)/}]},{begin:"@"+i},{subLanguage:"javascript",excludeBegin:!0,excludeEnd:!0,variants:[{begin:"```",end:"```"},{begin:"`",end:"`"}]}];s.contains=o;var c=r.inherit(r.TITLE_MODE,{begin:i}),l={className:"params",begin:"\\([^\\(]",returnBegin:!0,contains:[{begin:/\(/,end:/\)/,keywords:t,contains:["self"].concat(o)}]};return{name:"CoffeeScript",aliases:["coffee","cson","iced"],keywords:t,illegal:/\/\*/,contains:o.concat([r.COMMENT("###","###"),r.HASH_COMMENT_MODE,{className:"function",begin:"^\\s*"+i+"\\s*=\\s*(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[c,l]},{begin:/[:\(,=]\s*/,relevance:0,contains:[{className:"function",begin:"(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[l]}]},{className:"class",beginKeywords:"class",end:"$",illegal:/[:="\[\]]/,contains:[{beginKeywords:"extends",endsWithParent:!0,illegal:/[:="\[\]]/,contains:[c]},c]},{begin:i+":",end:":",returnBegin:!0,returnEnd:!0,relevance:0}])}}}());hljs.registerLanguage("ruby",function(){"use strict";return function(e){var n="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",a={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",literal:"true false nil"},s={className:"doctag",begin:"@[A-Za-z]+"},i={begin:"#<",end:">"},r=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^\\=begin","^\\=end",{contains:[s],relevance:10}),e.COMMENT("^__END__","\\n$")],c={className:"subst",begin:"#\\{",end:"}",keywords:a},t={className:"string",contains:[e.BACKSLASH_ESCAPE,c],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:"%[qQwWx]?\\(",end:"\\)"},{begin:"%[qQwWx]?\\[",end:"\\]"},{begin:"%[qQwWx]?{",end:"}"},{begin:"%[qQwWx]?<",end:">"},{begin:"%[qQwWx]?/",end:"/"},{begin:"%[qQwWx]?%",end:"%"},{begin:"%[qQwWx]?-",end:"-"},{begin:"%[qQwWx]?\\|",end:"\\|"},{begin:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{begin:/<<[-~]?'?(\w+)(?:.|\n)*?\n\s*\1\b/,returnBegin:!0,contains:[{begin:/<<[-~]?'?/},e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,c]})]}]},b={className:"params",begin:"\\(",end:"\\)",endsParent:!0,keywords:a},d=[t,i,{className:"class",beginKeywords:"class module",end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE}]}].concat(r)},{className:"function",beginKeywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:n}),b].concat(r)},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(\\!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[t,{begin:n}],relevance:0},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{className:"params",begin:/\|/,end:/\|/,keywords:a},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[i,{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:"%r{",end:"}[a-z]*"},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(r),relevance:0}].concat(r);c.contains=d,b.contains=d;var g=[{begin:/^\s*=>/,starts:{end:"$",contains:d}},{className:"meta",begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>)",starts:{end:"$",contains:d}}];return{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:a,illegal:/\/\*/,contains:r.concat(g).concat(d)}}}());hljs.registerLanguage("yaml",function(){"use strict";return function(e){var n="true false yes no null",a="[\\w#;/?:@&=+$,.~*\\'()[\\]]+",s={className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",variants:[{begin:"{{",end:"}}"},{begin:"%{",end:"}"}]}]},i=e.inherit(s,{variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),l={end:",",endsWithParent:!0,excludeEnd:!0,contains:[],keywords:n,relevance:0},t={begin:"{",end:"}",contains:[l],illegal:"\\n",relevance:0},g={begin:"\\[",end:"\\]",contains:[l],illegal:"\\n",relevance:0},b=[{className:"attr",variants:[{begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---s*$",relevance:10},{className:"string",begin:"[\\|>]([0-9]?[+-])?[ ]*\\n( *)[\\S ]+\\n(\\2[\\S ]+\\n?)*"},{begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:"!\\w+!"+a},{className:"type",begin:"!<"+a+">"},{className:"type",begin:"!"+a},{className:"type",begin:"!!"+a},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"\\-(?=[ ]|$)",relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{className:"number",begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"},{className:"number",begin:e.C_NUMBER_RE+"\\b"},t,g,s],c=[...b];return c.pop(),c.push(i),l.contains=c,{name:"YAML",case_insensitive:!0,aliases:["yml","YAML"],contains:b}}}());hljs.registerLanguage("d",function(){"use strict";return function(e){var a={$pattern:e.UNDERSCORE_IDENT_RE,keyword:"abstract alias align asm assert auto body break byte case cast catch class const continue debug default delete deprecated do else enum export extern final finally for foreach foreach_reverse|10 goto if immutable import in inout int interface invariant is lazy macro mixin module new nothrow out override package pragma private protected public pure ref return scope shared static struct super switch synchronized template this throw try typedef typeid typeof union unittest version void volatile while with __FILE__ __LINE__ __gshared|10 __thread __traits __DATE__ __EOF__ __TIME__ __TIMESTAMP__ __VENDOR__ __VERSION__",built_in:"bool cdouble cent cfloat char creal dchar delegate double dstring float function idouble ifloat ireal long real short string ubyte ucent uint ulong ushort wchar wstring",literal:"false null true"},d="((0|[1-9][\\d_]*)|0[bB][01_]+|0[xX]([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))",n="\\\\(['\"\\?\\\\abfnrtv]|u[\\dA-Fa-f]{4}|[0-7]{1,3}|x[\\dA-Fa-f]{2}|U[\\dA-Fa-f]{8})|&[a-zA-Z\\d]{2,};",t={className:"number",begin:"\\b"+d+"(L|u|U|Lu|LU|uL|UL)?",relevance:0},_={className:"number",begin:"\\b(((0[xX](([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)\\.([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)|\\.?([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))[pP][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))|((0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(\\.\\d*|([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)))|\\d+\\.(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)|\\.(0|[1-9][\\d_]*)([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))?))([fF]|L|i|[fF]i|Li)?|"+d+"(i|[fF]i|Li))",relevance:0},r={className:"string",begin:"'("+n+"|.)",end:"'",illegal:"."},i={className:"string",begin:'"',contains:[{begin:n,relevance:0}],end:'"[cwd]?'},s=e.COMMENT("\\/\\+","\\+\\/",{contains:["self"],relevance:10});return{name:"D",keywords:a,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s,{className:"string",begin:'x"[\\da-fA-F\\s\\n\\r]*"[cwd]?',relevance:10},i,{className:"string",begin:'[rq]"',end:'"[cwd]?',relevance:5},{className:"string",begin:"`",end:"`[cwd]?"},{className:"string",begin:'q"\\{',end:'\\}"'},_,t,r,{className:"meta",begin:"^#!",end:"$",relevance:5},{className:"meta",begin:"#(line)",end:"$",relevance:5},{className:"keyword",begin:"@[a-zA-Z_][a-zA-Z_\\d]*"}]}}}());hljs.registerLanguage("properties",function(){"use strict";return function(e){var n="[ \\t\\f]*",t="("+n+"[:=]"+n+"|[ \\t\\f]+)",a="([^\\\\:= \\t\\f\\n]|\\\\.)+",s={end:t,relevance:0,starts:{className:"string",end:/$/,relevance:0,contains:[{begin:"\\\\\\n"}]}};return{name:".properties",case_insensitive:!0,illegal:/\S/,contains:[e.COMMENT("^\\s*[!#]","$"),{begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+"+t,returnBegin:!0,contains:[{className:"attr",begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+",endsParent:!0,relevance:0}],starts:s},{begin:a+t,returnBegin:!0,relevance:0,contains:[{className:"meta",begin:a,endsParent:!0,relevance:0}],starts:s},{className:"attr",relevance:0,begin:a+n+"$"}]}}}());hljs.registerLanguage("http",function(){"use strict";return function(e){var n="HTTP/[0-9\\.]+";return{name:"HTTP",aliases:["https"],illegal:"\\S",contains:[{begin:"^"+n,end:"$",contains:[{className:"number",begin:"\\b\\d{3}\\b"}]},{begin:"^[A-Z]+ (.*?) "+n+"$",returnBegin:!0,end:"$",contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{begin:n},{className:"keyword",begin:"[A-Z]+"}]},{className:"attribute",begin:"^\\w",end:": ",excludeEnd:!0,illegal:"\\n|\\s|=",starts:{end:"$",relevance:0}},{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}]}}}());hljs.registerLanguage("haskell",function(){"use strict";return function(e){var n={variants:[e.COMMENT("--","$"),e.COMMENT("{-","-}",{contains:["self"]})]},i={className:"meta",begin:"{-#",end:"#-}"},a={className:"meta",begin:"^#",end:"$"},s={className:"type",begin:"\\b[A-Z][\\w']*",relevance:0},l={begin:"\\(",end:"\\)",illegal:'"',contains:[i,a,{className:"type",begin:"\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?"},e.inherit(e.TITLE_MODE,{begin:"[_a-z][\\w']*"}),n]};return{name:"Haskell",aliases:["hs"],keywords:"let in if then else case of where do module import hiding qualified type data newtype deriving class instance as default infix infixl infixr foreign export ccall stdcall cplusplus jvm dotnet safe unsafe family forall mdo proc rec",contains:[{beginKeywords:"module",end:"where",keywords:"module where",contains:[l,n],illegal:"\\W\\.|;"},{begin:"\\bimport\\b",end:"$",keywords:"import qualified as hiding",contains:[l,n],illegal:"\\W\\.|;"},{className:"class",begin:"^(\\s*)?(class|instance)\\b",end:"where",keywords:"class family instance where",contains:[s,l,n]},{className:"class",begin:"\\b(data|(new)?type)\\b",end:"$",keywords:"data family type newtype deriving",contains:[i,s,l,{begin:"{",end:"}",contains:l.contains},n]},{beginKeywords:"default",end:"$",contains:[s,l,n]},{beginKeywords:"infix infixl infixr",end:"$",contains:[e.C_NUMBER_MODE,n]},{begin:"\\bforeign\\b",end:"$",keywords:"foreign import export ccall stdcall cplusplus jvm dotnet safe unsafe",contains:[s,e.QUOTE_STRING_MODE,n]},{className:"meta",begin:"#!\\/usr\\/bin\\/env runhaskell",end:"$"},i,a,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,s,e.inherit(e.TITLE_MODE,{begin:"^[_a-z][\\w']*"}),n,{begin:"->|<-"}]}}}());hljs.registerLanguage("handlebars",function(){"use strict";function e(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(n){const a={"builtin-name":"action bindattr collection component concat debugger each each-in get hash if in input link-to loc log lookup mut outlet partial query-params render template textarea unbound unless view with yield"},t=/\[.*?\]/,s=/[^\s!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]+/,i=e("(",/'.*?'/,"|",/".*?"/,"|",t,"|",s,"|",/\.|\//,")+"),r=e("(",t,"|",s,")(?==)"),l={begin:i,lexemes:/[\w.\/]+/},c=n.inherit(l,{keywords:{literal:"true false undefined null"}}),o={begin:/\(/,end:/\)/},m={className:"attr",begin:r,relevance:0,starts:{begin:/=/,end:/=/,starts:{contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,c,o]}}},d={contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,{begin:/as\s+\|/,keywords:{keyword:"as"},end:/\|/,contains:[{begin:/\w+/}]},m,c,o],returnEnd:!0},g=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/\)/})});o.contains=[g];const u=n.inherit(l,{keywords:a,className:"name",starts:n.inherit(d,{end:/}}/})}),b=n.inherit(l,{keywords:a,className:"name"}),h=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/}}/})});return{name:"Handlebars",aliases:["hbs","html.hbs","html.handlebars","htmlbars"],case_insensitive:!0,subLanguage:"xml",contains:[{begin:/\\\{\{/,skip:!0},{begin:/\\\\(?=\{\{)/,skip:!0},n.COMMENT(/\{\{!--/,/--\}\}/),n.COMMENT(/\{\{!/,/\}\}/),{className:"template-tag",begin:/\{\{\{\{(?!\/)/,end:/\}\}\}\}/,contains:[u],starts:{end:/\{\{\{\{\//,returnEnd:!0,subLanguage:"xml"}},{className:"template-tag",begin:/\{\{\{\{\//,end:/\}\}\}\}/,contains:[b]},{className:"template-tag",begin:/\{\{#/,end:/\}\}/,contains:[u]},{className:"template-tag",begin:/\{\{(?=else\}\})/,end:/\}\}/,keywords:"else"},{className:"template-tag",begin:/\{\{\//,end:/\}\}/,contains:[b]},{className:"template-variable",begin:/\{\{\{/,end:/\}\}\}/,contains:[h]},{className:"template-variable",begin:/\{\{/,end:/\}\}/,contains:[h]}]}}}());hljs.registerLanguage("rust",function(){"use strict";return function(e){var n="([ui](8|16|32|64|128|size)|f(32|64))?",t="drop i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64 str char bool Box Option Result String Vec Copy Send Sized Sync Drop Fn FnMut FnOnce ToOwned Clone Debug PartialEq PartialOrd Eq Ord AsRef AsMut Into From Default Iterator Extend IntoIterator DoubleEndedIterator ExactSizeIterator SliceConcatExt ToString assert! assert_eq! bitflags! bytes! cfg! col! concat! concat_idents! debug_assert! debug_assert_eq! env! panic! file! format! format_args! include_bin! include_str! line! local_data_key! module_path! option_env! print! println! select! stringify! try! unimplemented! unreachable! vec! write! writeln! macro_rules! assert_ne! debug_assert_ne!";return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",keyword:"abstract as async await become box break const continue crate do dyn else enum extern false final fn for if impl in let loop macro match mod move mut override priv pub ref return self Self static struct super trait true try type typeof unsafe unsized use virtual where while yield",literal:"true false Some None Ok Err",built_in:t},illegal:"</",contains:[e.C_LINE_COMMENT_MODE,e.COMMENT("/\\*","\\*/",{contains:["self"]}),e.inherit(e.QUOTE_STRING_MODE,{begin:/b?"/,illegal:null}),{className:"string",variants:[{begin:/r(#*)"(.|\n)*?"\1(?!#)/},{begin:/b?'\\?(x\w{2}|u\w{4}|U\w{8}|.)'/}]},{className:"symbol",begin:/'[a-zA-Z_][a-zA-Z0-9_]*/},{className:"number",variants:[{begin:"\\b0b([01_]+)"+n},{begin:"\\b0o([0-7_]+)"+n},{begin:"\\b0x([A-Fa-f0-9_]+)"+n},{begin:"\\b(\\d[\\d_]*(\\.[0-9_]+)?([eE][+-]?[0-9_]+)?)"+n}],relevance:0},{className:"function",beginKeywords:"fn",end:"(\\(|<)",excludeEnd:!0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"meta",begin:"#\\!?\\[",end:"\\]",contains:[{className:"meta-string",begin:/"/,end:/"/}]},{className:"class",beginKeywords:"type",end:";",contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{endsParent:!0})],illegal:"\\S"},{className:"class",beginKeywords:"trait enum struct union",end:"{",contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{endsParent:!0})],illegal:"[\\w\\d]"},{begin:e.IDENT_RE+"::",keywords:{built_in:t}},{begin:"->"}]}}}());hljs.registerLanguage("cpp",function(){"use strict";return function(e){var t=e.getLanguage("c-like").rawDefinition();return t.disableAutodetect=!1,t.name="C++",t.aliases=["cc","c++","h++","hpp","hh","hxx","cxx"],t}}());hljs.registerLanguage("ini",function(){"use strict";function e(e){return e?"string"==typeof e?e:e.source:null}function n(...n){return n.map(n=>e(n)).join("")}return function(a){var s={className:"number",relevance:0,variants:[{begin:/([\+\-]+)?[\d]+_[\d_]+/},{begin:a.NUMBER_RE}]},i=a.COMMENT();i.variants=[{begin:/;/,end:/$/},{begin:/#/,end:/$/}];var t={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{begin:/\$\{(.*?)}/}]},r={className:"literal",begin:/\bon|off|true|false|yes|no\b/},l={className:"string",contains:[a.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}]},c={begin:/\[/,end:/\]/,contains:[i,r,t,l,s,"self"],relevance:0},g="("+[/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/].map(n=>e(n)).join("|")+")";return{name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/,contains:[i,{className:"section",begin:/\[+/,end:/\]+/},{begin:n(g,"(\\s*\\.\\s*",g,")*",n("(?=",/\s*=\s*[^#\s]/,")")),className:"attr",starts:{end:/$/,contains:[i,c,r,t,l,s]}}]}}}());hljs.registerLanguage("objectivec",function(){"use strict";return function(e){var n=/[a-zA-Z@][a-zA-Z0-9_]*/,_={$pattern:n,keyword:"@interface @class @protocol @implementation"};return{name:"Objective-C",aliases:["mm","objc","obj-c"],keywords:{$pattern:n,keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required @encode @package @import @defs @compatibility_alias __bridge __bridge_transfer __bridge_retained __bridge_retain __covariant __contravariant __kindof _Nonnull _Nullable _Null_unspecified __FUNCTION__ __PRETTY_FUNCTION__ __attribute__ getter setter retain unsafe_unretained nonnull nullable null_unspecified null_resettable class instancetype NS_DESIGNATED_INITIALIZER NS_UNAVAILABLE NS_REQUIRES_SUPER NS_RETURNS_INNER_POINTER NS_INLINE NS_AVAILABLE NS_DEPRECATED NS_ENUM NS_OPTIONS NS_SWIFT_UNAVAILABLE NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_REFINED_FOR_SWIFT NS_SWIFT_NAME NS_SWIFT_NOTHROW NS_DURING NS_HANDLER NS_ENDHANDLER NS_VALUERETURN NS_VOIDRETURN",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"},illegal:"</",contains:[{className:"built_in",begin:"\\b(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)\\w+"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.C_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{className:"string",variants:[{begin:'@"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]}]},{className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{"meta-keyword":"if else elif endif define undef warning error line pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(e.QUOTE_STRING_MODE,{className:"meta-string"}),{className:"meta-string",begin:/<.*?>/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",begin:"("+_.keyword.split(" ").join("|")+")\\b",end:"({|$)",excludeEnd:!0,keywords:_,contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}}}());hljs.registerLanguage("apache",function(){"use strict";return function(e){var n={className:"number",begin:"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?"};return{name:"Apache config",aliases:["apacheconf"],case_insensitive:!0,contains:[e.HASH_COMMENT_MODE,{className:"section",begin:"</?",end:">",contains:[n,{className:"number",begin:":\\d{1,5}"},e.inherit(e.QUOTE_STRING_MODE,{relevance:0})]},{className:"attribute",begin:/\w+/,relevance:0,keywords:{nomarkup:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{end:/$/,relevance:0,keywords:{literal:"on off all deny allow"},contains:[{className:"meta",begin:"\\s\\[",end:"\\]$"},{className:"variable",begin:"[\\$%]\\{",end:"\\}",contains:["self",{className:"number",begin:"[\\$%]\\d+"}]},n,{className:"number",begin:"\\d+"},e.QUOTE_STRING_MODE]}}],illegal:/\S/}}}());hljs.registerLanguage("java",function(){"use strict";function e(e){return e?"string"==typeof e?e:e.source:null}function n(e){return a("(",e,")?")}function a(...n){return n.map(n=>e(n)).join("")}function s(...n){return"("+n.map(n=>e(n)).join("|")+")"}return function(e){var t="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",i={className:"meta",begin:"@[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",contains:[{begin:/\(/,end:/\)/,contains:["self"]}]},r=e=>a("[",e,"]+([",e,"_]*[",e,"]+)?"),c={className:"number",variants:[{begin:`\\b(0[bB]${r("01")})[lL]?`},{begin:`\\b(0${r("0-7")})[dDfFlL]?`},{begin:a(/\b0[xX]/,s(a(r("a-fA-F0-9"),/\./,r("a-fA-F0-9")),a(r("a-fA-F0-9"),/\.?/),a(/\./,r("a-fA-F0-9"))),/([pP][+-]?(\d+))?/,/[fFdDlL]?/)},{begin:a(/\b/,s(a(/\d*\./,r("\\d")),r("\\d")),/[eE][+-]?[\d]+[dDfF]?/)},{begin:a(/\b/,r(/\d/),n(/\.?/),n(r(/\d/)),/[dDfFlL]?/)}],relevance:0};return{name:"Java",aliases:["jsp"],keywords:t,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"class",beginKeywords:"class interface",end:/[{;=]/,excludeEnd:!0,keywords:"class interface",illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"new throw return else",relevance:0},{className:"function",begin:"([À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(<[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(\\s*,\\s*[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*)*>)?\\s+)+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:t,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/,keywords:t,relevance:0,contains:[i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},c,i]}}}());hljs.registerLanguage("x86asm",function(){"use strict";return function(s){return{name:"Intel x86 Assembly",case_insensitive:!0,keywords:{$pattern:"[.%]?"+s.IDENT_RE,keyword:"lock rep repe repz repne repnz xaquire xrelease bnd nobnd aaa aad aam aas adc add and arpl bb0_reset bb1_reset bound bsf bsr bswap bt btc btr bts call cbw cdq cdqe clc cld cli clts cmc cmp cmpsb cmpsd cmpsq cmpsw cmpxchg cmpxchg486 cmpxchg8b cmpxchg16b cpuid cpu_read cpu_write cqo cwd cwde daa das dec div dmint emms enter equ f2xm1 fabs fadd faddp fbld fbstp fchs fclex fcmovb fcmovbe fcmove fcmovnb fcmovnbe fcmovne fcmovnu fcmovu fcom fcomi fcomip fcomp fcompp fcos fdecstp fdisi fdiv fdivp fdivr fdivrp femms feni ffree ffreep fiadd ficom ficomp fidiv fidivr fild fimul fincstp finit fist fistp fisttp fisub fisubr fld fld1 fldcw fldenv fldl2e fldl2t fldlg2 fldln2 fldpi fldz fmul fmulp fnclex fndisi fneni fninit fnop fnsave fnstcw fnstenv fnstsw fpatan fprem fprem1 fptan frndint frstor fsave fscale fsetpm fsin fsincos fsqrt fst fstcw fstenv fstp fstsw fsub fsubp fsubr fsubrp ftst fucom fucomi fucomip fucomp fucompp fxam fxch fxtract fyl2x fyl2xp1 hlt ibts icebp idiv imul in inc incbin insb insd insw int int01 int1 int03 int3 into invd invpcid invlpg invlpga iret iretd iretq iretw jcxz jecxz jrcxz jmp jmpe lahf lar lds lea leave les lfence lfs lgdt lgs lidt lldt lmsw loadall loadall286 lodsb lodsd lodsq lodsw loop loope loopne loopnz loopz lsl lss ltr mfence monitor mov movd movq movsb movsd movsq movsw movsx movsxd movzx mul mwait neg nop not or out outsb outsd outsw packssdw packsswb packuswb paddb paddd paddsb paddsiw paddsw paddusb paddusw paddw pand pandn pause paveb pavgusb pcmpeqb pcmpeqd pcmpeqw pcmpgtb pcmpgtd pcmpgtw pdistib pf2id pfacc pfadd pfcmpeq pfcmpge pfcmpgt pfmax pfmin pfmul pfrcp pfrcpit1 pfrcpit2 pfrsqit1 pfrsqrt pfsub pfsubr pi2fd pmachriw pmaddwd pmagw pmulhriw pmulhrwa pmulhrwc pmulhw pmullw pmvgezb pmvlzb pmvnzb pmvzb pop popa popad popaw popf popfd popfq popfw por prefetch prefetchw pslld psllq psllw psrad psraw psrld psrlq psrlw psubb psubd psubsb psubsiw psubsw psubusb psubusw psubw punpckhbw punpckhdq punpckhwd punpcklbw punpckldq punpcklwd push pusha pushad pushaw pushf pushfd pushfq pushfw pxor rcl rcr rdshr rdmsr rdpmc rdtsc rdtscp ret retf retn rol ror rdm rsdc rsldt rsm rsts sahf sal salc sar sbb scasb scasd scasq scasw sfence sgdt shl shld shr shrd sidt sldt skinit smi smint smintold smsw stc std sti stosb stosd stosq stosw str sub svdc svldt svts swapgs syscall sysenter sysexit sysret test ud0 ud1 ud2b ud2 ud2a umov verr verw fwait wbinvd wrshr wrmsr xadd xbts xchg xlatb xlat xor cmove cmovz cmovne cmovnz cmova cmovnbe cmovae cmovnb cmovb cmovnae cmovbe cmovna cmovg cmovnle cmovge cmovnl cmovl cmovnge cmovle cmovng cmovc cmovnc cmovo cmovno cmovs cmovns cmovp cmovpe cmovnp cmovpo je jz jne jnz ja jnbe jae jnb jb jnae jbe jna jg jnle jge jnl jl jnge jle jng jc jnc jo jno js jns jpo jnp jpe jp sete setz setne setnz seta setnbe setae setnb setnc setb setnae setcset setbe setna setg setnle setge setnl setl setnge setle setng sets setns seto setno setpe setp setpo setnp addps addss andnps andps cmpeqps cmpeqss cmpleps cmpless cmpltps cmpltss cmpneqps cmpneqss cmpnleps cmpnless cmpnltps cmpnltss cmpordps cmpordss cmpunordps cmpunordss cmpps cmpss comiss cvtpi2ps cvtps2pi cvtsi2ss cvtss2si cvttps2pi cvttss2si divps divss ldmxcsr maxps maxss minps minss movaps movhps movlhps movlps movhlps movmskps movntps movss movups mulps mulss orps rcpps rcpss rsqrtps rsqrtss shufps sqrtps sqrtss stmxcsr subps subss ucomiss unpckhps unpcklps xorps fxrstor fxrstor64 fxsave fxsave64 xgetbv xsetbv xsave xsave64 xsaveopt xsaveopt64 xrstor xrstor64 prefetchnta prefetcht0 prefetcht1 prefetcht2 maskmovq movntq pavgb pavgw pextrw pinsrw pmaxsw pmaxub pminsw pminub pmovmskb pmulhuw psadbw pshufw pf2iw pfnacc pfpnacc pi2fw pswapd maskmovdqu clflush movntdq movnti movntpd movdqa movdqu movdq2q movq2dq paddq pmuludq pshufd pshufhw pshuflw pslldq psrldq psubq punpckhqdq punpcklqdq addpd addsd andnpd andpd cmpeqpd cmpeqsd cmplepd cmplesd cmpltpd cmpltsd cmpneqpd cmpneqsd cmpnlepd cmpnlesd cmpnltpd cmpnltsd cmpordpd cmpordsd cmpunordpd cmpunordsd cmppd comisd cvtdq2pd cvtdq2ps cvtpd2dq cvtpd2pi cvtpd2ps cvtpi2pd cvtps2dq cvtps2pd cvtsd2si cvtsd2ss cvtsi2sd cvtss2sd cvttpd2pi cvttpd2dq cvttps2dq cvttsd2si divpd divsd maxpd maxsd minpd minsd movapd movhpd movlpd movmskpd movupd mulpd mulsd orpd shufpd sqrtpd sqrtsd subpd subsd ucomisd unpckhpd unpcklpd xorpd addsubpd addsubps haddpd haddps hsubpd hsubps lddqu movddup movshdup movsldup clgi stgi vmcall vmclear vmfunc vmlaunch vmload vmmcall vmptrld vmptrst vmread vmresume vmrun vmsave vmwrite vmxoff vmxon invept invvpid pabsb pabsw pabsd palignr phaddw phaddd phaddsw phsubw phsubd phsubsw pmaddubsw pmulhrsw pshufb psignb psignw psignd extrq insertq movntsd movntss lzcnt blendpd blendps blendvpd blendvps dppd dpps extractps insertps movntdqa mpsadbw packusdw pblendvb pblendw pcmpeqq pextrb pextrd pextrq phminposuw pinsrb pinsrd pinsrq pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq pmuldq pmulld ptest roundpd roundps roundsd roundss crc32 pcmpestri pcmpestrm pcmpistri pcmpistrm pcmpgtq popcnt getsec pfrcpv pfrsqrtv movbe aesenc aesenclast aesdec aesdeclast aesimc aeskeygenassist vaesenc vaesenclast vaesdec vaesdeclast vaesimc vaeskeygenassist vaddpd vaddps vaddsd vaddss vaddsubpd vaddsubps vandpd vandps vandnpd vandnps vblendpd vblendps vblendvpd vblendvps vbroadcastss vbroadcastsd vbroadcastf128 vcmpeq_ospd vcmpeqpd vcmplt_ospd vcmpltpd vcmple_ospd vcmplepd vcmpunord_qpd vcmpunordpd vcmpneq_uqpd vcmpneqpd vcmpnlt_uspd vcmpnltpd vcmpnle_uspd vcmpnlepd vcmpord_qpd vcmpordpd vcmpeq_uqpd vcmpnge_uspd vcmpngepd vcmpngt_uspd vcmpngtpd vcmpfalse_oqpd vcmpfalsepd vcmpneq_oqpd vcmpge_ospd vcmpgepd vcmpgt_ospd vcmpgtpd vcmptrue_uqpd vcmptruepd vcmplt_oqpd vcmple_oqpd vcmpunord_spd vcmpneq_uspd vcmpnlt_uqpd vcmpnle_uqpd vcmpord_spd vcmpeq_uspd vcmpnge_uqpd vcmpngt_uqpd vcmpfalse_ospd vcmpneq_ospd vcmpge_oqpd vcmpgt_oqpd vcmptrue_uspd vcmppd vcmpeq_osps vcmpeqps vcmplt_osps vcmpltps vcmple_osps vcmpleps vcmpunord_qps vcmpunordps vcmpneq_uqps vcmpneqps vcmpnlt_usps vcmpnltps vcmpnle_usps vcmpnleps vcmpord_qps vcmpordps vcmpeq_uqps vcmpnge_usps vcmpngeps vcmpngt_usps vcmpngtps vcmpfalse_oqps vcmpfalseps vcmpneq_oqps vcmpge_osps vcmpgeps vcmpgt_osps vcmpgtps vcmptrue_uqps vcmptrueps vcmplt_oqps vcmple_oqps vcmpunord_sps vcmpneq_usps vcmpnlt_uqps vcmpnle_uqps vcmpord_sps vcmpeq_usps vcmpnge_uqps vcmpngt_uqps vcmpfalse_osps vcmpneq_osps vcmpge_oqps vcmpgt_oqps vcmptrue_usps vcmpps vcmpeq_ossd vcmpeqsd vcmplt_ossd vcmpltsd vcmple_ossd vcmplesd vcmpunord_qsd vcmpunordsd vcmpneq_uqsd vcmpneqsd vcmpnlt_ussd vcmpnltsd vcmpnle_ussd vcmpnlesd vcmpord_qsd vcmpordsd vcmpeq_uqsd vcmpnge_ussd vcmpngesd vcmpngt_ussd vcmpngtsd vcmpfalse_oqsd vcmpfalsesd vcmpneq_oqsd vcmpge_ossd vcmpgesd vcmpgt_ossd vcmpgtsd vcmptrue_uqsd vcmptruesd vcmplt_oqsd vcmple_oqsd vcmpunord_ssd vcmpneq_ussd vcmpnlt_uqsd vcmpnle_uqsd vcmpord_ssd vcmpeq_ussd vcmpnge_uqsd vcmpngt_uqsd vcmpfalse_ossd vcmpneq_ossd vcmpge_oqsd vcmpgt_oqsd vcmptrue_ussd vcmpsd vcmpeq_osss vcmpeqss vcmplt_osss vcmpltss vcmple_osss vcmpless vcmpunord_qss vcmpunordss vcmpneq_uqss vcmpneqss vcmpnlt_usss vcmpnltss vcmpnle_usss vcmpnless vcmpord_qss vcmpordss vcmpeq_uqss vcmpnge_usss vcmpngess vcmpngt_usss vcmpngtss vcmpfalse_oqss vcmpfalsess vcmpneq_oqss vcmpge_osss vcmpgess vcmpgt_osss vcmpgtss vcmptrue_uqss vcmptruess vcmplt_oqss vcmple_oqss vcmpunord_sss vcmpneq_usss vcmpnlt_uqss vcmpnle_uqss vcmpord_sss vcmpeq_usss vcmpnge_uqss vcmpngt_uqss vcmpfalse_osss vcmpneq_osss vcmpge_oqss vcmpgt_oqss vcmptrue_usss vcmpss vcomisd vcomiss vcvtdq2pd vcvtdq2ps vcvtpd2dq vcvtpd2ps vcvtps2dq vcvtps2pd vcvtsd2si vcvtsd2ss vcvtsi2sd vcvtsi2ss vcvtss2sd vcvtss2si vcvttpd2dq vcvttps2dq vcvttsd2si vcvttss2si vdivpd vdivps vdivsd vdivss vdppd vdpps vextractf128 vextractps vhaddpd vhaddps vhsubpd vhsubps vinsertf128 vinsertps vlddqu vldqqu vldmxcsr vmaskmovdqu vmaskmovps vmaskmovpd vmaxpd vmaxps vmaxsd vmaxss vminpd vminps vminsd vminss vmovapd vmovaps vmovd vmovq vmovddup vmovdqa vmovqqa vmovdqu vmovqqu vmovhlps vmovhpd vmovhps vmovlhps vmovlpd vmovlps vmovmskpd vmovmskps vmovntdq vmovntqq vmovntdqa vmovntpd vmovntps vmovsd vmovshdup vmovsldup vmovss vmovupd vmovups vmpsadbw vmulpd vmulps vmulsd vmulss vorpd vorps vpabsb vpabsw vpabsd vpacksswb vpackssdw vpackuswb vpackusdw vpaddb vpaddw vpaddd vpaddq vpaddsb vpaddsw vpaddusb vpaddusw vpalignr vpand vpandn vpavgb vpavgw vpblendvb vpblendw vpcmpestri vpcmpestrm vpcmpistri vpcmpistrm vpcmpeqb vpcmpeqw vpcmpeqd vpcmpeqq vpcmpgtb vpcmpgtw vpcmpgtd vpcmpgtq vpermilpd vpermilps vperm2f128 vpextrb vpextrw vpextrd vpextrq vphaddw vphaddd vphaddsw vphminposuw vphsubw vphsubd vphsubsw vpinsrb vpinsrw vpinsrd vpinsrq vpmaddwd vpmaddubsw vpmaxsb vpmaxsw vpmaxsd vpmaxub vpmaxuw vpmaxud vpminsb vpminsw vpminsd vpminub vpminuw vpminud vpmovmskb vpmovsxbw vpmovsxbd vpmovsxbq vpmovsxwd vpmovsxwq vpmovsxdq vpmovzxbw vpmovzxbd vpmovzxbq vpmovzxwd vpmovzxwq vpmovzxdq vpmulhuw vpmulhrsw vpmulhw vpmullw vpmulld vpmuludq vpmuldq vpor vpsadbw vpshufb vpshufd vpshufhw vpshuflw vpsignb vpsignw vpsignd vpslldq vpsrldq vpsllw vpslld vpsllq vpsraw vpsrad vpsrlw vpsrld vpsrlq vptest vpsubb vpsubw vpsubd vpsubq vpsubsb vpsubsw vpsubusb vpsubusw vpunpckhbw vpunpckhwd vpunpckhdq vpunpckhqdq vpunpcklbw vpunpcklwd vpunpckldq vpunpcklqdq vpxor vrcpps vrcpss vrsqrtps vrsqrtss vroundpd vroundps vroundsd vroundss vshufpd vshufps vsqrtpd vsqrtps vsqrtsd vsqrtss vstmxcsr vsubpd vsubps vsubsd vsubss vtestps vtestpd vucomisd vucomiss vunpckhpd vunpckhps vunpcklpd vunpcklps vxorpd vxorps vzeroall vzeroupper pclmullqlqdq pclmulhqlqdq pclmullqhqdq pclmulhqhqdq pclmulqdq vpclmullqlqdq vpclmulhqlqdq vpclmullqhqdq vpclmulhqhqdq vpclmulqdq vfmadd132ps vfmadd132pd vfmadd312ps vfmadd312pd vfmadd213ps vfmadd213pd vfmadd123ps vfmadd123pd vfmadd231ps vfmadd231pd vfmadd321ps vfmadd321pd vfmaddsub132ps vfmaddsub132pd vfmaddsub312ps vfmaddsub312pd vfmaddsub213ps vfmaddsub213pd vfmaddsub123ps vfmaddsub123pd vfmaddsub231ps vfmaddsub231pd vfmaddsub321ps vfmaddsub321pd vfmsub132ps vfmsub132pd vfmsub312ps vfmsub312pd vfmsub213ps vfmsub213pd vfmsub123ps vfmsub123pd vfmsub231ps vfmsub231pd vfmsub321ps vfmsub321pd vfmsubadd132ps vfmsubadd132pd vfmsubadd312ps vfmsubadd312pd vfmsubadd213ps vfmsubadd213pd vfmsubadd123ps vfmsubadd123pd vfmsubadd231ps vfmsubadd231pd vfmsubadd321ps vfmsubadd321pd vfnmadd132ps vfnmadd132pd vfnmadd312ps vfnmadd312pd vfnmadd213ps vfnmadd213pd vfnmadd123ps vfnmadd123pd vfnmadd231ps vfnmadd231pd vfnmadd321ps vfnmadd321pd vfnmsub132ps vfnmsub132pd vfnmsub312ps vfnmsub312pd vfnmsub213ps vfnmsub213pd vfnmsub123ps vfnmsub123pd vfnmsub231ps vfnmsub231pd vfnmsub321ps vfnmsub321pd vfmadd132ss vfmadd132sd vfmadd312ss vfmadd312sd vfmadd213ss vfmadd213sd vfmadd123ss vfmadd123sd vfmadd231ss vfmadd231sd vfmadd321ss vfmadd321sd vfmsub132ss vfmsub132sd vfmsub312ss vfmsub312sd vfmsub213ss vfmsub213sd vfmsub123ss vfmsub123sd vfmsub231ss vfmsub231sd vfmsub321ss vfmsub321sd vfnmadd132ss vfnmadd132sd vfnmadd312ss vfnmadd312sd vfnmadd213ss vfnmadd213sd vfnmadd123ss vfnmadd123sd vfnmadd231ss vfnmadd231sd vfnmadd321ss vfnmadd321sd vfnmsub132ss vfnmsub132sd vfnmsub312ss vfnmsub312sd vfnmsub213ss vfnmsub213sd vfnmsub123ss vfnmsub123sd vfnmsub231ss vfnmsub231sd vfnmsub321ss vfnmsub321sd rdfsbase rdgsbase rdrand wrfsbase wrgsbase vcvtph2ps vcvtps2ph adcx adox rdseed clac stac xstore xcryptecb xcryptcbc xcryptctr xcryptcfb xcryptofb montmul xsha1 xsha256 llwpcb slwpcb lwpval lwpins vfmaddpd vfmaddps vfmaddsd vfmaddss vfmaddsubpd vfmaddsubps vfmsubaddpd vfmsubaddps vfmsubpd vfmsubps vfmsubsd vfmsubss vfnmaddpd vfnmaddps vfnmaddsd vfnmaddss vfnmsubpd vfnmsubps vfnmsubsd vfnmsubss vfrczpd vfrczps vfrczsd vfrczss vpcmov vpcomb vpcomd vpcomq vpcomub vpcomud vpcomuq vpcomuw vpcomw vphaddbd vphaddbq vphaddbw vphadddq vphaddubd vphaddubq vphaddubw vphaddudq vphadduwd vphadduwq vphaddwd vphaddwq vphsubbw vphsubdq vphsubwd vpmacsdd vpmacsdqh vpmacsdql vpmacssdd vpmacssdqh vpmacssdql vpmacsswd vpmacssww vpmacswd vpmacsww vpmadcsswd vpmadcswd vpperm vprotb vprotd vprotq vprotw vpshab vpshad vpshaq vpshaw vpshlb vpshld vpshlq vpshlw vbroadcasti128 vpblendd vpbroadcastb vpbroadcastw vpbroadcastd vpbroadcastq vpermd vpermpd vpermps vpermq vperm2i128 vextracti128 vinserti128 vpmaskmovd vpmaskmovq vpsllvd vpsllvq vpsravd vpsrlvd vpsrlvq vgatherdpd vgatherqpd vgatherdps vgatherqps vpgatherdd vpgatherqd vpgatherdq vpgatherqq xabort xbegin xend xtest andn bextr blci blcic blsi blsic blcfill blsfill blcmsk blsmsk blsr blcs bzhi mulx pdep pext rorx sarx shlx shrx tzcnt tzmsk t1mskc valignd valignq vblendmpd vblendmps vbroadcastf32x4 vbroadcastf64x4 vbroadcasti32x4 vbroadcasti64x4 vcompresspd vcompressps vcvtpd2udq vcvtps2udq vcvtsd2usi vcvtss2usi vcvttpd2udq vcvttps2udq vcvttsd2usi vcvttss2usi vcvtudq2pd vcvtudq2ps vcvtusi2sd vcvtusi2ss vexpandpd vexpandps vextractf32x4 vextractf64x4 vextracti32x4 vextracti64x4 vfixupimmpd vfixupimmps vfixupimmsd vfixupimmss vgetexppd vgetexpps vgetexpsd vgetexpss vgetmantpd vgetmantps vgetmantsd vgetmantss vinsertf32x4 vinsertf64x4 vinserti32x4 vinserti64x4 vmovdqa32 vmovdqa64 vmovdqu32 vmovdqu64 vpabsq vpandd vpandnd vpandnq vpandq vpblendmd vpblendmq vpcmpltd vpcmpled vpcmpneqd vpcmpnltd vpcmpnled vpcmpd vpcmpltq vpcmpleq vpcmpneqq vpcmpnltq vpcmpnleq vpcmpq vpcmpequd vpcmpltud vpcmpleud vpcmpnequd vpcmpnltud vpcmpnleud vpcmpud vpcmpequq vpcmpltuq vpcmpleuq vpcmpnequq vpcmpnltuq vpcmpnleuq vpcmpuq vpcompressd vpcompressq vpermi2d vpermi2pd vpermi2ps vpermi2q vpermt2d vpermt2pd vpermt2ps vpermt2q vpexpandd vpexpandq vpmaxsq vpmaxuq vpminsq vpminuq vpmovdb vpmovdw vpmovqb vpmovqd vpmovqw vpmovsdb vpmovsdw vpmovsqb vpmovsqd vpmovsqw vpmovusdb vpmovusdw vpmovusqb vpmovusqd vpmovusqw vpord vporq vprold vprolq vprolvd vprolvq vprord vprorq vprorvd vprorvq vpscatterdd vpscatterdq vpscatterqd vpscatterqq vpsraq vpsravq vpternlogd vpternlogq vptestmd vptestmq vptestnmd vptestnmq vpxord vpxorq vrcp14pd vrcp14ps vrcp14sd vrcp14ss vrndscalepd vrndscaleps vrndscalesd vrndscaless vrsqrt14pd vrsqrt14ps vrsqrt14sd vrsqrt14ss vscalefpd vscalefps vscalefsd vscalefss vscatterdpd vscatterdps vscatterqpd vscatterqps vshuff32x4 vshuff64x2 vshufi32x4 vshufi64x2 kandnw kandw kmovw knotw kortestw korw kshiftlw kshiftrw kunpckbw kxnorw kxorw vpbroadcastmb2q vpbroadcastmw2d vpconflictd vpconflictq vplzcntd vplzcntq vexp2pd vexp2ps vrcp28pd vrcp28ps vrcp28sd vrcp28ss vrsqrt28pd vrsqrt28ps vrsqrt28sd vrsqrt28ss vgatherpf0dpd vgatherpf0dps vgatherpf0qpd vgatherpf0qps vgatherpf1dpd vgatherpf1dps vgatherpf1qpd vgatherpf1qps vscatterpf0dpd vscatterpf0dps vscatterpf0qpd vscatterpf0qps vscatterpf1dpd vscatterpf1dps vscatterpf1qpd vscatterpf1qps prefetchwt1 bndmk bndcl bndcu bndcn bndmov bndldx bndstx sha1rnds4 sha1nexte sha1msg1 sha1msg2 sha256rnds2 sha256msg1 sha256msg2 hint_nop0 hint_nop1 hint_nop2 hint_nop3 hint_nop4 hint_nop5 hint_nop6 hint_nop7 hint_nop8 hint_nop9 hint_nop10 hint_nop11 hint_nop12 hint_nop13 hint_nop14 hint_nop15 hint_nop16 hint_nop17 hint_nop18 hint_nop19 hint_nop20 hint_nop21 hint_nop22 hint_nop23 hint_nop24 hint_nop25 hint_nop26 hint_nop27 hint_nop28 hint_nop29 hint_nop30 hint_nop31 hint_nop32 hint_nop33 hint_nop34 hint_nop35 hint_nop36 hint_nop37 hint_nop38 hint_nop39 hint_nop40 hint_nop41 hint_nop42 hint_nop43 hint_nop44 hint_nop45 hint_nop46 hint_nop47 hint_nop48 hint_nop49 hint_nop50 hint_nop51 hint_nop52 hint_nop53 hint_nop54 hint_nop55 hint_nop56 hint_nop57 hint_nop58 hint_nop59 hint_nop60 hint_nop61 hint_nop62 hint_nop63",built_in:"ip eip rip al ah bl bh cl ch dl dh sil dil bpl spl r8b r9b r10b r11b r12b r13b r14b r15b ax bx cx dx si di bp sp r8w r9w r10w r11w r12w r13w r14w r15w eax ebx ecx edx esi edi ebp esp eip r8d r9d r10d r11d r12d r13d r14d r15d rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15 cs ds es fs gs ss st st0 st1 st2 st3 st4 st5 st6 st7 mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15 xmm16 xmm17 xmm18 xmm19 xmm20 xmm21 xmm22 xmm23 xmm24 xmm25 xmm26 xmm27 xmm28 xmm29 xmm30 xmm31 ymm0 ymm1 ymm2 ymm3 ymm4 ymm5 ymm6 ymm7 ymm8 ymm9 ymm10 ymm11 ymm12 ymm13 ymm14 ymm15 ymm16 ymm17 ymm18 ymm19 ymm20 ymm21 ymm22 ymm23 ymm24 ymm25 ymm26 ymm27 ymm28 ymm29 ymm30 ymm31 zmm0 zmm1 zmm2 zmm3 zmm4 zmm5 zmm6 zmm7 zmm8 zmm9 zmm10 zmm11 zmm12 zmm13 zmm14 zmm15 zmm16 zmm17 zmm18 zmm19 zmm20 zmm21 zmm22 zmm23 zmm24 zmm25 zmm26 zmm27 zmm28 zmm29 zmm30 zmm31 k0 k1 k2 k3 k4 k5 k6 k7 bnd0 bnd1 bnd2 bnd3 cr0 cr1 cr2 cr3 cr4 cr8 dr0 dr1 dr2 dr3 dr8 tr3 tr4 tr5 tr6 tr7 r0 r1 r2 r3 r4 r5 r6 r7 r0b r1b r2b r3b r4b r5b r6b r7b r0w r1w r2w r3w r4w r5w r6w r7w r0d r1d r2d r3d r4d r5d r6d r7d r0h r1h r2h r3h r0l r1l r2l r3l r4l r5l r6l r7l r8l r9l r10l r11l r12l r13l r14l r15l db dw dd dq dt ddq do dy dz resb resw resd resq rest resdq reso resy resz incbin equ times byte word dword qword nosplit rel abs seg wrt strict near far a32 ptr",meta:"%define %xdefine %+ %undef %defstr %deftok %assign %strcat %strlen %substr %rotate %elif %else %endif %if %ifmacro %ifctx %ifidn %ifidni %ifid %ifnum %ifstr %iftoken %ifempty %ifenv %error %warning %fatal %rep %endrep %include %push %pop %repl %pathsearch %depend %use %arg %stacksize %local %line %comment %endcomment .nolist __FILE__ __LINE__ __SECT__ __BITS__ __OUTPUT_FORMAT__ __DATE__ __TIME__ __DATE_NUM__ __TIME_NUM__ __UTC_DATE__ __UTC_TIME__ __UTC_DATE_NUM__ __UTC_TIME_NUM__ __PASS__ struc endstruc istruc at iend align alignb sectalign daz nodaz up down zero default option assume public bits use16 use32 use64 default section segment absolute extern global common cpu float __utf16__ __utf16le__ __utf16be__ __utf32__ __utf32le__ __utf32be__ __float8__ __float16__ __float32__ __float64__ __float80m__ __float80e__ __float128l__ __float128h__ __Infinity__ __QNaN__ __SNaN__ Inf NaN QNaN SNaN float8 float16 float32 float64 float80m float80e float128l float128h __FLOAT_DAZ__ __FLOAT_ROUND__ __FLOAT__"},contains:[s.COMMENT(";","$",{relevance:0}),{className:"number",variants:[{begin:"\\b(?:([0-9][0-9_]*)?\\.[0-9_]*(?:[eE][+-]?[0-9_]+)?|(0[Xx])?[0-9][0-9_]*\\.?[0-9_]*(?:[pP](?:[+-]?[0-9_]+)?)?)\\b",relevance:0},{begin:"\\$[0-9][0-9A-Fa-f]*",relevance:0},{begin:"\\b(?:[0-9A-Fa-f][0-9A-Fa-f_]*[Hh]|[0-9][0-9_]*[DdTt]?|[0-7][0-7_]*[QqOo]|[0-1][0-1_]*[BbYy])\\b"},{begin:"\\b(?:0[Xx][0-9A-Fa-f_]+|0[DdTt][0-9_]+|0[QqOo][0-7_]+|0[BbYy][0-1_]+)\\b"}]},s.QUOTE_STRING_MODE,{className:"string",variants:[{begin:"'",end:"[^\\\\]'"},{begin:"`",end:"[^\\\\]`"}],relevance:0},{className:"symbol",variants:[{begin:"^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)"},{begin:"^\\s*%%[A-Za-z0-9_$#@~.?]*:"}],relevance:0},{className:"subst",begin:"%[0-9]+",relevance:0},{className:"subst",begin:"%!S+",relevance:0},{className:"meta",begin:/^\s*\.[\w_-]+/}]}}}());hljs.registerLanguage("kotlin",function(){"use strict";return function(e){var n={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual trait volatile transient native default",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},a={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"},i={className:"subst",begin:"\\${",end:"}",contains:[e.C_NUMBER_MODE]},s={className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},t={className:"string",variants:[{begin:'"""',end:'"""(?=[^"])',contains:[s,i]},{begin:"'",end:"'",illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,s,i]}]};i.contains.push(t);var r={className:"meta",begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"},l={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,end:/\)/,contains:[e.inherit(t,{className:"meta-string"})]}]},c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),o={variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}]},d=o;return d.variants[1].contains=[o],o.variants[1].contains=[d],{name:"Kotlin",aliases:["kt"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",begin:/@\w+/}]}},a,r,l,{className:"function",beginKeywords:"fun",end:"[(]|$",returnBegin:!0,excludeEnd:!0,keywords:n,illegal:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,relevance:5,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin:/</,end:/>/,keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,endsWithParent:!0,contains:[o,e.C_LINE_COMMENT_MODE,c],relevance:0},e.C_LINE_COMMENT_MODE,c,r,l,t,e.C_NUMBER_MODE]},c]},{className:"class",beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,illegal:"extends implements",contains:[{beginKeywords:"public protected internal private constructor"},e.UNDERSCORE_TITLE_MODE,{className:"type",begin:/</,end:/>/,excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,excludeBegin:!0,returnEnd:!0},r,l]},t,{className:"meta",begin:"^#!/usr/bin/env",end:"$",illegal:"\n"},{className:"number",begin:"\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",relevance:0}]}}}());hljs.registerLanguage("armasm",function(){"use strict";return function(s){const e={variants:[s.COMMENT("^[ \\t]*(?=#)","$",{relevance:0,excludeBegin:!0}),s.COMMENT("[;@]","$",{relevance:0}),s.C_LINE_COMMENT_MODE,s.C_BLOCK_COMMENT_MODE]};return{name:"ARM Assembly",case_insensitive:!0,aliases:["arm"],keywords:{$pattern:"\\.?"+s.IDENT_RE,meta:".2byte .4byte .align .ascii .asciz .balign .byte .code .data .else .end .endif .endm .endr .equ .err .exitm .extern .global .hword .if .ifdef .ifndef .include .irp .long .macro .rept .req .section .set .skip .space .text .word .arm .thumb .code16 .code32 .force_thumb .thumb_func .ltorg ALIAS ALIGN ARM AREA ASSERT ATTR CN CODE CODE16 CODE32 COMMON CP DATA DCB DCD DCDU DCDO DCFD DCFDU DCI DCQ DCQU DCW DCWU DN ELIF ELSE END ENDFUNC ENDIF ENDP ENTRY EQU EXPORT EXPORTAS EXTERN FIELD FILL FUNCTION GBLA GBLL GBLS GET GLOBAL IF IMPORT INCBIN INCLUDE INFO KEEP LCLA LCLL LCLS LTORG MACRO MAP MEND MEXIT NOFP OPT PRESERVE8 PROC QN READONLY RELOC REQUIRE REQUIRE8 RLIST FN ROUT SETA SETL SETS SN SPACE SUBT THUMB THUMBX TTL WHILE WEND ",built_in:"r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 pc lr sp ip sl sb fp a1 a2 a3 a4 v1 v2 v3 v4 v5 v6 v7 v8 f0 f1 f2 f3 f4 f5 f6 f7 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 q0 q1 q2 q3 q4 q5 q6 q7 q8 q9 q10 q11 q12 q13 q14 q15 cpsr_c cpsr_x cpsr_s cpsr_f cpsr_cx cpsr_cxs cpsr_xs cpsr_xsf cpsr_sf cpsr_cxsf spsr_c spsr_x spsr_s spsr_f spsr_cx spsr_cxs spsr_xs spsr_xsf spsr_sf spsr_cxsf s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 s16 s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 s29 s30 s31 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 d11 d12 d13 d14 d15 d16 d17 d18 d19 d20 d21 d22 d23 d24 d25 d26 d27 d28 d29 d30 d31 {PC} {VAR} {TRUE} {FALSE} {OPT} {CONFIG} {ENDIAN} {CODESIZE} {CPU} {FPU} {ARCHITECTURE} {PCSTOREOFFSET} {ARMASM_VERSION} {INTER} {ROPI} {RWPI} {SWST} {NOSWST} . @"},contains:[{className:"keyword",begin:"\\b(adc|(qd?|sh?|u[qh]?)?add(8|16)?|usada?8|(q|sh?|u[qh]?)?(as|sa)x|and|adrl?|sbc|rs[bc]|asr|b[lx]?|blx|bxj|cbn?z|tb[bh]|bic|bfc|bfi|[su]bfx|bkpt|cdp2?|clz|clrex|cmp|cmn|cpsi[ed]|cps|setend|dbg|dmb|dsb|eor|isb|it[te]{0,3}|lsl|lsr|ror|rrx|ldm(([id][ab])|f[ds])?|ldr((s|ex)?[bhd])?|movt?|mvn|mra|mar|mul|[us]mull|smul[bwt][bt]|smu[as]d|smmul|smmla|mla|umlaal|smlal?([wbt][bt]|d)|mls|smlsl?[ds]|smc|svc|sev|mia([bt]{2}|ph)?|mrr?c2?|mcrr2?|mrs|msr|orr|orn|pkh(tb|bt)|rbit|rev(16|sh)?|sel|[su]sat(16)?|nop|pop|push|rfe([id][ab])?|stm([id][ab])?|str(ex)?[bhd]?|(qd?)?sub|(sh?|q|u[qh]?)?sub(8|16)|[su]xt(a?h|a?b(16)?)|srs([id][ab])?|swpb?|swi|smi|tst|teq|wfe|wfi|yield)(eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo)?[sptrx]?(?=\\s)"},e,s.QUOTE_STRING_MODE,{className:"string",begin:"'",end:"[^\\\\]'",relevance:0},{className:"title",begin:"\\|",end:"\\|",illegal:"\\n",relevance:0},{className:"number",variants:[{begin:"[#$=]?0x[0-9a-f]+"},{begin:"[#$=]?0b[01]+"},{begin:"[#$=]\\d+"},{begin:"\\b\\d+"}],relevance:0},{className:"symbol",variants:[{begin:"^[ \\t]*[a-z_\\.\\$][a-z0-9_\\.\\$]+:"},{begin:"^[a-z_\\.\\$][a-z0-9_\\.\\$]+"},{begin:"[=#]\\w+"}],relevance:0}]}}}());hljs.registerLanguage("go",function(){"use strict";return function(e){var n={keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune",literal:"true false iota nil",built_in:"append cap close complex copy imag len make new panic print println real recover delete"};return{name:"Go",aliases:["golang"],keywords:n,illegal:"</",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"string",variants:[e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{begin:"`",end:"`"}]},{className:"number",variants:[{begin:e.C_NUMBER_RE+"[i]",relevance:1},e.C_NUMBER_MODE]},{begin:/:=/},{className:"function",beginKeywords:"func",end:"\\s*(\\{|$)",excludeEnd:!0,contains:[e.TITLE_MODE,{className:"params",begin:/\(/,end:/\)/,keywords:n,illegal:/["']/}]}]}}}());hljs.registerLanguage("diff",function(){"use strict";return function(e){return{name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,variants:[{begin:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{begin:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{begin:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{className:"comment",variants:[{begin:/Index: /,end:/$/},{begin:/={3,}/,end:/$/},{begin:/^\-{3}/,end:/$/},{begin:/^\*{3} /,end:/$/},{begin:/^\+{3}/,end:/$/},{begin:/^\*{15}$/}]},{className:"addition",begin:"^\\+",end:"$"},{className:"deletion",begin:"^\\-",end:"$"},{className:"addition",begin:"^\\!",end:"$"}]}}}());hljs.registerLanguage("python",function(){"use strict";return function(e){var n={keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda async await nonlocal|10",built_in:"Ellipsis NotImplemented",literal:"False None True"},a={className:"meta",begin:/^(>>>|\.\.\.) /},i={className:"subst",begin:/\{/,end:/\}/,keywords:n,illegal:/#/},s={begin:/\{\{/,relevance:0},r={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:/(u|b)?r?'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(u|b)?r?"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(fr|rf|f)'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(fr|rf|f)"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(u|r|ur)'/,end:/'/,relevance:10},{begin:/(u|r|ur)"/,end:/"/,relevance:10},{begin:/(b|br)'/,end:/'/},{begin:/(b|br)"/,end:/"/},{begin:/(fr|rf|f)'/,end:/'/,contains:[e.BACKSLASH_ESCAPE,s,i]},{begin:/(fr|rf|f)"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,i]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},l={className:"number",relevance:0,variants:[{begin:e.BINARY_NUMBER_RE+"[lLjJ]?"},{begin:"\\b(0o[0-7]+)[lLjJ]?"},{begin:e.C_NUMBER_RE+"[lLjJ]?"}]},t={className:"params",variants:[{begin:/\(\s*\)/,skip:!0,className:null},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:["self",a,l,r,e.HASH_COMMENT_MODE]}]};return i.contains=[r,l,a],{name:"Python",aliases:["py","gyp","ipython"],keywords:n,illegal:/(<\/|->|\?)|=>/,contains:[a,l,{beginKeywords:"if",relevance:0},r,e.HASH_COMMENT_MODE,{variants:[{className:"function",beginKeywords:"def"},{className:"class",beginKeywords:"class"}],end:/:/,illegal:/[${=;\n,]/,contains:[e.UNDERSCORE_TITLE_MODE,t,{begin:/->/,endsWithParent:!0,keywords:"None"}]},{className:"meta",begin:/^[\t ]*@/,end:/$/},{begin:/\b(print|exec)\(/}]}}}());hljs.registerLanguage("shell",function(){"use strict";return function(s){return{name:"Shell Session",aliases:["console"],contains:[{className:"meta",begin:"^\\s{0,3}[/\\w\\d\\[\\]()@-]*[>%$#]",starts:{end:"$",subLanguage:"bash"}}]}}}());hljs.registerLanguage("scala",function(){"use strict";return function(e){var n={className:"subst",variants:[{begin:"\\$[A-Za-z0-9_]+"},{begin:"\\${",end:"}"}]},a={className:"string",variants:[{begin:'"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:'"""',end:'"""',relevance:10},{begin:'[a-z]+"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE,n]},{className:"string",begin:'[a-z]+"""',end:'"""',contains:[n],relevance:10}]},s={className:"type",begin:"\\b[A-Z][A-Za-z0-9_]*",relevance:0},t={className:"title",begin:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,relevance:0},i={className:"class",beginKeywords:"class object trait type",end:/[:={\[\n;]/,excludeEnd:!0,contains:[{beginKeywords:"extends with",relevance:10},{begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},t]},l={className:"function",beginKeywords:"def",end:/[:={\[(\n;]/,excludeEnd:!0,contains:[t]};return{name:"Scala",keywords:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,{className:"symbol",begin:"'\\w[\\w\\d_]*(?!')"},s,l,i,e.C_NUMBER_MODE,{className:"meta",begin:"@[A-Za-z]+"}]}}}());hljs.registerLanguage("julia",function(){"use strict";return function(e){var r="[A-Za-z_\\u00A1-\\uFFFF][A-Za-z_0-9\\u00A1-\\uFFFF]*",t={$pattern:r,keyword:"in isa where baremodule begin break catch ccall const continue do else elseif end export false finally for function global if import importall let local macro module quote return true try using while type immutable abstract bitstype typealias ",literal:"true false ARGS C_NULL DevNull ENDIAN_BOM ENV I Inf Inf16 Inf32 Inf64 InsertionSort JULIA_HOME LOAD_PATH MergeSort NaN NaN16 NaN32 NaN64 PROGRAM_FILE QuickSort RoundDown RoundFromZero RoundNearest RoundNearestTiesAway RoundNearestTiesUp RoundToZero RoundUp STDERR STDIN STDOUT VERSION catalan e|0 eu|0 eulergamma golden im nothing pi γ π φ ",built_in:"ANY AbstractArray AbstractChannel AbstractFloat AbstractMatrix AbstractRNG AbstractSerializer AbstractSet AbstractSparseArray AbstractSparseMatrix AbstractSparseVector AbstractString AbstractUnitRange AbstractVecOrMat AbstractVector Any ArgumentError Array AssertionError Associative Base64DecodePipe Base64EncodePipe Bidiagonal BigFloat BigInt BitArray BitMatrix BitVector Bool BoundsError BufferStream CachingPool CapturedException CartesianIndex CartesianRange Cchar Cdouble Cfloat Channel Char Cint Cintmax_t Clong Clonglong ClusterManager Cmd CodeInfo Colon Complex Complex128 Complex32 Complex64 CompositeException Condition ConjArray ConjMatrix ConjVector Cptrdiff_t Cshort Csize_t Cssize_t Cstring Cuchar Cuint Cuintmax_t Culong Culonglong Cushort Cwchar_t Cwstring DataType Date DateFormat DateTime DenseArray DenseMatrix DenseVecOrMat DenseVector Diagonal Dict DimensionMismatch Dims DirectIndexString Display DivideError DomainError EOFError EachLine Enum Enumerate ErrorException Exception ExponentialBackOff Expr Factorization FileMonitor Float16 Float32 Float64 Function Future GlobalRef GotoNode HTML Hermitian IO IOBuffer IOContext IOStream IPAddr IPv4 IPv6 IndexCartesian IndexLinear IndexStyle InexactError InitError Int Int128 Int16 Int32 Int64 Int8 IntSet Integer InterruptException InvalidStateException Irrational KeyError LabelNode LinSpace LineNumberNode LoadError LowerTriangular MIME Matrix MersenneTwister Method MethodError MethodTable Module NTuple NewvarNode NullException Nullable Number ObjectIdDict OrdinalRange OutOfMemoryError OverflowError Pair ParseError PartialQuickSort PermutedDimsArray Pipe PollingFileWatcher ProcessExitedException Ptr QuoteNode RandomDevice Range RangeIndex Rational RawFD ReadOnlyMemoryError Real ReentrantLock Ref Regex RegexMatch RemoteChannel RemoteException RevString RoundingMode RowVector SSAValue SegmentationFault SerializationState Set SharedArray SharedMatrix SharedVector Signed SimpleVector Slot SlotNumber SparseMatrixCSC SparseVector StackFrame StackOverflowError StackTrace StepRange StepRangeLen StridedArray StridedMatrix StridedVecOrMat StridedVector String SubArray SubString SymTridiagonal Symbol Symmetric SystemError TCPSocket Task Text TextDisplay Timer Tridiagonal Tuple Type TypeError TypeMapEntry TypeMapLevel TypeName TypeVar TypedSlot UDPSocket UInt UInt128 UInt16 UInt32 UInt64 UInt8 UndefRefError UndefVarError UnicodeError UniformScaling Union UnionAll UnitRange Unsigned UpperTriangular Val Vararg VecElement VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef WorkerConfig WorkerPool "},a={keywords:t,illegal:/<\//},n={className:"subst",begin:/\$\(/,end:/\)/,keywords:t},o={className:"variable",begin:"\\$"+r},i={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],variants:[{begin:/\w*"""/,end:/"""\w*/,relevance:10},{begin:/\w*"/,end:/"\w*/}]},l={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],begin:"`",end:"`"},s={className:"meta",begin:"@"+r};return a.name="Julia",a.contains=[{className:"number",begin:/(\b0x[\d_]*(\.[\d_]*)?|0x\.\d[\d_]*)p[-+]?\d+|\b0[box][a-fA-F0-9][a-fA-F0-9_]*|(\b\d[\d_]*(\.[\d_]*)?|\.\d[\d_]*)([eEfF][-+]?\d+)?/,relevance:0},{className:"string",begin:/'(.|\\[xXuU][a-zA-Z0-9]+)'/},i,l,s,{className:"comment",variants:[{begin:"#=",end:"=#",relevance:10},{begin:"#",end:"$"}]},e.HASH_COMMENT_MODE,{className:"keyword",begin:"\\b(((abstract|primitive)\\s+)type|(mutable\\s+)?struct)\\b"},{begin:/<:/}],n.contains=a.contains,a}}());hljs.registerLanguage("php-template",function(){"use strict";return function(n){return{name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0},n.inherit(n.APOS_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0}),n.inherit(n.QUOTE_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0})]}]}}}());hljs.registerLanguage("scss",function(){"use strict";return function(e){var t={className:"variable",begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b"},i={className:"number",begin:"#[0-9A-Fa-f]+"};return e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{name:"SCSS",case_insensitive:!0,illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"selector-id",begin:"\\#[A-Za-z0-9_-]+",relevance:0},{className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0},{className:"selector-attr",begin:"\\[",end:"\\]",illegal:"$"},{className:"selector-tag",begin:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b",relevance:0},{className:"selector-pseudo",begin:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)"},{className:"selector-pseudo",begin:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)"},t,{className:"attribute",begin:"\\b(src|z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background-blend-mode|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b",illegal:"[^\\s]"},{begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{begin:":",end:";",contains:[t,i,e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{className:"meta",begin:"!important"}]},{begin:"@(page|font-face)",lexemes:"@[a-z-]+",keywords:"@page @font-face"},{begin:"@",end:"[{;]",returnBegin:!0,keywords:"and or not only",contains:[{begin:"@[a-z-]+",className:"keyword"},t,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,i,e.CSS_NUMBER_MODE]}]}}}());hljs.registerLanguage("r",function(){"use strict";return function(e){var n="([a-zA-Z]|\\.[a-zA-Z.])[a-zA-Z0-9._]*";return{name:"R",contains:[e.HASH_COMMENT_MODE,{begin:n,keywords:{$pattern:n,keyword:"function if in break next repeat else for return switch while try tryCatch stop warning require library attach detach source setMethod setGeneric setGroupGeneric setClass ...",literal:"NULL NA TRUE FALSE T F Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10"},relevance:0},{className:"number",begin:"0[xX][0-9a-fA-F]+[Li]?\\b",relevance:0},{className:"number",begin:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",relevance:0},{className:"number",begin:"\\d+\\.(?!\\d)(?:i\\b)?",relevance:0},{className:"number",begin:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{className:"number",begin:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{begin:"`",end:"`",relevance:0},{className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:'"',end:'"'},{begin:"'",end:"'"}]}]}}}());hljs.registerLanguage("sql",function(){"use strict";return function(e){var t=e.COMMENT("--","$");return{name:"SQL",case_insensitive:!0,illegal:/[<>{}*]/,contains:[{beginKeywords:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment values with",end:/;/,endsWithParent:!0,keywords:{$pattern:/[\w\.]+/,keyword:"as abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias all allocate allow alter always analyze ancillary and anti any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound bucket buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain explode export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force foreign form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour hours http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lateral lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minutes minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notnull notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second seconds section securefile security seed segment select self semi sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tablesample tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unnest unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace window with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null unknown",built_in:"array bigint binary bit blob bool boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text time timestamp tinyint varchar varchar2 varying void"},contains:[{className:"string",begin:"'",end:"'",contains:[{begin:"''"}]},{className:"string",begin:'"',end:'"',contains:[{begin:'""'}]},{className:"string",begin:"`",end:"`"},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]},e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]}}}());hljs.registerLanguage("c",function(){"use strict";return function(e){var n=e.getLanguage("c-like").rawDefinition();return n.name="C",n.aliases=["c","h"],n}}());hljs.registerLanguage("json",function(){"use strict";return function(n){var e={literal:"true false null"},i=[n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],t=[n.QUOTE_STRING_MODE,n.C_NUMBER_MODE],a={end:",",endsWithParent:!0,excludeEnd:!0,contains:t,keywords:e},l={begin:"{",end:"}",contains:[{className:"attr",begin:/"/,end:/"/,contains:[n.BACKSLASH_ESCAPE],illegal:"\\n"},n.inherit(a,{begin:/:/})].concat(i),illegal:"\\S"},s={begin:"\\[",end:"\\]",contains:[n.inherit(a)],illegal:"\\S"};return t.push(l,s),i.forEach((function(n){t.push(n)})),{name:"JSON",contains:t,keywords:e,illegal:"\\S"}}}());hljs.registerLanguage("python-repl",function(){"use strict";return function(n){return{aliases:["pycon"],contains:[{className:"meta",starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}}}());hljs.registerLanguage("markdown",function(){"use strict";return function(n){const e={begin:"<",end:">",subLanguage:"xml",relevance:0},a={begin:"\\[.+?\\][\\(\\[].*?[\\)\\]]",returnBegin:!0,contains:[{className:"string",begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0,relevance:0},{className:"link",begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}],relevance:10},i={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},s={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};i.contains.push(s),s.contains.push(i);var c=[e,a];return i.contains=i.contains.concat(c),s.contains=s.contains.concat(c),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:c=c.concat(i,s)},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:c}]}]},e,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:c,end:"$"},{className:"code",variants:[{begin:"(`{3,})(.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})(.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$"},a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}}());hljs.registerLanguage("javascript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);function s(e){return r("(?=",e,")")}function r(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(t){var i="[A-Za-z$_][0-9A-Za-z$_]*",c={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/},o={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.join(" "),literal:n.join(" "),built_in:a.join(" ")},l={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:t.C_NUMBER_RE+"n?"}],relevance:0},E={className:"subst",begin:"\\$\\{",end:"\\}",keywords:o,contains:[]},d={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"xml"}},g={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"css"}},u={className:"string",begin:"`",end:"`",contains:[t.BACKSLASH_ESCAPE,E]};E.contains=[t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,l,t.REGEXP_MODE];var b=E.contains.concat([{begin:/\(/,end:/\)/,contains:["self"].concat(E.contains,[t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE])},t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE]),_={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:b};return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:o,contains:[t.SHEBANG({binary:"node",relevance:5}),{className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,t.C_LINE_COMMENT_MODE,t.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type",begin:"\\{",end:"\\}",relevance:0},{className:"variable",begin:i+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),t.C_BLOCK_COMMENT_MODE,l,{begin:r(/[{,\n]\s*/,s(r(/(((\/\/.*)|(\/\*(.|\n)*\*\/))\s*)*/,i+"\\s*:"))),relevance:0,contains:[{className:"attr",begin:i+s("\\s*:"),relevance:0}]},{begin:"("+t.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE,t.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+t.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:t.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:o,contains:b}]}]},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{begin:"<>",end:"</>"},{begin:c.begin,end:c.end}],subLanguage:"xml",contains:[{begin:c.begin,end:c.end,skip:!0,contains:["self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/\{/,excludeEnd:!0,contains:[t.inherit(t.TITLE_MODE,{begin:i}),_],illegal:/\[|%/},{begin:/\$[(.]/},t.METHOD_GUARD,{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends"},t.UNDERSCORE_TITLE_MODE]},{beginKeywords:"constructor",end:/\{/,excludeEnd:!0},{begin:"(get|set)\\s+(?="+i+"\\()",end:/{/,keywords:"get set",contains:[t.inherit(t.TITLE_MODE,{begin:i}),{begin:/\(\)/},_]}],illegal:/#(?!!)/}}}());hljs.registerLanguage("typescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.concat(["type","namespace","typedef","interface","public","private","protected","implements","declare","abstract","readonly"]).join(" "),literal:n.join(" "),built_in:a.concat(["any","void","number","boolean","string","object","never","enum"]).join(" ")},s={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},i={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:r.C_NUMBER_RE+"n?"}],relevance:0},o={className:"subst",begin:"\\$\\{",end:"\\}",keywords:t,contains:[]},c={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"xml"}},l={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"css"}},E={className:"string",begin:"`",end:"`",contains:[r.BACKSLASH_ESCAPE,o]};o.contains=[r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,i,r.REGEXP_MODE];var d={begin:"\\(",end:/\)/,keywords:t,contains:["self",r.QUOTE_STRING_MODE,r.APOS_STRING_MODE,r.NUMBER_MODE]},u={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,s,d]};return{name:"TypeScript",aliases:["ts"],keywords:t,contains:[r.SHEBANG(),{className:"meta",begin:/^\s*['"]use strict['"]/},r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,i,{begin:"("+r.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,r.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+r.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:r.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:d.contains}]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/[\{;]/,excludeEnd:!0,keywords:t,contains:["self",r.inherit(r.TITLE_MODE,{begin:"[A-Za-z$_][0-9A-Za-z$_]*"}),u],illegal:/%/,relevance:0},{beginKeywords:"constructor",end:/[\{;]/,excludeEnd:!0,contains:["self",u]},{begin:/module\./,keywords:{built_in:"module"},relevance:0},{beginKeywords:"module",end:/\{/,excludeEnd:!0},{beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:"interface extends"},{begin:/\$[(.]/},{begin:"\\."+r.IDENT_RE,relevance:0},s,d]}}}());hljs.registerLanguage("plaintext",function(){"use strict";return function(t){return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}}());hljs.registerLanguage("less",function(){"use strict";return function(e){var n="([\\w-]+|@{[\\w-]+})",a=[],s=[],t=function(e){return{className:"string",begin:"~?"+e+".*?"+e}},r=function(e,n,a){return{className:e,begin:n,relevance:a}},i={begin:"\\(",end:"\\)",contains:s,relevance:0};s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,t("'"),t('"'),e.CSS_NUMBER_MODE,{begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",excludeEnd:!0}},r("number","#[0-9A-Fa-f]+\\b"),i,r("variable","@@?[\\w-]+",10),r("variable","@{[\\w-]+}"),r("built_in","~?`[^`]*?`"),{className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0},{className:"meta",begin:"!important"});var c=s.concat({begin:"{",end:"}",contains:a}),l={beginKeywords:"when",endsWithParent:!0,contains:[{beginKeywords:"and not"}].concat(s)},o={begin:n+"\\s*:",returnBegin:!0,end:"[;}]",relevance:0,contains:[{className:"attribute",begin:n,end:":",excludeEnd:!0,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}]},g={className:"keyword",begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{end:"[;{}]",returnEnd:!0,contains:s,relevance:0}},d={className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:c}},b={variants:[{begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:n,end:"{"}],returnBegin:!0,returnEnd:!0,illegal:"[<='$\"]",relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,l,r("keyword","all\\b"),r("variable","@{[\\w-]+}"),r("selector-tag",n+"%?",0),r("selector-id","#"+n),r("selector-class","\\."+n,0),r("selector-tag","&",0),{className:"selector-attr",begin:"\\[",end:"\\]"},{className:"selector-pseudo",begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"\\(",end:"\\)",contains:c},{begin:"!important"}]};return a.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,d,o,b),{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:a}}}());hljs.registerLanguage("lua",function(){"use strict";return function(e){var t={begin:"\\[=*\\[",end:"\\]=*\\]",contains:["self"]},a=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[","\\]=*\\]",{contains:[t],relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE,literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"},contains:a.concat([{className:"function",beginKeywords:"function",end:"\\)",contains:[e.inherit(e.TITLE_MODE,{begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",begin:"\\(",endsWithParent:!0,contains:a}].concat(a)},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",begin:"\\[=*\\[",end:"\\]=*\\]",contains:[t],relevance:5}])}}}());
book/theme/index.hbs+51−87
@@ -1,11 +1,11 @@
1<!DOCTYPE HTML>
1<!DOCTYPE HTML>
2−<html lang="{{ language }}" class="{{ default_theme }}" dir="{{ text_direction }}">
2+<html lang="{{ language }}" class="sidebar-visible no-js {{ default_theme }}">
3 <head>
3 <head>
4 <!-- Book generated using mdBook -->
4 <!-- Book generated using mdBook -->
5 <meta charset="UTF-8">
5 <meta charset="UTF-8">
6 <title>{{ title }}</title>
6 <title>{{ title }}</title>
7 {{#if is_print }}
7 {{#if is_print }}
8− <meta name="robots" content="noindex">
8+ <meta name="robots" content="noindex" />
9 {{/if}}
9 {{/if}}
10 {{#if base_url}}
10 {{#if base_url}}
11 <base href="{{ base_url }}">
11 <base href="{{ base_url }}">
@@ -15,9 +15,10 @@
15 <!-- Custom HTML head -->
15 <!-- Custom HTML head -->
16 {{> head}}
16 {{> head}}
17
17
18+ <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
18 <meta name="description" content="{{ description }}">
19 <meta name="description" content="{{ description }}">
19 <meta name="viewport" content="width=device-width, initial-scale=1">
20 <meta name="viewport" content="width=device-width, initial-scale=1">
20− <meta name="theme-color" content="#ffffff">
21+ <meta name="theme-color" content="#ffffff" />
21
22
22 {{#if favicon_svg}}
23 {{#if favicon_svg}}
23 <link rel="icon" href="{{ path_to_root }}favicon.svg">
24 <link rel="icon" href="{{ path_to_root }}favicon.svg">
@@ -34,6 +35,8 @@
34
35
35 <!-- Fonts -->
36 <!-- Fonts -->
36 <link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">
37 <link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">
38+ <link rel="preconnect" href="https://fonts.gstatic.com">
39+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@200;400;500;700&display=swap" rel="stylesheet">
37 {{#if copy_fonts}}
40 {{#if copy_fonts}}
38 <link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css">
41 <link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css">
39 {{/if}}
42 {{/if}}
@@ -50,19 +53,18 @@
50
53
51 {{#if mathjax_support}}
54 {{#if mathjax_support}}
52 <!-- MathJax -->
55 <!-- MathJax -->
53− <script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
56+ <script async type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
54 {{/if}}
57 {{/if}}
55 </head>
58 </head>
56− <body class="sidebar-visible no-js">
59+ <body>
57− <div id="body-container">
58 <!-- Provide site root to javascript -->
60 <!-- Provide site root to javascript -->
59− <script>
61+ <script type="text/javascript">
60 var path_to_root = "{{ path_to_root }}";
62 var path_to_root = "{{ path_to_root }}";
61 var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "{{ preferred_dark_theme }}" : "{{ default_theme }}";
63 var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "{{ preferred_dark_theme }}" : "{{ default_theme }}";
62 </script>
64 </script>
63
65
64 <!-- Work around some values being stored in localStorage wrapped in quotes -->
66 <!-- Work around some values being stored in localStorage wrapped in quotes -->
65− <script>
67+ <script type="text/javascript">
66 try {
68 try {
67 var theme = localStorage.getItem('mdbook-theme');
69 var theme = localStorage.getItem('mdbook-theme');
68 var sidebar = localStorage.getItem('mdbook-sidebar');
70 var sidebar = localStorage.getItem('mdbook-sidebar');
@@ -78,34 +80,27 @@
78 </script>
80 </script>
79
81
80 <!-- Set the theme before any content is loaded, prevents flash -->
82 <!-- Set the theme before any content is loaded, prevents flash -->
81− <script>
83+ <script type="text/javascript">
82 var theme;
84 var theme;
83 try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
85 try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
84 if (theme === null || theme === undefined) { theme = default_theme; }
86 if (theme === null || theme === undefined) { theme = default_theme; }
85 var html = document.querySelector('html');
87 var html = document.querySelector('html');
88+ html.classList.remove('no-js')
86 html.classList.remove('{{ default_theme }}')
89 html.classList.remove('{{ default_theme }}')
87 html.classList.add(theme);
90 html.classList.add(theme);
88− var body = document.querySelector('body');
89− body.classList.remove('no-js')
90− body.classList.add('js');
91+ html.classList.add('js');
91 </script>
92 </script>
92
93
93− <input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
94−
95 <!-- Hide / unhide sidebar before it is displayed -->
94 <!-- Hide / unhide sidebar before it is displayed -->
96− <script>
95+ <script type="text/javascript">
97− var body = document.querySelector('body');
96+ var html = document.querySelector('html');
98− var sidebar = null;
97+ var sidebar = 'hidden';
99− var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
100 if (document.body.clientWidth >= 1080) {
98 if (document.body.clientWidth >= 1080) {
101 try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
99 try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
102 sidebar = sidebar || 'visible';
100 sidebar = sidebar || 'visible';
103− } else {
104− sidebar = 'hidden';
105 }
101 }
106− sidebar_toggle.checked = sidebar === 'visible';
107− body.classList.remove('sidebar-visible');
102+ html.classList.remove('sidebar-visible');
108− body.classList.add("sidebar-" + sidebar);
103+ html.classList.add("sidebar-" + sidebar);
109 </script>
104 </script>
110
105
111 <nav id="sidebar" class="sidebar" aria-label="Table of contents">
106 <nav id="sidebar" class="sidebar" aria-label="Table of contents">
@@ -115,48 +110,26 @@
115 <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
110 <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
116 </nav>
111 </nav>
117
112
118− <!-- Track and set sidebar scroll position -->
119− <script>
120− var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
121− sidebarScrollbox.addEventListener('click', function(e) {
122− if (e.target.tagName === 'A') {
123− sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
124− }
125− }, { passive: true });
126− var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
127− sessionStorage.removeItem('sidebar-scroll');
128− if (sidebarScrollTop) {
129− // preserve sidebar scroll position when navigating via links within sidebar
130− sidebarScrollbox.scrollTop = sidebarScrollTop;
131− } else {
132− // scroll sidebar to current active section when navigating via "next/previous chapter" buttons
133− var activeSection = document.querySelector('#sidebar .active');
134− if (activeSection) {
135− activeSection.scrollIntoView({ block: 'center' });
136− }
137− }
138− </script>
139−
140 <div id="page-wrapper" class="page-wrapper">
113 <div id="page-wrapper" class="page-wrapper">
141
114
142 <div class="page">
115 <div class="page">
143 {{> header}}
116 {{> header}}
144 <div id="menu-bar-hover-placeholder"></div>
117 <div id="menu-bar-hover-placeholder"></div>
145− <div id="menu-bar" class="menu-bar sticky">
118+ <div id="menu-bar" class="menu-bar sticky bordered">
146 <div class="left-buttons">
119 <div class="left-buttons">
147− <label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
120+ <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
148 <i class="fa fa-bars"></i>
121 <i class="fa fa-bars"></i>
149− </label>
122+ </button>
150 <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
123 <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
151 <i class="fa fa-paint-brush"></i>
124 <i class="fa fa-paint-brush"></i>
152 </button>
125 </button>
153 <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
126 <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
154− <li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
127+ <li role="none"><button role="menuitem" class="theme" id="light">{{ theme_option "Light" }}</button></li>
155− <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
128+ <li role="none"><button role="menuitem" class="theme" id="rust">{{ theme_option "Rust" }}</button></li>
156− <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
129+ <li role="none"><button role="menuitem" class="theme" id="coal">{{ theme_option "Coal" }}</button></li>
157− <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
130+ <li role="none"><button role="menuitem" class="theme" id="navy">{{ theme_option "Navy" }}</button></li>
158− <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
131+ <li role="none"><button role="menuitem" class="theme" id="ayu">{{ theme_option "Ayu" }}</button></li>
159− <li role="none"><button role="menuitem" class="theme" id="colibri">Colibri</button></li>
132+ <li role="none"><button role="menuitem" class="theme" id="colibri">{{ theme_option "Colibri" }}</button></li>
160 </ul>
133 </ul>
161 {{#if search_enabled}}
134 {{#if search_enabled}}
162 <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
135 <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
@@ -178,19 +151,13 @@
178 <i id="git-repository-button" class="fa {{git_repository_icon}}"></i>
151 <i id="git-repository-button" class="fa {{git_repository_icon}}"></i>
179 </a>
152 </a>
180 {{/if}}
153 {{/if}}
181− {{#if git_repository_edit_url}}
182− <a href="{{git_repository_edit_url}}" title="Suggest an edit" aria-label="Suggest an edit">
183− <i id="git-edit-button" class="fa fa-edit"></i>
184− </a>
185− {{/if}}
186−
187 </div>
154 </div>
188 </div>
155 </div>
189
156
190 {{#if search_enabled}}
157 {{#if search_enabled}}
191 <div id="search-wrapper" class="hidden">
158 <div id="search-wrapper" class="hidden">
192 <form id="searchbar-outer" class="searchbar-outer">
159 <form id="searchbar-outer" class="searchbar-outer">
193− <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
160+ <input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
194 </form>
161 </form>
195 <div id="searchresults-outer" class="searchresults-outer hidden">
162 <div id="searchresults-outer" class="searchresults-outer hidden">
196 <div id="searchresults-header" class="searchresults-header"></div>
163 <div id="searchresults-header" class="searchresults-header"></div>
@@ -201,7 +168,7 @@
201 {{/if}}
168 {{/if}}
202
169
203 <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
170 <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
204− <script>
171+ <script type="text/javascript">
205 document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
172 document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
206 document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
173 document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
207 Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
174 Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
@@ -223,7 +190,7 @@
223 {{/previous}}
190 {{/previous}}
224
191
225 {{#next}}
192 {{#next}}
226− <a rel="next prefetch" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
193+ <a rel="next" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
227 <i class="fa fa-angle-right"></i>
194 <i class="fa fa-angle-right"></i>
228 </a>
195 </a>
229 {{/next}}
196 {{/next}}
@@ -241,7 +208,7 @@
241 {{/previous}}
208 {{/previous}}
242
209
243 {{#next}}
210 {{#next}}
244− <a rel="next prefetch" href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
211+ <a rel="next" href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
245 <i class="fa fa-angle-right"></i>
212 <i class="fa fa-angle-right"></i>
246 </a>
213 </a>
247 {{/next}}
214 {{/next}}
@@ -249,12 +216,10 @@
249
216
250 </div>
217 </div>
251
218
252− {{#if live_reload_endpoint}}
219+ {{#if livereload}}
253 <!-- Livereload script (if served using the cli tool) -->
220 <!-- Livereload script (if served using the cli tool) -->
254− <script>
221+ <script type="text/javascript">
255− const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
256− const wsAddress = wsProtocol + "//" + location.host + "/" + "{{{live_reload_endpoint}}}";
257− const socket = new WebSocket(wsAddress);
222+ var socket = new WebSocket("{{{livereload}}}");
258 socket.onmessage = function (event) {
223 socket.onmessage = function (event) {
259 if (event.data === "reload") {
224 if (event.data === "reload") {
260 socket.close();
225 socket.close();
@@ -270,7 +235,7 @@
270
235
271 {{#if google_analytics}}
236 {{#if google_analytics}}
272 <!-- Google Analytics Tag -->
237 <!-- Google Analytics Tag -->
273− <script>
238+ <script type="text/javascript">
274 var localAddrs = ["localhost", "127.0.0.1", ""];
239 var localAddrs = ["localhost", "127.0.0.1", ""];
275
240
276 // make sure we don't activate google analytics if the developer is
241 // make sure we don't activate google analytics if the developer is
@@ -288,43 +253,43 @@
288 {{/if}}
253 {{/if}}
289
254
290 {{#if playground_line_numbers}}
255 {{#if playground_line_numbers}}
291− <script>
256+ <script type="text/javascript">
292 window.playground_line_numbers = true;
257 window.playground_line_numbers = true;
293 </script>
258 </script>
294 {{/if}}
259 {{/if}}
295
260
296 {{#if playground_copyable}}
261 {{#if playground_copyable}}
297− <script>
262+ <script type="text/javascript">
298 window.playground_copyable = true;
263 window.playground_copyable = true;
299 </script>
264 </script>
300 {{/if}}
265 {{/if}}
301
266
302 {{#if playground_js}}
267 {{#if playground_js}}
303− <script src="{{ path_to_root }}ace.js"></script>
268+ <script src="{{ path_to_root }}ace.js" type="text/javascript" charset="utf-8"></script>
304− <script src="{{ path_to_root }}editor.js"></script>
269+ <script src="{{ path_to_root }}editor.js" type="text/javascript" charset="utf-8"></script>
305− <script src="{{ path_to_root }}mode-rust.js"></script>
270+ <script src="{{ path_to_root }}mode-rust.js" type="text/javascript" charset="utf-8"></script>
306− <script src="{{ path_to_root }}theme-dawn.js"></script>
271+ <script src="{{ path_to_root }}theme-dawn.js" type="text/javascript" charset="utf-8"></script>
307− <script src="{{ path_to_root }}theme-tomorrow_night.js"></script>
272+ <script src="{{ path_to_root }}theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
308 {{/if}}
273 {{/if}}
309
274
310 {{#if search_js}}
275 {{#if search_js}}
311− <script src="{{ path_to_root }}elasticlunr.min.js"></script>
276+ <script src="{{ path_to_root }}elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
312− <script src="{{ path_to_root }}mark.min.js"></script>
277+ <script src="{{ path_to_root }}mark.min.js" type="text/javascript" charset="utf-8"></script>
313− <script src="{{ path_to_root }}searcher.js"></script>
278+ <script src="{{ path_to_root }}searcher.js" type="text/javascript" charset="utf-8"></script>
314 {{/if}}
279 {{/if}}
315
280
316− <script src="{{ path_to_root }}clipboard.min.js"></script>
281+ <script src="{{ path_to_root }}clipboard.min.js" type="text/javascript" charset="utf-8"></script>
317− <script src="{{ path_to_root }}highlight.js"></script>
282+ <script src="{{ path_to_root }}highlight.js" type="text/javascript" charset="utf-8"></script>
318− <script src="{{ path_to_root }}book.js"></script>
283+ <script src="{{ path_to_root }}book.js" type="text/javascript" charset="utf-8"></script>
319
284
320 <!-- Custom JS scripts -->
285 <!-- Custom JS scripts -->
321 {{#each additional_js}}
286 {{#each additional_js}}
322− <script src="{{ ../path_to_root }}{{this}}"></script>
287+ <script type="text/javascript" src="{{ ../path_to_root }}{{this}}"></script>
323 {{/each}}
288 {{/each}}
324
289
325 {{#if is_print}}
290 {{#if is_print}}
326 {{#if mathjax_support}}
291 {{#if mathjax_support}}
327− <script>
292+ <script type="text/javascript">
328 window.addEventListener('load', function() {
293 window.addEventListener('load', function() {
329 MathJax.Hub.Register.StartupHook('End', function() {
294 MathJax.Hub.Register.StartupHook('End', function() {
330 window.setTimeout(window.print, 100);
295 window.setTimeout(window.print, 100);
@@ -332,7 +297,7 @@
332 });
297 });
333 </script>
298 </script>
334 {{else}}
299 {{else}}
335− <script>
300+ <script type="text/javascript">
336 window.addEventListener('load', function() {
301 window.addEventListener('load', function() {
337 window.setTimeout(window.print, 100);
302 window.setTimeout(window.print, 100);
338 });
303 });
@@ -340,6 +305,5 @@
340 {{/if}}
305 {{/if}}
341 {{/if}}
306 {{/if}}
342
307
343− </div>
344 </body>
308 </body>
345</html>
309</html>
contrib/Helix.appdata.xmldeleted−108
@@ -1,108 +0,0 @@
1−<?xml version="1.0" encoding="UTF-8"?>
2−<component type="desktop-application">
3− <id>com.helix_editor.Helix</id>
4− <metadata_license>CC0-1.0</metadata_license>
5− <project_license>MPL-2.0</project_license>
6− <name>Helix</name>
7− <summary>A post-modern text editor</summary>
8− <summary xml:lang="ar">مُحَرِّرُ نُصُوصٍ سَابِقٌ لِعَهدِه</summary>
9−
10− <description>
11− <p>
12− Helix is a terminal-based text editor inspired by Kakoune / Neovim and written in Rust.
13− </p>
14− <ul>
15− <li>Vim-like modal editing</li>
16− <li>Multiple selections</li>
17− <li>Built-in language server support</li>
18− <li>Smart, incremental syntax highlighting and code editing via tree-sitter</li>
19− </ul>
20− </description>
21− <description xml:lang="ar">
22− <p>
23− مُحَرِّرُ نُصُوصٍ يَعمَلُ فِي الطَّرَفِيَّة، مُستَلهَمٌ مِن Kakoune وَ Neovim وَمَكتُوبٌ بِلُغَةِ رَست البَرمَجِيَّة.
24− </p>
25− <ul>
26− <li>تَحرِيرٌ وَضعِيٌّ شَبيهٌ بِـVim</li>
27− <li>تَحدِيدَاتٌ لِلنَّصِ مُتَعَدِّدَة</li>
28− <li>دَعْمٌ مُدمَجٌ لِخَوادِمِ اللُّغَات</li>
29− <li>تَحرِيرُ التَّعلِيمَاتِ البَّرمَجِيَّةِ مَعَ تَمييزٍ لِلتَّركِيبِ النَّحُويِّ بِواسِطَةِ tree-sitter</li>
30− </ul>
31− </description>
32−
33− <launchable type="desktop-id">Helix.desktop</launchable>
34−
35− <screenshots>
36− <screenshot type="default">
37− <caption>Helix with default theme</caption>
38− <image>https://github.com/helix-editor/helix/raw/d4565b4404cabc522bd60822abd374755581d751/screenshot.png</image>
39− </screenshot>
40− </screenshots>
41−
42− <url type="homepage">https://helix-editor.com/</url>
43− <url type="donation">https://opencollective.com/helix-editor</url>
44− <url type="help">https://docs.helix-editor.com/</url>
45− <url type="vcs-browser">https://github.com/helix-editor/helix</url>
46− <url type="bugtracker">https://github.com/helix-editor/helix/issues</url>
47−
48− <content_rating type="oars-1.1" />
49−
50− <releases>
51− <release version="23.10" date="2023-10-24">
52− <url>https://helix-editor.com/news/release-23-10-highlights/</url>
53− </release>
54− <release version="23.05" date="2023-05-18">
55− <url>https://github.com/helix-editor/helix/releases/tag/23.05</url>
56− </release>
57− <release version="23.03" date="2023-03-31">
58− <url>https://helix-editor.com/news/release-23-03-highlights/</url>
59− </release>
60− <release version="22.12" date="2022-12-6">
61− <url>https://helix-editor.com/news/release-22-12-highlights/</url>
62− </release>
63− <release version="22.08" date="2022-8-31">
64− <url>https://helix-editor.com/news/release-22-08-highlights/</url>
65− </release>
66− <release version="22.05" date="2022-5-28">
67− <url>https://helix-editor.com/news/release-22-05-highlights/</url>
68− </release>
69− <release version="22.03" date="2022-3-28">
70− <url>https://helix-editor.com/news/release-22-03-highlights/</url>
71− </release>
72− </releases>
73−
74− <requires>
75− <control>keyboard</control>
76− </requires>
77−
78− <categories>
79− <category>Utility</category>
80− <category>TextEditor</category>
81− </categories>
82−
83− <keywords>
84− <keyword>text</keyword>
85− <keyword>editor</keyword>
86− <keyword>development</keyword>
87− <keyword>programming</keyword>
88− </keywords>
89−
90− <provides>
91− <binary>hx</binary>
92− <mediatype>text/english</mediatype>
93− <mediatype>text/plain</mediatype>
94− <mediatype>text/x-makefile</mediatype>
95− <mediatype>text/x-c++hdr</mediatype>
96− <mediatype>text/x-c++src</mediatype>
97− <mediatype>text/x-chdr</mediatype>
98− <mediatype>text/x-csrc</mediatype>
99− <mediatype>text/x-java</mediatype>
100− <mediatype>text/x-moc</mediatype>
101− <mediatype>text/x-pascal</mediatype>
102− <mediatype>text/x-tcl</mediatype>
103− <mediatype>text/x-tex</mediatype>
104− <mediatype>application/x-shellscript</mediatype>
105− <mediatype>text/x-c</mediatype>
106− <mediatype>text/x-c++</mediatype>
107− </provides>
108−</component>
contrib/Helix.desktopdeleted−91
@@ -1,91 +0,0 @@
1−[Desktop Entry]
2−Name=Helix
3−GenericName=Text Editor
4−GenericName[ar]=مُحَرِّرُ نُصُوص
5−GenericName[de]=Texteditor
6−GenericName[fr]=Éditeur de texte
7−GenericName[ru]=Текстовый редактор
8−GenericName[sr]=Едитор текст
9−GenericName[tr]=Metin Düzenleyici
10−Comment=Edit text files
11−Comment[af]=Redigeer tekslêers
12−Comment[am]=የጽሑፍ ፋይሎች ያስተካክሉ
13−Comment[ar]=مُحَرِّرُ مِلَفَّاتٍ نَصِّيَّة
14−Comment[az]=Mətn fayllarını redaktə edin
15−Comment[be]=Рэдагаваньне тэкставых файлаў
16−Comment[bg]=Редактиране на текстови файлове
17−Comment[bn]=টেক্স্ট ফাইল এডিট করুন
18−Comment[bs]=Izmijeni tekstualne datoteke
19−Comment[ca]=Edita fitxers de text
20−Comment[cs]=Úprava textových souborů
21−Comment[cy]=Golygu ffeiliau testun
22−Comment[da]=Redigér tekstfiler
23−Comment[de]=Textdateien bearbeiten
24−Comment[el]=Επεξεργασία αρχείων κειμένου
25−Comment[en_CA]=Edit text files
26−Comment[en_GB]=Edit text files
27−Comment[es]=Edita archivos de texto
28−Comment[et]=Redigeeri tekstifaile
29−Comment[eu]=Editatu testu-fitxategiak
30−Comment[fa]=ویرایش پرونده‌های متنی
31−Comment[fi]=Muokkaa tekstitiedostoja
32−Comment[fr]=Éditer des fichiers texte
33−Comment[ga]=Eagar comhad Téacs
34−Comment[gu]=લખાણ ફાઇલોમાં ફેરફાર કરો
35−Comment[he]=ערוך קבצי טקסט
36−Comment[hi]=पाठ फ़ाइलें संपादित करें
37−Comment[hr]=Uređivanje tekstualne datoteke
38−Comment[hu]=Szövegfájlok szerkesztése
39−Comment[id]=Edit file teks
40−Comment[it]=Modifica file di testo
41−Comment[ja]=テキストファイルを編集します
42−Comment[kn]=ಪಠ್ಯ ಕಡತಗಳನ್ನು ಸಂಪಾದಿಸು
43−Comment[ko]=텍스트 파일을 편집합니다
44−Comment[lt]=Redaguoti tekstines bylas
45−Comment[lv]=Rediģēt teksta failus
46−Comment[mk]=Уреди текстуални фајлови
47−Comment[ml]=വാചക രചനകള് തിരുത്തുക
48−Comment[mn]=Текст файл боловсруулах
49−Comment[mr]=गद्य फाइल संपादित करा
50−Comment[ms]=Edit fail teks
51−Comment[nb]=Rediger tekstfiler
52−Comment[ne]=पाठ फाइललाई संशोधन गर्नुहोस्
53−Comment[nl]=Tekstbestanden bewerken
54−Comment[nn]=Rediger tekstfiler
55−Comment[no]=Rediger tekstfiler
56−Comment[or]=ପାଠ୍ଯ ଫାଇଲଗୁଡ଼ିକୁ ସମ୍ପାଦନ କରନ୍ତୁ
57−Comment[pa]=ਪਾਠ ਫਾਇਲਾਂ ਸੰਪਾਦਨ
58−Comment[pl]=Edytor plików tekstowych
59−Comment[pt]=Editar ficheiros de texto
60−Comment[pt_BR]=Edite arquivos de texto
61−Comment[ro]=Editare fişiere text
62−Comment[ru]=Редактирование текстовых файлов
63−Comment[sk]=Úprava textových súborov
64−Comment[sl]=Urejanje datotek z besedili
65−Comment[sq]=Përpuno files teksti
66−Comment[sr]=Уређујте текст фајлове
67−Comment[sr@Latn]=Izmeni tekstualne datoteke
68−Comment[sv]=Redigera textfiler
69−Comment[ta]=உரை கோப்புகளை தொகுக்கவும்
70−Comment[th]=แก้ไขแฟ้มข้อความ
71−Comment[tk]=Metin faýllary editle
72−Comment[tr]=Metin dosyaları düzenleyin
73−Comment[uk]=Редактор текстових файлів
74−Comment[vi]=Soạn thảo tập tin văn bản
75−Comment[wa]=Asspougnî des fitchîs tecses
76−Comment[zh_CN]=编辑文本文件
77−Comment[zh_TW]=編輯文字檔
78−TryExec=hx
79−Exec=hx %F
80−Terminal=true
81−Type=Application
82−Keywords=Text;editor;
83−Keywords[ar]=نص;نصوص;محرر;
84−Keywords[fr]=Texte;éditeur;
85−Keywords[ru]=текст;текстовый редактор;
86−Keywords[sr]=Текст;едитор;
87−Keywords[tr]=Metin;düzenleyici;
88−Icon=helix
89−Categories=Utility;TextEditor;
90−StartupNotify=false
91−MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
contrib/completion/hx.bashdeleted−23
@@ -1,23 +0,0 @@
1−#!/usr/bin/env bash
2−# Bash completion script for Helix editor
3−
4−_hx() {
5− # $1 command name
6− # $2 word being completed
7− # $3 word preceding
8− COMPREPLY=()
9−
10− case "$3" in
11− -g | --grammar)
12− COMPREPLY=($(compgen -W "fetch build" -- $2))
13− ;;
14− --health)
15− local languages=$(hx --health |tail -n '+7' |awk '{print $1}' |sed 's/\x1b\[[0-9;]*m//g')
16− COMPREPLY=($(compgen -W "$languages" -- $2))
17− ;;
18− *)
19− COMPREPLY=($(compgen -fd -W "-h --help --tutor -V --version -v -vv -vvv --health -g --grammar --vsplit --hsplit -c --config --log" -- $2))
20− ;;
21− esac
22−} && complete -o filenames -F _hx hx
23−
contrib/completion/hx.elvdeleted−55
@@ -1,55 +0,0 @@
1−# You can move it here ~/.config/elvish/lib/hx.elv
2−# Or add `eval (slurp < ~/$REPOS/helix/contrib/completion/hx.elv)`
3−# Be sure to replace `$REPOS` with something that makes sense for you!
4−
5−### Renders a pretty completion candidate
6−var candidate = { | _stem _desc |
7− edit:complex-candidate $_stem &display=(styled $_stem bold)(styled " "$_desc dim)
8−}
9−
10−### These commands will invalidate further input (i.e. not react to them)
11−var skips = [ "--tutor" "--help" "--version" "-V" "--health" ]
12−
13−### Grammar commands
14−var grammar = [ "--grammar" "-g" ]
15−
16−### Config commands
17−var config = [ "--config" "-c" ]
18−
19−### Set an arg-completer for the `hx` binary
20−set edit:completion:arg-completer[hx] = {|@args|
21− var n = (count $args)
22− if (>= $n 3) {
23− # Stop completions if passed arg will take presedence
24− # and invalidate further input
25− if (has-value $skips $args[-2]) {
26− return
27− }
28− # If the previous arg == --grammar, then only suggest:
29− if (has-value $grammar $args[-2]) {
30− $candidate "fetch" "Fetch the tree-sitter grammars"
31− $candidate "build" "Build the tree-sitter grammars"
32− return
33− }
34− # When we have --config, we need a file
35− if (has-values $config $args[-2]) {
36− edit:complete-filename $args[-1] | each { |v| put $v[stem] }
37− return
38− }
39− # When we have --log, we need a file
40− if (has-values "log" $args[-2]) {
41− edit:complete-filename $args[-1] | each { |v| put $v[stem] }
42− return
43− }
44− }
45− edit:complete-filename $args[-1] | each { |v| put $v[stem]}
46− $candidate "--help" "(Prints help information)"
47− $candidate "--version" "(Prints version information)"
48− $candidate "--tutor" "(Loads the tutorial)"
49− $candidate "--health" "(Checks for errors in editor setup)"
50− $candidate "--grammar" "(Fetch or build the tree-sitter grammars)"
51− $candidate "--vsplit" "(Splits all given files vertically)"
52− $candidate "--hsplit" "(Splits all given files horizontally)"
53− $candidate "--config" "(Specifies a file to use for configuration)"
54− $candidate "--log" "(Specifies a file to write log data into)"
55−}
contrib/completion/hx.fishdeleted−15
@@ -1,15 +0,0 @@
1−#!/usr/bin/env fish
2−# Fish completion script for Helix editor
3−
4−set -l langs (hx --health |tail -n '+7' |awk '{print $1}' |sed 's/\x1b\[[0-9;]*m//g')
5−
6−complete -c hx -s h -l help -d "Prints help information"
7−complete -c hx -l tutor -d "Loads the tutorial"
8−complete -c hx -l health -x -a "$langs" -d "Checks for errors in editor setup"
9−complete -c hx -s g -l grammar -x -a "fetch build" -d "Fetches or builds tree-sitter grammars"
10−complete -c hx -s v -o vv -o vvv -d "Increases logging verbosity"
11−complete -c hx -s V -l version -d "Prints version information"
12−complete -c hx -l vsplit -d "Splits all given files vertically into different windows"
13−complete -c hx -l hsplit -d "Splits all given files horizontally into different windows"
14−complete -c hx -s c -l config -r -d "Specifies a file to use for completion"
15−complete -c hx -l log -r -d "Specifies a file to write log data into"
contrib/completion/hx.zshdeleted−34
@@ -1,34 +0,0 @@
1−#compdef _hx hx
2−# Zsh completion script for Helix editor
3−
4−_hx() {
5− _arguments -C \
6− "-h[Prints help information]" \
7− "--help[Prints help information]" \
8− "-v[Increase logging verbosity]" \
9− "-vv[Increase logging verbosity]" \
10− "-vvv[Increase logging verbosity]" \
11− "-V[Prints version information]" \
12− "--version[Prints version information]" \
13− "--tutor[Loads the tutorial]" \
14− "--health[Checks for errors in editor setup]:language:->health" \
15− "-g[Fetches or builds tree-sitter grammars]:action:->grammar" \
16− "--grammar[Fetches or builds tree-sitter grammars]:action:->grammar" \
17− "--vsplit[Splits all given files vertically into different windows]" \
18− "--hsplit[Splits all given files horizontally into different windows]" \
19− "-c[Specifies a file to use for configuration]" \
20− "--config[Specifies a file to use for configuration]" \
21− "--log[Specifies a file to write log data into]" \
22− "*:file:_files"
23−
24− case "$state" in
25− health)
26− local languages=($(hx --health |tail -n '+7' |awk '{print $1}' |sed 's/\x1b\[[0-9;]*m//g'))
27− _values 'language' $languages
28− ;;
29− grammar)
30− _values 'action' fetch build
31− ;;
32− esac
33−}
34−
contrib/helix.pngdeleted

Binary file not shown.

default.nixdeleted−8
@@ -1,8 +0,0 @@
1−# Flake's default package for non-flake-enabled nix instances
2−let
3− compat = builtins.fetchTarball {
4− url = "https://github.com/edolstra/flake-compat/archive/b4a34015c698c7793d592d66adbab377907a2be8.tar.gz";
5− sha256 = "sha256:1qc703yg0babixi6wshn5wm2kgl5y1drcswgszh4xxzbrwkk9sv7";
6− };
7−in
8− (import compat {src = ./.;}).defaultNix.default
docs/CONTRIBUTING.md+4−35
@@ -8,10 +8,7 @@ Some suggestions to get started:
8- Help with packaging on various distributions needed!
8- Help with packaging on various distributions needed!
9- To use print debugging to the [Helix log file][log-file], you must:
9- To use print debugging to the [Helix log file][log-file], you must:
10 * Print using `log::info!`, `warn!`, or `error!`. (`log::info!("helix!")`)
10 * Print using `log::info!`, `warn!`, or `error!`. (`log::info!("helix!")`)
11− * Pass the appropriate verbosity level option for the desired log level. (`hx -v <file>` for info, more `v`s for higher verbosity)
11+ * Pass the appropriate verbosity level option for the desired log level. (`hx -v <file>` for info, more `v`s for higher severity inclusive)
12− * Want to display the logs in a separate file instead of using the `:log-open` command in your compiled Helix editor? Start your debug version with `cargo run -- --log foo.log` and in a new terminal use `tail -f foo.log`
13−- Instead of running a release version of Helix, while developing you may want to run in debug mode with `cargo run` which is way faster to compile
14−- Looking for even faster compile times? Give a try to [mold](https://github.com/rui314/mold)
15- If your preferred language is missing, integrating a tree-sitter grammar for
12- If your preferred language is missing, integrating a tree-sitter grammar for
16 it and defining syntax highlight queries for it is straight forward and
13 it and defining syntax highlight queries for it is straight forward and
17 doesn't require much knowledge of the internals.
14 doesn't require much knowledge of the internals.
@@ -29,40 +26,12 @@ files, run
29cargo xtask docgen
26cargo xtask docgen
30```
27```
31
28
32−inside the project. We use [xtask][xtask] as an ad-hoc task runner.
29+inside the project. We use [xtask][xtask] as an ad-hoc task runner and
30+thus do not require any dependencies other than `cargo` (You don't have
31+to `cargo install` anything either).
33
32
34−To preview the book itself, install [mdbook][mdbook]. Then, run
35−
36−```shell
37−mdbook serve book
38−```
39−
40−and visit [http://localhost:3000](http://localhost:3000).
41−
42−# Testing
43−
44−## Unit tests/Documentation tests
45−
46−Run `cargo test --workspace` to run unit tests and documentation tests in all packages.
47−
48−## Integration tests
49−
50−Integration tests for helix-term can be run with `cargo integration-test`. Code
51−contributors are strongly encouraged to write integration tests for their code.
52−Existing tests can be used as examples. Helpers can be found in
53−[helpers.rs][helpers.rs]. The log level can be set with the `HELIX_LOG_LEVEL`
54−environment variable, e.g. `HELIX_LOG_LEVEL=debug cargo integration-test`.
55−
56−## Minimum Stable Rust Version (MSRV) Policy
57−
58−Helix follows the MSRV of Firefox.
59−The current MSRV and future changes to the MSRV are listed in the [Firefox documentation].
60−
61−[Firefox documentation]: https://firefox-source-docs.mozilla.org/writing-rust-code/update-policy.html
62[good-first-issue]: https://github.com/helix-editor/helix/labels/E-easy
33[good-first-issue]: https://github.com/helix-editor/helix/labels/E-easy
63[log-file]: https://github.com/helix-editor/helix/wiki/FAQ#access-the-log-file
34[log-file]: https://github.com/helix-editor/helix/wiki/FAQ#access-the-log-file
64[architecture.md]: ./architecture.md
35[architecture.md]: ./architecture.md
65[docs]: https://docs.helix-editor.com/
36[docs]: https://docs.helix-editor.com/
66[xtask]: https://github.com/matklad/cargo-xtask
37[xtask]: https://github.com/matklad/cargo-xtask
67−[mdbook]: https://rust-lang.github.io/mdBook/guide/installation.html
68−[helpers.rs]: ../helix-term/tests/test/helpers.rs
docs/architecture.md+13−39
@@ -1,13 +1,12 @@
1
1
2−| Crate | Description |
2+| Crate | Description |
3−| ----------- | ----------- |
3+| ----------- | ----------- |
4−| helix-core | Core editing primitives, functional. |
4+| helix-core | Core editing primitives, functional. |
5+| helix-syntax | Tree-sitter grammars |
5−| helix-lsp | Language server client |
6+| helix-lsp | Language server client |
6−| helix-dap | Debug Adapter Protocol (DAP) client |
7−| helix-loader | Functions for building, fetching, and loading external resources |
8−| helix-view | UI abstractions for use in backends, imperative shell. |
7+| helix-view | UI abstractions for use in backends, imperative shell. |
9−| helix-term | Terminal UI |
8+| helix-term | Terminal UI |
10−| helix-tui | TUI primitives, forked from tui-rs, inspired by Cursive |
9+| helix-tui | TUI primitives, forked from tui-rs, inspired by Cursive |
11
10
12
11
13This document contains a high-level overview of Helix internals.
12This document contains a high-level overview of Helix internals.
@@ -32,7 +31,7 @@ represented by a `Selection`. Each `Range` in the selection consists of a moving
32a selection with a single range, with the head and the anchor in the same
31a selection with a single range, with the head and the anchor in the same
33position.
32position.
34
33
35−Ropes are modified by constructing an OT-like `Transaction`. It represents
34+Ropes are modified by constructing an OT-like `Transaction`. It's represents
36a single coherent change to the document and can be applied to the rope.
35a single coherent change to the document and can be applied to the rope.
37A transaction can be inverted to produce an undo. Selections and marks can be
36A transaction can be inverted to produce an undo. Selections and marks can be
38mapped over a transaction to translate to a position in the new text state after
37mapped over a transaction to translate to a position in the new text state after
@@ -42,7 +41,7 @@ applying the transaction.
42> interface used to generate text edits.
41> interface used to generate text edits.
43
42
44`Syntax` is the interface used to interact with tree-sitter ASTs for syntax
43`Syntax` is the interface used to interact with tree-sitter ASTs for syntax
45−highlighting and other features.
44+highling and other features.
46
45
47## View
46## View
48
47
@@ -55,40 +54,15 @@ A `Document` ties together the `Rope`, `Selection`(s), `Syntax`, document
55file.
54file.
56
55
57A `View` represents an open split in the UI. It holds the currently open
56A `View` represents an open split in the UI. It holds the currently open
58−document ID and other related state. Views encapsulate the gutter, status line,
57+document ID and other related state.
59−diagnostics, and the inner area where the code is displayed.
60
58
61> NOTE: Multiple views are able to display the same document, so the document
59> NOTE: Multiple views are able to display the same document, so the document
62> contains selections for each view. To retrieve, `document.selection()` takes
60> contains selections for each view. To retrieve, `document.selection()` takes
63> a `ViewId`.
61> a `ViewId`.
64
62
65−`Info` is the autoinfo box that shows hints when awaiting another key with bindings
66−like `g` and `m`. It is attached to the viewport as a whole.
67−
68−`Surface` is like a buffer to which widgets draw themselves to, and the
69−surface is then rendered on the screen on each cycle.
70−
71−`Rect`s are areas (simply an x and y coordinate with the origin at the
72−screen top left and then a height and width) which are part of a
73−`Surface`. They can be used to limit the area to which a `Component` can
74−render. For example if we wrap a `Markdown` component in a `Popup`
75−(think the documentation popup with space+k), Markdown's render method
76−will get a Rect that is the exact size of the popup.
77−
78−Widgets are called `Component`s internally, and you can see most of them
79−in `helix-term/src/ui`. Some components like `Popup` and `Overlay` can take
80−other components as children.
81−
82−`Layer`s are how multiple components are displayed, and is simply a
83−`Vec<Component>`. Layers are managed by the `Compositor`. On each top
84−level render call, the compositor renders each component in the order
85−they were pushed into the stack. This makes multiple components "layer"
86−on top of one another. Hence we get a file picker displayed over the
87−editor, etc.
88−
89The `Editor` holds the global state: all the open documents, a tree
63The `Editor` holds the global state: all the open documents, a tree
90−representation of all the view splits, the configuration, and a registry of
64+representation of all the view splits, and a registry of language servers. To
91−language servers. To open or close files, interact with the editor.
65+open or close files, interact with the editor.
92
66
93## LSP
67## LSP
94
68
docs/releases.mddeleted−67
@@ -1,67 +0,0 @@
1−## Checklist
2−
3−Helix releases are versioned in the Calendar Versioning scheme:
4−`YY.0M(.MICRO)`, for example, `22.05` for May of 2022, or in a patch release,
5−`22.05.1`. In these instructions we'll use `<tag>` as a placeholder for the tag
6−being published.
7−
8−* Merge the changelog PR
9−* Add new `<release>` entry in `contrib/Helix.appdata.xml` with release information according to the [AppStream spec](https://www.freedesktop.org/software/appstream/docs/sect-Metadata-Releases.html)
10−* Tag and push
11− * `git tag -s -m "<tag>" -a <tag> && git push`
12− * Make sure to switch to master and pull first
13−* Edit the `Cargo.toml` file and change the date in the `version` field to the next planned release
14− * Due to Cargo having a strict requirement on SemVer with 3 or more version
15− numbers, a `0` is required in the micro version; however, unless we are
16− publishing a patch release after a major release, the `.0` is dropped in
17− the user facing version.
18− * Releases are planned to happen every two months, so `22.05.0` would change to `22.07.0`
19− * If we are pushing a patch/bugfix release in the same month as the previous
20− release, bump the micro version, e.g. `22.07.0` to `22.07.1`
21−* Wait for the Release CI to finish
22− * It will automatically turn the git tag into a GitHub release when it uploads artifacts
23−* Edit the new release
24− * Use `<tag>` as the title
25− * Link to the changelog and release notes
26−* Merge the release notes PR
27−* Download the macos and linux binaries and update the `sha256`s in the [homebrew formula]
28− * Use `sha256sum` on the downloaded `.tar.xz` files to determine the hash
29−* Link to the release notes in this-week-in-rust
30− * [Example PR](https://github.com/rust-lang/this-week-in-rust/pull/3300)
31−* Post to reddit
32− * [Example post](https://www.reddit.com/r/rust/comments/uzp5ze/helix_editor_2205_released/)
33−
34−[homebrew formula]: https://github.com/Homebrew/homebrew-core/blob/master/Formula/helix.rb
35−
36−## Changelog Curation
37−
38−The changelog is currently created manually by reading through commits in the
39−log since the last release. GitHub's compare view is a nice way to approach
40−this. For example, when creating the 22.07 release notes, this compare link
41−may be used
42−
43−```
44−https://github.com/helix-editor/helix/compare/22.05...master
45−```
46−
47−Either side of the triple-dot may be replaced with an exact revision, so if
48−you wish to incrementally compile the changelog, you can tackle a weeks worth
49−or so, record the revision where you stopped, and use that as a starting point
50−next week:
51−
52−```
53−https://github.com/helix-editor/helix/compare/7706a4a0d8b67b943c31d0c5f7b00d357b5d838d...master
54−```
55−
56−A work-in-progress commit for a changelog might look like
57−[this example](https://github.com/helix-editor/helix/commit/831adfd4c709ca16b248799bfef19698d5175e55).
58−
59−Not every PR or commit needs a blurb in the changelog. Each release section
60−tends to have a blurb that links to a GitHub comparison between release
61−versions for convenience:
62−
63−> As usual, the following is a summary of each of the changes since the last
64−> release. For the full log, check out the git log.
65−
66−Typically, small changes like dependencies or documentation updates, refactors,
67−or meta changes like GitHub Actions work are left out.
docs/vision.md+1−1
@@ -20,5 +20,5 @@ Vision statements are all well and good, but are also vague and subjective. Her
20* **Built-in tools** for working with code bases efficiently. Most projects aren't a single file, and an editor should handle that as a first-class use case. In Helix's case, this means (among other things) a fuzzy-search file navigator and LSP support.
20* **Built-in tools** for working with code bases efficiently. Most projects aren't a single file, and an editor should handle that as a first-class use case. In Helix's case, this means (among other things) a fuzzy-search file navigator and LSP support.
21* **Edit anything** that comes up when coding, within reason. Whether it's a 200 MB XML file, a megabyte of minified javascript on a single line, or Japanese text encoded in ShiftJIS, you should be able to open it and edit it without problems. (Note: this doesn't mean handle every esoteric use case. Sometimes you do just need a specialized tool, and Helix isn't that.)
21* **Edit anything** that comes up when coding, within reason. Whether it's a 200 MB XML file, a megabyte of minified javascript on a single line, or Japanese text encoded in ShiftJIS, you should be able to open it and edit it without problems. (Note: this doesn't mean handle every esoteric use case. Sometimes you do just need a specialized tool, and Helix isn't that.)
22* **Configurable**, within reason. Although the defaults should be good, not everyone will agree on what "good" is. Within the bounds of Helix's core interaction models, it should be reasonably configurable so that it can be "good" for more people. This means, for example, custom key maps among other things.
22* **Configurable**, within reason. Although the defaults should be good, not everyone will agree on what "good" is. Within the bounds of Helix's core interaction models, it should be reasonably configurable so that it can be "good" for more people. This means, for example, custom key maps among other things.
23−* **Extensible**, within reason. Although we want Helix to be productive out-of-the-box, it's not practical or desirable to cram every useful feature and use case into the core editor. The basics should be built-in, but you should be able to extend it with additional functionality as needed.
23+* **Extensible**, within reason. Although we want Helix to be productive out-of-the-box, it's not practical or desirable to cram every useful feature and use case into the core editor. The basics should be built-in, but you should be able to extend it with additional functionality as needed. Right now we're thinking Wasm-based plugins.
24* **Clean code base.** Sometimes other factors (e.g. significant performance gains, important features, correctness, etc.) will trump strict readability, but we nevertheless want to keep the code base straightforward and easy to understand to the extent we can.
24* **Clean code base.** Sometimes other factors (e.g. significant performance gains, important features, correctness, etc.) will trump strict readability, but we nevertheless want to keep the code base straightforward and easy to understand to the extent we can.
flake.lock+60−48
@@ -1,35 +1,27 @@
1{
1{
2 "nodes": {
2 "nodes": {
3− "crane": {
3+ "devshell": {
4− "inputs": {
5− "nixpkgs": [
6− "nixpkgs"
7− ]
8− },
9 "locked": {
4 "locked": {
10− "lastModified": 1701025348,
5+ "lastModified": 1639692811,
11− "narHash": "sha256-42GHmYH+GF7VjwGSt+fVT1CQuNpGanJbNgVHTAZppUM=",
6+ "narHash": "sha256-wOOBH0fVsfNqw/5ZWRoKspyesoXBgiwEOUBH4c7JKEo=",
12− "owner": "ipetkov",
7+ "owner": "numtide",
13− "repo": "crane",
8+ "repo": "devshell",
14− "rev": "42afaeb1a0325194a7cdb526332d2cb92fddd07b",
9+ "rev": "d3a1f5bec3632b33346865b1c165bf2420bb2f52",
15 "type": "github"
10 "type": "github"
16 },
11 },
17 "original": {
12 "original": {
18− "owner": "ipetkov",
13+ "owner": "numtide",
19− "repo": "crane",
14+ "repo": "devshell",
20 "type": "github"
15 "type": "github"
21 }
16 }
22 },
17 },
23 "flake-utils": {
18 "flake-utils": {
24− "inputs": {
25− "systems": "systems"
26− },
27 "locked": {
19 "locked": {
28− "lastModified": 1694529238,
20+ "lastModified": 1637014545,
29− "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
21+ "narHash": "sha256-26IZAc5yzlD9FlDT54io1oqG/bBoyka+FJk5guaX4x4=",
30 "owner": "numtide",
22 "owner": "numtide",
31 "repo": "flake-utils",
23 "repo": "flake-utils",
32− "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
24+ "rev": "bba5dcc8e0b20ab664967ad83d24d64cb64ec4f4",
33 "type": "github"
25 "type": "github"
34 },
26 },
35 "original": {
27 "original": {
@@ -38,13 +30,37 @@
38 "type": "github"
30 "type": "github"
39 }
31 }
40 },
32 },
33+ "nixCargoIntegration": {
34+ "inputs": {
35+ "devshell": "devshell",
36+ "nixpkgs": [
37+ "nixpkgs"
38+ ],
39+ "rustOverlay": [
40+ "rust-overlay"
41+ ]
42+ },
43+ "locked": {
44+ "lastModified": 1639807801,
45+ "narHash": "sha256-y32tMq1LTRVbMW3QN5i98iOQjQt2QSsif3ayUkD1o3g=",
46+ "owner": "yusdacra",
47+ "repo": "nix-cargo-integration",
48+ "rev": "b5bbaa4f5239e6f0619846f9a5380f07baa853d3",
49+ "type": "github"
50+ },
51+ "original": {
52+ "owner": "yusdacra",
53+ "repo": "nix-cargo-integration",
54+ "type": "github"
55+ }
56+ },
41 "nixpkgs": {
57 "nixpkgs": {
42 "locked": {
58 "locked": {
43− "lastModified": 1700794826,
59+ "lastModified": 1639699734,
44− "narHash": "sha256-RyJTnTNKhO0yqRpDISk03I/4A67/dp96YRxc86YOPgU=",
60+ "narHash": "sha256-tlX6WebGmiHb2Hmniff+ltYp+7dRfdsBxw9YczLsP60=",
45 "owner": "nixos",
61 "owner": "nixos",
46 "repo": "nixpkgs",
62 "repo": "nixpkgs",
47− "rev": "5a09cb4b393d58f9ed0d9ca1555016a8543c2ac8",
63+ "rev": "03ec468b14067729a285c2c7cfa7b9434a04816c",
48 "type": "github"
64 "type": "github"
49 },
65 },
50 "original": {
66 "original": {
@@ -54,29 +70,40 @@
54 "type": "github"
70 "type": "github"
55 }
71 }
56 },
72 },
73+ "nixpkgs_2": {
74+ "locked": {
75+ "lastModified": 1637453606,
76+ "narHash": "sha256-Gy6cwUswft9xqsjWxFYEnx/63/qzaFUwatcbV5GF/GQ=",
77+ "owner": "NixOS",
78+ "repo": "nixpkgs",
79+ "rev": "8afc4e543663ca0a6a4f496262cd05233737e732",
80+ "type": "github"
81+ },
82+ "original": {
83+ "owner": "NixOS",
84+ "ref": "nixpkgs-unstable",
85+ "repo": "nixpkgs",
86+ "type": "github"
87+ }
88+ },
57 "root": {
89 "root": {
58 "inputs": {
90 "inputs": {
59− "crane": "crane",
91+ "nixCargoIntegration": "nixCargoIntegration",
60− "flake-utils": "flake-utils",
61 "nixpkgs": "nixpkgs",
92 "nixpkgs": "nixpkgs",
62 "rust-overlay": "rust-overlay"
93 "rust-overlay": "rust-overlay"
63 }
94 }
64 },
95 },
65 "rust-overlay": {
96 "rust-overlay": {
66 "inputs": {
97 "inputs": {
67− "flake-utils": [
98+ "flake-utils": "flake-utils",
68− "flake-utils"
69− ],
70− "nixpkgs": [
99+ "nixpkgs": "nixpkgs_2"
71− "nixpkgs"
72− ]
73 },
100 },
74 "locked": {
101 "locked": {
75− "lastModified": 1701137803,
102+ "lastModified": 1639880499,
76− "narHash": "sha256-0LcPAdql5IhQSUXJx3Zna0dYTgdIoYO7zUrsKgiBd04=",
103+ "narHash": "sha256-/BibDmFwgWuuTUkNVO6YlvuTSWM9dpBvlZoTAPs7ORI=",
77 "owner": "oxalica",
104 "owner": "oxalica",
78 "repo": "rust-overlay",
105 "repo": "rust-overlay",
79− "rev": "9dd940c967502f844eacea52a61e9596268d4f70",
106+ "rev": "c6c83589ae048af20d93d01eb07a4176012093d0",
80 "type": "github"
107 "type": "github"
81 },
108 },
82 "original": {
109 "original": {
@@ -84,21 +111,6 @@
84 "repo": "rust-overlay",
111 "repo": "rust-overlay",
85 "type": "github"
112 "type": "github"
86 }
113 }
87− },
88− "systems": {
89− "locked": {
90− "lastModified": 1681028828,
91− "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
92− "owner": "nix-systems",
93− "repo": "default",
94− "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
95− "type": "github"
96− },
97− "original": {
98− "owner": "nix-systems",
99− "repo": "default",
100− "type": "github"
101− }
102 }
114 }
103 },
115 },
104 "root": "root",
116 "root": "root",
flake.nix+55−184
@@ -3,198 +3,69 @@
3
3
4 inputs = {
4 inputs = {
5 nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
5 nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
6− flake-utils.url = "github:numtide/flake-utils";
7− rust-overlay = {
8− url = "github:oxalica/rust-overlay";
6+ rust-overlay.url = "github:oxalica/rust-overlay";
9− inputs = {
7+ nixCargoIntegration = {
10− nixpkgs.follows = "nixpkgs";
8+ url = "github:yusdacra/nix-cargo-integration";
11− flake-utils.follows = "flake-utils";
12− };
13− };
14− crane = {
15− url = "github:ipetkov/crane";
16 inputs.nixpkgs.follows = "nixpkgs";
9 inputs.nixpkgs.follows = "nixpkgs";
10+ inputs.rustOverlay.follows = "rust-overlay";
17 };
11 };
18 };
12 };
19
13
20− outputs = {
14+ outputs = inputs@{ self, nixCargoIntegration, ... }:
21− self,
15+ nixCargoIntegration.lib.makeOutputs {
22− nixpkgs,
16+ root = ./.;
23− crane,
17+ buildPlatform = "crate2nix";
24− flake-utils,
18+ renameOutputs = { "helix-term" = "helix"; };
25− rust-overlay,
19+ # Set default app to hx (binary is from helix-term release build)
26− ...
20+ # Set default package to helix-term release build
27− }:
21+ defaultOutputs = { app = "hx"; package = "helix"; };
28− flake-utils.lib.eachDefaultSystem (system: let
22+ overrides = {
29− pkgs = import nixpkgs {
23+ crateOverrides = common: _: {
30− inherit system;
24+ helix-term = prev: {
31− overlays = [(import rust-overlay)];
25+ # link languages and theme toml files since helix-term expects them (for tests)
32− };
26+ preConfigure = "ln -s ${common.root}/{languages.toml,theme.toml} ..";
33− mkRootPath = rel:
27+ buildInputs = (prev.buildInputs or [ ]) ++ [ common.cCompiler.cc.lib ];
34− builtins.path {
28+ };
35− path = "${toString ./.}/${rel}";
29+ # link languages and theme toml files since helix-view expects them
36− name = rel;
30+ helix-view = _: { preConfigure = "ln -s ${common.root}/{languages.toml,theme.toml} .."; };
31+ helix-syntax = _prev: {
32+ preConfigure = "mkdir -p ../runtime/grammars";
33+ postInstall = "cp -r ../runtime $out/runtime";
34+ };
37 };
35 };
38− filteredSource = let
36+ mainBuild = common: prev:
39− pathsToIgnore = [
37+ let
40− ".envrc"
38+ inherit (common) pkgs lib;
41− ".ignore"
39+ helixSyntax = lib.buildCrate {
42− ".github"
40+ root = self;
43− ".gitignore"
41+ memberName = "helix-syntax";
44− "logo_dark.svg"
42+ defaultCrateOverrides = {
45− "logo_light.svg"
43+ helix-syntax = common.crateOverrides.helix-syntax;
46− "rust-toolchain.toml"
47− "rustfmt.toml"
48− "runtime"
49− "screenshot.png"
50− "book"
51− "docs"
52− "README.md"
53− "CHANGELOG.md"
54− "shell.nix"
55− "default.nix"
56− "grammars.nix"
57− "flake.nix"
58− "flake.lock"
59− ];
60− ignorePaths = path: type: let
61− inherit (nixpkgs) lib;
62− # split the nix store path into its components
63− components = lib.splitString "/" path;
64− # drop off the `/nix/hash-source` section from the path
65− relPathComponents = lib.drop 4 components;
66− # reassemble the path components
67− relPath = lib.concatStringsSep "/" relPathComponents;
68− in
69− lib.all (p: ! (lib.hasPrefix p relPath)) pathsToIgnore;
70− in
71− builtins.path {
72− name = "helix-source";
73− path = toString ./.;
74− # filter out unnecessary paths
75− filter = ignorePaths;
76− };
77− makeOverridableHelix = old: config: let
78− grammars = pkgs.callPackage ./grammars.nix config;
79− runtimeDir = pkgs.runCommand "helix-runtime" {} ''
80− mkdir -p $out
81− ln -s ${mkRootPath "runtime"}/* $out
82− rm -r $out/grammars
83− ln -s ${grammars} $out/grammars
84− '';
85− helix-wrapped =
86− pkgs.runCommand
87− old.name
88− {
89− inherit (old) pname version;
90− meta = old.meta or {};
91− passthru =
92− (old.passthru or {})
93− // {
94− unwrapped = old;
95 };
44 };
96− nativeBuildInputs = [pkgs.makeWrapper];
45+ release = false;
97− makeWrapperArgs = config.makeWrapperArgs or [];
98− }
99− ''
100− cp -rs --no-preserve=mode,ownership ${old} $out
101− wrapProgram "$out/bin/hx" ''${makeWrapperArgs[@]} --set HELIX_RUNTIME "${runtimeDir}"
102− '';
103− in
104− helix-wrapped
105− // {
106− override = makeOverridableHelix old;
107− passthru =
108− helix-wrapped.passthru
109− // {
110− wrapper = old: makeOverridableHelix old config;
111 };
46 };
112− };
47+ runtimeDir = pkgs.runCommand "helix-runtime" { } ''
113− stdenv =
48+ mkdir -p $out
114− if pkgs.stdenv.isLinux
49+ ln -s ${common.root}/runtime/* $out
115− then pkgs.stdenv
50+ ln -sf ${helixSyntax}/runtime/grammars $out
116− else pkgs.clangStdenv;
117− rustFlagsEnv =
118− if stdenv.isLinux
119− then ''$RUSTFLAGS -C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment''
120− else "$RUSTFLAGS";
121− rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
122− craneLibMSRV = (crane.mkLib pkgs).overrideToolchain rustToolchain;
123− craneLibStable = (crane.mkLib pkgs).overrideToolchain pkgs.pkgsBuildHost.rust-bin.stable.latest.default;
124− commonArgs = {
125− inherit stdenv;
126− inherit (craneLibMSRV.crateNameFromCargoToml {cargoToml = ./helix-term/Cargo.toml;}) pname;
127− inherit (craneLibMSRV.crateNameFromCargoToml {cargoToml = ./Cargo.toml;}) version;
128− src = filteredSource;
129− # disable fetching and building of tree-sitter grammars in the helix-term build.rs
130− HELIX_DISABLE_AUTO_GRAMMAR_BUILD = "1";
131− buildInputs = [stdenv.cc.cc.lib];
132− # disable tests
133− doCheck = false;
134− meta.mainProgram = "hx";
135− };
136− cargoArtifacts = craneLibMSRV.buildDepsOnly commonArgs;
137− in {
138− packages = {
139− helix-unwrapped = craneLibStable.buildPackage (commonArgs
140− // {
141− cargoArtifacts = craneLibStable.buildDepsOnly commonArgs;
142− postInstall = ''
143− mkdir -p $out/share/applications $out/share/icons/hicolor/scalable/apps $out/share/icons/hicolor/256x256/apps
144− cp contrib/Helix.desktop $out/share/applications
145− cp logo.svg $out/share/icons/hicolor/scalable/apps/helix.svg
146− cp contrib/helix.png $out/share/icons/hicolor/256x256/apps
147 '';
51 '';
148− });
52+ in
149− helix = makeOverridableHelix self.packages.${system}.helix-unwrapped {};
53+ lib.optionalAttrs (common.memberName == "helix-term") {
150− default = self.packages.${system}.helix;
151− };
152−
153− checks = {
154− # Build the crate itself
155− inherit (self.packages.${system}) helix;
156−
157− clippy = craneLibMSRV.cargoClippy (commonArgs
158− // {
159− inherit cargoArtifacts;
160− cargoClippyExtraArgs = "--all-targets -- --deny warnings";
161− });
162−
163− fmt = craneLibMSRV.cargoFmt commonArgs;
164−
165− doc = craneLibMSRV.cargoDoc (commonArgs
166− // {
167− inherit cargoArtifacts;
168− });
169−
170− test = craneLibMSRV.cargoTest (commonArgs
171− // {
172− inherit cargoArtifacts;
173− });
174− };
175−
176− devShells.default = pkgs.mkShell {
177− inputsFrom = builtins.attrValues self.checks.${system};
178− nativeBuildInputs = with pkgs;
54+ nativeBuildInputs = [ pkgs.makeWrapper ];
179− [lld_13 cargo-flamegraph rust-analyzer]
55+ postFixup = ''
180− ++ (lib.optional (stdenv.isx86_64 && stdenv.isLinux) pkgs.cargo-tarpaulin)
56+ if [ -f "$out/bin/hx" ]; then
181− ++ (lib.optional stdenv.isLinux pkgs.lldb)
57+ wrapProgram "$out/bin/hx" --set HELIX_RUNTIME "${runtimeDir}"
182− ++ (lib.optional stdenv.isDarwin pkgs.darwin.apple_sdk.frameworks.CoreFoundation);
58+ fi
183− shellHook = ''
59+ '';
60+ };
61+ shell = common: prev: {
62+ packages = prev.packages ++ (with common.pkgs; [ lld_13 lldb cargo-tarpaulin ]);
63+ env = prev.env ++ [
184− export HELIX_RUNTIME="$PWD/runtime"
64+ { name = "HELIX_RUNTIME"; eval = "$PWD/runtime"; }
185− export RUST_BACKTRACE="1"
65+ { name = "RUST_BACKTRACE"; value = "1"; }
186− export RUSTFLAGS="${rustFlagsEnv}"
66+ { name = "RUSTFLAGS"; value = "-C link-arg=-fuse-ld=lld -C target-cpu=native"; }
187− '';
67+ ];
188− };
68+ };
189− })
190− // {
191− overlays.default = final: prev: {
192− inherit (self.packages.${final.system}) helix;
193 };
69 };
194 };
70 };
195−
196− nixConfig = {
197− extra-substituters = ["https://helix.cachix.org"];
198− extra-trusted-public-keys = ["helix.cachix.org-1:ejp9KQpR1FBI2onstMQ34yogDm4OgU2ru6lIwPvuCVs="];
199− };
200}
71}
grammars.nixdeleted−124
@@ -1,124 +0,0 @@
1−{
2− stdenv,
3− lib,
4− runCommandLocal,
5− runCommand,
6− yj,
7− includeGrammarIf ? _: true,
8− grammarOverlays ? [],
9− ...
10−}: let
11− # HACK: nix < 2.6 has a bug in the toml parser, so we convert to JSON
12− # before parsing
13− languages-json = runCommandLocal "languages-toml-to-json" {} ''
14− ${yj}/bin/yj -t < ${./languages.toml} > $out
15− '';
16− languagesConfig =
17− if lib.versionAtLeast builtins.nixVersion "2.6.0"
18− then builtins.fromTOML (builtins.readFile ./languages.toml)
19− else builtins.fromJSON (builtins.readFile (builtins.toPath languages-json));
20− isGitGrammar = grammar:
21− builtins.hasAttr "source" grammar
22− && builtins.hasAttr "git" grammar.source
23− && builtins.hasAttr "rev" grammar.source;
24− isGitHubGrammar = grammar: lib.hasPrefix "https://github.com" grammar.source.git;
25− toGitHubFetcher = url: let
26− match = builtins.match "https://github\.com/([^/]*)/([^/]*)/?" url;
27− in {
28− owner = builtins.elemAt match 0;
29− repo = builtins.elemAt match 1;
30− };
31− gitGrammars = builtins.filter isGitGrammar languagesConfig.grammar;
32− buildGrammar = grammar: let
33− gh = toGitHubFetcher grammar.source.git;
34− sourceGit = builtins.fetchTree {
35− type = "git";
36− url = grammar.source.git;
37− rev = grammar.source.rev;
38− ref = grammar.source.ref or "HEAD";
39− shallow = true;
40− };
41− sourceGitHub = builtins.fetchTree {
42− type = "github";
43− owner = gh.owner;
44− repo = gh.repo;
45− inherit (grammar.source) rev;
46− };
47− source =
48− if isGitHubGrammar grammar
49− then sourceGitHub
50− else sourceGit;
51− in
52− stdenv.mkDerivation {
53− # see https://github.com/NixOS/nixpkgs/blob/fbdd1a7c0bc29af5325e0d7dd70e804a972eb465/pkgs/development/tools/parsing/tree-sitter/grammar.nix
54−
55− pname = "helix-tree-sitter-${grammar.name}";
56− version = grammar.source.rev;
57−
58− src = source;
59− sourceRoot = if builtins.hasAttr "subpath" grammar.source then
60− "source/${grammar.source.subpath}"
61− else
62− "source";
63−
64− dontConfigure = true;
65−
66− FLAGS = [
67− "-Isrc"
68− "-g"
69− "-O3"
70− "-fPIC"
71− "-fno-exceptions"
72− "-Wl,-z,relro,-z,now"
73− ];
74−
75− NAME = grammar.name;
76−
77− buildPhase = ''
78− runHook preBuild
79−
80− if [[ -e src/scanner.cc ]]; then
81− $CXX -c src/scanner.cc -o scanner.o $FLAGS
82− elif [[ -e src/scanner.c ]]; then
83− $CC -c src/scanner.c -o scanner.o $FLAGS
84− fi
85−
86− $CC -c src/parser.c -o parser.o $FLAGS
87− $CXX -shared -o $NAME.so *.o
88−
89− ls -al
90−
91− runHook postBuild
92− '';
93−
94− installPhase = ''
95− runHook preInstall
96− mkdir $out
97− mv $NAME.so $out/
98− runHook postInstall
99− '';
100−
101− # Strip failed on darwin: strip: error: symbols referenced by indirect symbol table entries that can't be stripped
102− fixupPhase = lib.optionalString stdenv.isLinux ''
103− runHook preFixup
104− $STRIP $out/$NAME.so
105− runHook postFixup
106− '';
107− };
108− grammarsToBuild = builtins.filter includeGrammarIf gitGrammars;
109− builtGrammars = builtins.map (grammar: {
110− inherit (grammar) name;
111− value = buildGrammar grammar;
112− }) grammarsToBuild;
113− extensibleGrammars =
114− lib.makeExtensible (self: builtins.listToAttrs builtGrammars);
115− overlayedGrammars = lib.pipe extensibleGrammars
116− (builtins.map (overlay: grammar: grammar.extend overlay) grammarOverlays);
117− grammarLinks = lib.mapAttrsToList
118− (name: artifact: "ln -s ${artifact}/${name}.so $out/${name}.so")
119− (lib.filterAttrs (n: v: lib.isDerivation v) overlayedGrammars);
120−in
121− runCommand "consolidated-helix-grammars" {} ''
122− mkdir -p $out
123− ${builtins.concatStringsSep "\n" grammarLinks}
124− ''
helix-core/Cargo.toml+18−32
@@ -1,57 +1,43 @@
1[package]
1[package]
2name = "helix-core"
2name = "helix-core"
3+version = "0.5.0"
4+authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
5+edition = "2021"
6+license = "MPL-2.0"
3description = "Helix editor core editing primitives"
7description = "Helix editor core editing primitives"
8+categories = ["editor"]
9+repository = "https://github.com/helix-editor/helix"
10+homepage = "https://helix-editor.com"
4include = ["src/**/*", "README.md"]
11include = ["src/**/*", "README.md"]
5−version.workspace = true
6−authors.workspace = true
7−edition.workspace = true
8−license.workspace = true
9−rust-version.workspace = true
10−categories.workspace = true
11−repository.workspace = true
12−homepage.workspace = true
13
12
14[features]
13[features]
15−unicode-lines = ["ropey/unicode_lines"]
16−integration = []
17
14
18[dependencies]
15[dependencies]
19−helix-loader = { path = "../helix-loader" }
16+helix-syntax = { version = "0.5", path = "../helix-syntax" }
20
17
21−ropey = { version = "1.6.1", default-features = false, features = ["simd"] }
18+ropey = "1.3"
22−smallvec = "1.11"
19+smallvec = "1.7"
23−smartstring = "1.0.1"
20+tendril = "0.4.2"
24−unicode-segmentation = "1.10"
21+unicode-segmentation = "1.8"
25unicode-width = "0.1"
22unicode-width = "0.1"
26−unicode-general-category = "0.6"
23+unicode-general-category = "0.4"
27# slab = "0.4.2"
24# slab = "0.4.2"
28−slotmap = "1.0"
29−tree-sitter.workspace = true
25+tree-sitter = "0.20"
30−once_cell = "1.19"
26+once_cell = "1.9"
31arc-swap = "1"
27arc-swap = "1"
32regex = "1"
28regex = "1"
33−bitflags = "2.4"
34−ahash = "0.8.6"
35−hashbrown = { version = "0.14.3", features = ["raw"] }
36−dunce = "1.0"
37
29
38log = "0.4"
30log = "0.4"
39serde = { version = "1.0", features = ["derive"] }
31serde = { version = "1.0", features = ["derive"] }
40serde_json = "1.0"
32serde_json = "1.0"
41−toml = "0.7"
33+toml = "0.5"
42
34
43−imara-diff = "0.1.0"
35+similar = "2.1"
44
36
37+etcetera = "0.3"
45encoding_rs = "0.8"
38encoding_rs = "0.8"
46
39
47chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }
40chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }
48
41
49−etcetera = "0.8"
50−textwrap = "0.16.0"
51−
52−nucleo.workspace = true
53−parking_lot = "0.12"
54−
55[dev-dependencies]
42[dev-dependencies]
56quickcheck = { version = "1", default-features = false }
43quickcheck = { version = "1", default-features = false }
57−indoc = "2.0.4"
helix-core/src/auto_pairs.rs+473−237
@@ -1,13 +1,13 @@
1//! When typing the opening character of one of the possible pairs defined below,
1//! When typing the opening character of one of the possible pairs defined below,
2//! this module provides the functionality to insert the paired closing character.
2//! this module provides the functionality to insert the paired closing character.
3
3
4−use crate::{graphemes, movement::Direction, Range, Rope, Selection, Tendril, Transaction};
4+use crate::{movement::Direction, Range, Rope, Selection, Tendril, Transaction};
5−use std::collections::HashMap;
5+use log::debug;
6−
7use smallvec::SmallVec;
6use smallvec::SmallVec;
8
7
9// Heavily based on https://github.com/codemirror/closebrackets/
8// Heavily based on https://github.com/codemirror/closebrackets/
9+
10−pub const DEFAULT_PAIRS: &[(char, char)] = &[
10+pub const PAIRS: &[(char, char)] = &[
11 ('(', ')'),
11 ('(', ')'),
12 ('{', '}'),
12 ('{', '}'),
13 ('[', ']'),
13 ('[', ']'),
@@ -16,95 +16,9 @@ pub const DEFAULT_PAIRS: &[(char, char)] = &[
16 ('`', '`'),
16 ('`', '`'),
17];
17];
18
18
19−/// The type that represents the collection of auto pairs,
19+// [TODO] build this dynamically in language config. see #992
20−/// keyed by both opener and closer.
20+const OPEN_BEFORE: &str = "([{'\":;,> \n\r\u{000B}\u{000C}\u{0085}\u{2028}\u{2029}";
21−#[derive(Debug, Clone)]
21+const CLOSE_BEFORE: &str = ")]}'\":;,> \n\r\u{000B}\u{000C}\u{0085}\u{2028}\u{2029}"; // includes space and newlines
22−pub struct AutoPairs(HashMap<char, Pair>);
23−
24−/// Represents the config for a particular pairing.
25−#[derive(Debug, Clone, Copy)]
26−pub struct Pair {
27− pub open: char,
28− pub close: char,
29−}
30−
31−impl Pair {
32− /// true if open == close
33− pub fn same(&self) -> bool {
34− self.open == self.close
35− }
36−
37− /// true if all of the pair's conditions hold for the given document and range
38− pub fn should_close(&self, doc: &Rope, range: &Range) -> bool {
39− let mut should_close = Self::next_is_not_alpha(doc, range);
40−
41− if self.same() {
42− should_close &= Self::prev_is_not_alpha(doc, range);
43− }
44−
45− should_close
46− }
47−
48− pub fn next_is_not_alpha(doc: &Rope, range: &Range) -> bool {
49− let cursor = range.cursor(doc.slice(..));
50− let next_char = doc.get_char(cursor);
51− next_char.map(|c| !c.is_alphanumeric()).unwrap_or(true)
52− }
53−
54− pub fn prev_is_not_alpha(doc: &Rope, range: &Range) -> bool {
55− let cursor = range.cursor(doc.slice(..));
56− let prev_char = prev_char(doc, cursor);
57− prev_char.map(|c| !c.is_alphanumeric()).unwrap_or(true)
58− }
59−}
60−
61−impl From<&(char, char)> for Pair {
62− fn from(&(open, close): &(char, char)) -> Self {
63− Self { open, close }
64− }
65−}
66−
67−impl From<(&char, &char)> for Pair {
68− fn from((open, close): (&char, &char)) -> Self {
69− Self {
70− open: *open,
71− close: *close,
72− }
73− }
74−}
75−
76−impl AutoPairs {
77− /// Make a new AutoPairs set with the given pairs and default conditions.
78− pub fn new<'a, V: 'a, A>(pairs: V) -> Self
79− where
80− V: IntoIterator<Item = A>,
81− A: Into<Pair>,
82− {
83− let mut auto_pairs = HashMap::new();
84−
85− for pair in pairs.into_iter() {
86− let auto_pair = pair.into();
87−
88− auto_pairs.insert(auto_pair.open, auto_pair);
89−
90− if auto_pair.open != auto_pair.close {
91− auto_pairs.insert(auto_pair.close, auto_pair);
92− }
93− }
94−
95− Self(auto_pairs)
96− }
97−
98− pub fn get(&self, ch: char) -> Option<&Pair> {
99− self.0.get(&ch)
100− }
101−}
102−
103−impl Default for AutoPairs {
104− fn default() -> Self {
105− AutoPairs::new(DEFAULT_PAIRS.iter())
106− }
107−}
108
22
109// insert hook:
23// insert hook:
110// Fn(doc, selection, char) => Option<Transaction>
24// Fn(doc, selection, char) => Option<Transaction>
@@ -120,17 +34,21 @@ impl Default for AutoPairs {
120// middle of triple quotes, and more exotic pairs like Jinja's {% %}
34// middle of triple quotes, and more exotic pairs like Jinja's {% %}
121
35
122#[must_use]
36#[must_use]
123−pub fn hook(doc: &Rope, selection: &Selection, ch: char, pairs: &AutoPairs) -> Option<Transaction> {
37+pub fn hook(doc: &Rope, selection: &Selection, ch: char) -> Option<Transaction> {
124− log::trace!("autopairs hook selection: {:#?}", selection);
38+ debug!("autopairs hook selection: {:#?}", selection);
125−
39+
126− if let Some(pair) = pairs.get(ch) {
40+ for &(open, close) in PAIRS {
127− if pair.same() {
41+ if open == ch {
128− return Some(handle_same(doc, selection, pair));
42+ if open == close {
129− } else if pair.open == ch {
43+ return Some(handle_same(doc, selection, open, CLOSE_BEFORE, OPEN_BEFORE));
130− return Some(handle_open(doc, selection, pair));
44+ } else {
131− } else if pair.close == ch {
45+ return Some(handle_open(doc, selection, open, close, CLOSE_BEFORE));
46+ }
47+ }
48+
49+ if close == ch {
132 // && char_at pos == close
50 // && char_at pos == close
133− return Some(handle_close(doc, selection, pair));
51+ return Some(handle_close(doc, selection, open, close));
134 }
52 }
135 }
53 }
136
54
@@ -146,123 +64,42 @@ fn prev_char(doc: &Rope, pos: usize) -> Option<char> {
146}
64}
147
65
148/// calculate what the resulting range should be for an auto pair insertion
66/// calculate what the resulting range should be for an auto pair insertion
149−fn get_next_range(doc: &Rope, start_range: &Range, offset: usize, len_inserted: usize) -> Range {
67+fn get_next_range(
150− // When the character under the cursor changes due to complete pair
68+ start_range: &Range,
151− // insertion, we must look backward a grapheme and then add the length
69+ offset: usize,
152− // of the insertion to put the resulting cursor in the right place, e.g.
70+ typed_char: char,
153− //
71+ len_inserted: usize,
154− // foo[\r\n] - anchor: 3, head: 5
72+) -> Range {
155− // foo([)]\r\n - anchor: 4, head: 5
73+ let end_head = start_range.head + offset + typed_char.len_utf8();
156− //
157− // foo[\r\n] - anchor: 3, head: 5
158− // foo'[\r\n] - anchor: 4, head: 6
159− //
160− // foo([)]\r\n - anchor: 4, head: 5
161− // foo()[\r\n] - anchor: 5, head: 7
162− //
163− // [foo]\r\n - anchor: 0, head: 3
164− // [foo(])\r\n - anchor: 0, head: 5
165−
166− // inserting at the very end of the document after the last newline
167− if start_range.head == doc.len_chars() && start_range.anchor == doc.len_chars() {
168− return Range::new(
169− start_range.anchor + offset + 1,
170− start_range.head + offset + 1,
171− );
172− }
173−
174− let doc_slice = doc.slice(..);
175− let single_grapheme = start_range.is_single_grapheme(doc_slice);
176−
177− // just skip over graphemes
178− if len_inserted == 0 {
179− let end_anchor = if single_grapheme {
180− graphemes::next_grapheme_boundary(doc_slice, start_range.anchor) + offset
181−
182− // even for backward inserts with multiple grapheme selections,
183− // we want the anchor to stay where it is so that the relative
184− // selection does not change, e.g.:
185− //
186− // foo([) wor]d -> insert ) -> foo()[ wor]d
187− } else {
188− start_range.anchor + offset
189− };
190−
191− return Range::new(
192− end_anchor,
193− graphemes::next_grapheme_boundary(doc_slice, start_range.head) + offset,
194− );
195− }
196−
197− // trivial case: only inserted a single-char opener, just move the selection
198− if len_inserted == 1 {
199− let end_anchor = if single_grapheme || start_range.direction() == Direction::Backward {
200− start_range.anchor + offset + 1
201− } else {
202− start_range.anchor + offset
203− };
204−
205− return Range::new(end_anchor, start_range.head + offset + 1);
206− }
207−
208− // If the head = 0, then we must be in insert mode with a backward
209− // cursor, which implies the head will just move
210− let end_head = if start_range.head == 0 || start_range.direction() == Direction::Backward {
211− start_range.head + offset + 1
212− } else {
213− // We must have a forward cursor, which means we must move to the
214− // other end of the grapheme to get to where the new characters
215− // are inserted, then move the head to where it should be
216− let prev_bound = graphemes::prev_grapheme_boundary(doc_slice, start_range.head);
217− log::trace!(
218− "prev_bound: {}, offset: {}, len_inserted: {}",
219− prev_bound,
220− offset,
221− len_inserted
222− );
223− prev_bound + offset + len_inserted
224− };
225
74
226 let end_anchor = match (start_range.len(), start_range.direction()) {
75 let end_anchor = match (start_range.len(), start_range.direction()) {
227 // if we have a zero width cursor, it shifts to the same number
76 // if we have a zero width cursor, it shifts to the same number
228 (0, _) => end_head,
77 (0, _) => end_head,
229
78
230− // If we are inserting for a regular one-width cursor, the anchor
79+ // if we are inserting for a regular one-width cursor, the anchor
231− // moves with the head. This is the fast path for ASCII.
80+ // moves with the head
232 (1, Direction::Forward) => end_head - 1,
81 (1, Direction::Forward) => end_head - 1,
233 (1, Direction::Backward) => end_head + 1,
82 (1, Direction::Backward) => end_head + 1,
234
83
235− (_, Direction::Forward) => {
84+ // if we are appending, the anchor stays where it is; only offset
236− if single_grapheme {
85+ // for multiple range insertions
237− graphemes::prev_grapheme_boundary(doc.slice(..), start_range.head) + 1
86+ (_, Direction::Forward) => start_range.anchor + offset,
238−
239− // if we are appending, the anchor stays where it is; only offset
240− // for multiple range insertions
241− } else {
242− start_range.anchor + offset
243− }
244− }
245
87
246− (_, Direction::Backward) => {
88+ // when we are inserting in front of a selection, we need to move
247− if single_grapheme {
89+ // the anchor over by however many characters were inserted overall
248− // if we're backward, then the head is at the first char
90+ (_, Direction::Backward) => start_range.anchor + offset + len_inserted,
249− // of the typed char, so we need to add the length of
250− // the closing char
251− graphemes::prev_grapheme_boundary(doc.slice(..), start_range.anchor)
252− + len_inserted
253− + offset
254− } else {
255− // when we are inserting in front of a selection, we need to move
256− // the anchor over by however many characters were inserted overall
257− start_range.anchor + offset + len_inserted
258− }
259− }
260 };
91 };
261
92
262 Range::new(end_anchor, end_head)
93 Range::new(end_anchor, end_head)
263}
94}
264
95
265−fn handle_open(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
96+fn handle_open(
97+ doc: &Rope,
98+ selection: &Selection,
99+ open: char,
100+ close: char,
101+ close_before: &str,
102+) -> Transaction {
266 let mut end_ranges = SmallVec::with_capacity(selection.len());
103 let mut end_ranges = SmallVec::with_capacity(selection.len());
267 let mut offs = 0;
104 let mut offs = 0;
268
105
@@ -271,25 +108,21 @@ fn handle_open(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
271 let next_char = doc.get_char(cursor);
108 let next_char = doc.get_char(cursor);
272 let len_inserted;
109 let len_inserted;
273
110
274− // Since auto pairs are currently limited to single chars, we're either
275− // inserting exactly one or two chars. When arbitrary length pairs are
276− // added, these will need to be changed.
277 let change = match next_char {
111 let change = match next_char {
278− Some(_) if !pair.should_close(doc, start_range) => {
112+ Some(ch) if !close_before.contains(ch) => {
279− len_inserted = 1;
113+ len_inserted = open.len_utf8();
280− let mut tendril = Tendril::new();
114+ (cursor, cursor, Some(Tendril::from_char(open)))
281− tendril.push(pair.open);
282− (cursor, cursor, Some(tendril))
283 }
115 }
116+ // None | Some(ch) if close_before.contains(ch) => {}
284 _ => {
117 _ => {
285 // insert open & close
118 // insert open & close
286− let pair_str = Tendril::from_iter([pair.open, pair.close]);
119+ let pair = Tendril::from_iter([open, close]);
287− len_inserted = 2;
120+ len_inserted = open.len_utf8() + close.len_utf8();
288− (cursor, cursor, Some(pair_str))
121+ (cursor, cursor, Some(pair))
289 }
122 }
290 };
123 };
291
124
292− let next_range = get_next_range(doc, start_range, offs, len_inserted);
125+ let next_range = get_next_range(start_range, offs, open, len_inserted);
293 end_ranges.push(next_range);
126 end_ranges.push(next_range);
294 offs += len_inserted;
127 offs += len_inserted;
295
128
@@ -297,12 +130,13 @@ fn handle_open(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
297 });
130 });
298
131
299 let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index()));
132 let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index()));
300− log::debug!("auto pair transaction: {:#?}", t);
133+ debug!("auto pair transaction: {:#?}", t);
301 t
134 t
302}
135}
303
136
304−fn handle_close(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
137+fn handle_close(doc: &Rope, selection: &Selection, _open: char, close: char) -> Transaction {
305 let mut end_ranges = SmallVec::with_capacity(selection.len());
138 let mut end_ranges = SmallVec::with_capacity(selection.len());
139+
306 let mut offs = 0;
140 let mut offs = 0;
307
141
308 let transaction = Transaction::change_by_selection(doc, selection, |start_range| {
142 let transaction = Transaction::change_by_selection(doc, selection, |start_range| {
@@ -310,17 +144,15 @@ fn handle_close(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
310 let next_char = doc.get_char(cursor);
144 let next_char = doc.get_char(cursor);
311 let mut len_inserted = 0;
145 let mut len_inserted = 0;
312
146
313− let change = if next_char == Some(pair.close) {
147+ let change = if next_char == Some(close) {
314 // return transaction that moves past close
148 // return transaction that moves past close
315 (cursor, cursor, None) // no-op
149 (cursor, cursor, None) // no-op
316 } else {
150 } else {
317− len_inserted = 1;
151+ len_inserted += close.len_utf8();
318− let mut tendril = Tendril::new();
152+ (cursor, cursor, Some(Tendril::from_char(close)))
319− tendril.push(pair.close);
320− (cursor, cursor, Some(tendril))
321 };
153 };
322
154
323− let next_range = get_next_range(doc, start_range, offs, len_inserted);
155+ let next_range = get_next_range(start_range, offs, close, len_inserted);
324 end_ranges.push(next_range);
156 end_ranges.push(next_range);
325 offs += len_inserted;
157 offs += len_inserted;
326
158
@@ -328,12 +160,18 @@ fn handle_close(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
328 });
160 });
329
161
330 let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index()));
162 let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index()));
331− log::debug!("auto pair transaction: {:#?}", t);
163+ debug!("auto pair transaction: {:#?}", t);
332 t
164 t
333}
165}
334
166
335/// handle cases where open and close is the same, or in triples ("""docstring""")
167/// handle cases where open and close is the same, or in triples ("""docstring""")
336−fn handle_same(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
168+fn handle_same(
169+ doc: &Rope,
170+ selection: &Selection,
171+ token: char,
172+ close_before: &str,
173+ open_before: &str,
174+) -> Transaction {
337 let mut end_ranges = SmallVec::with_capacity(selection.len());
175 let mut end_ranges = SmallVec::with_capacity(selection.len());
338
176
339 let mut offs = 0;
177 let mut offs = 0;
@@ -341,26 +179,30 @@ fn handle_same(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
341 let transaction = Transaction::change_by_selection(doc, selection, |start_range| {
179 let transaction = Transaction::change_by_selection(doc, selection, |start_range| {
342 let cursor = start_range.cursor(doc.slice(..));
180 let cursor = start_range.cursor(doc.slice(..));
343 let mut len_inserted = 0;
181 let mut len_inserted = 0;
182+
344 let next_char = doc.get_char(cursor);
183 let next_char = doc.get_char(cursor);
184+ let prev_char = prev_char(doc, cursor);
345
185
346− let change = if next_char == Some(pair.open) {
186+ let change = if next_char == Some(token) {
347 // return transaction that moves past close
187 // return transaction that moves past close
348 (cursor, cursor, None) // no-op
188 (cursor, cursor, None) // no-op
349 } else {
189 } else {
350− let mut pair_str = Tendril::new();
190+ let mut pair = Tendril::with_capacity(2 * token.len_utf8() as u32);
351− pair_str.push(pair.open);
191+ pair.push_char(token);
352
192
353 // for equal pairs, don't insert both open and close if either
193 // for equal pairs, don't insert both open and close if either
354 // side has a non-pair char
194 // side has a non-pair char
355− if pair.should_close(doc, start_range) {
195+ if (next_char.is_none() || close_before.contains(next_char.unwrap()))
356− pair_str.push(pair.close);
196+ && (prev_char.is_none() || open_before.contains(prev_char.unwrap()))
197+ {
198+ pair.push_char(token);
357 }
199 }
358
200
359− len_inserted += pair_str.chars().count();
201+ len_inserted += pair.len();
360− (cursor, cursor, Some(pair_str))
202+ (cursor, cursor, Some(pair))
361 };
203 };
362
204
363− let next_range = get_next_range(doc, start_range, offs, len_inserted);
205+ let next_range = get_next_range(start_range, offs, token, len_inserted);
364 end_ranges.push(next_range);
206 end_ranges.push(next_range);
365 offs += len_inserted;
207 offs += len_inserted;
366
208
@@ -368,6 +210,400 @@ fn handle_same(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
368 });
210 });
369
211
370 let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index()));
212 let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index()));
371− log::debug!("auto pair transaction: {:#?}", t);
213+ debug!("auto pair transaction: {:#?}", t);
372 t
214 t
373}
215}
216+
217+#[cfg(test)]
218+mod test {
219+ use super::*;
220+ use smallvec::smallvec;
221+
222+ fn differing_pairs() -> impl Iterator<Item = &'static (char, char)> {
223+ PAIRS.iter().filter(|(open, close)| open != close)
224+ }
225+
226+ fn matching_pairs() -> impl Iterator<Item = &'static (char, char)> {
227+ PAIRS.iter().filter(|(open, close)| open == close)
228+ }
229+
230+ fn test_hooks(
231+ in_doc: &Rope,
232+ in_sel: &Selection,
233+ ch: char,
234+ expected_doc: &Rope,
235+ expected_sel: &Selection,
236+ ) {
237+ let trans = hook(&in_doc, &in_sel, ch).unwrap();
238+ let mut actual_doc = in_doc.clone();
239+ assert!(trans.apply(&mut actual_doc));
240+ assert_eq!(expected_doc, &actual_doc);
241+ assert_eq!(expected_sel, trans.selection().unwrap());
242+ }
243+
244+ fn test_hooks_with_pairs<I, F, R>(
245+ in_doc: &Rope,
246+ in_sel: &Selection,
247+ pairs: I,
248+ get_expected_doc: F,
249+ actual_sel: &Selection,
250+ ) where
251+ I: IntoIterator<Item = &'static (char, char)>,
252+ F: Fn(char, char) -> R,
253+ R: Into<Rope>,
254+ Rope: From<R>,
255+ {
256+ pairs.into_iter().for_each(|(open, close)| {
257+ test_hooks(
258+ in_doc,
259+ in_sel,
260+ *open,
261+ &Rope::from(get_expected_doc(*open, *close)),
262+ actual_sel,
263+ )
264+ });
265+ }
266+
267+ // [] indicates range
268+
269+ /// [] -> insert ( -> ([])
270+ #[test]
271+ fn test_insert_blank() {
272+ test_hooks_with_pairs(
273+ &Rope::new(),
274+ &Selection::single(1, 0),
275+ PAIRS,
276+ |open, close| format!("{}{}", open, close),
277+ &Selection::single(2, 1),
278+ );
279+ }
280+
281+ /// [] -> append ( -> ([])
282+ #[test]
283+ fn test_append_blank() {
284+ test_hooks_with_pairs(
285+ // this is what happens when you have a totally blank document and then append
286+ &Rope::from("\n\n"),
287+ &Selection::single(0, 2),
288+ PAIRS,
289+ |open, close| format!("\n{}{}\n", open, close),
290+ &Selection::single(0, 3),
291+ );
292+ }
293+
294+ /// [] ([])
295+ /// [] -> insert -> ([])
296+ /// [] ([])
297+ #[test]
298+ fn test_insert_blank_multi_cursor() {
299+ test_hooks_with_pairs(
300+ &Rope::from("\n\n\n"),
301+ &Selection::new(
302+ smallvec!(Range::new(1, 0), Range::new(2, 1), Range::new(3, 2),),
303+ 0,
304+ ),
305+ PAIRS,
306+ |open, close| {
307+ format!(
308+ "{open}{close}\n{open}{close}\n{open}{close}\n",
309+ open = open,
310+ close = close
311+ )
312+ },
313+ &Selection::new(
314+ smallvec!(Range::new(2, 1), Range::new(5, 4), Range::new(8, 7),),
315+ 0,
316+ ),
317+ );
318+ }
319+
320+ /// fo[o] -> append ( -> fo[o(])
321+ #[test]
322+ fn test_append() {
323+ test_hooks_with_pairs(
324+ &Rope::from("foo\n"),
325+ &Selection::single(2, 4),
326+ differing_pairs(),
327+ |open, close| format!("foo{}{}\n", open, close),
328+ &Selection::single(2, 5),
329+ );
330+ }
331+
332+ /// fo[o] fo[o(])
333+ /// fo[o] -> append ( -> fo[o(])
334+ /// fo[o] fo[o(])
335+ #[test]
336+ fn test_append_multi() {
337+ test_hooks_with_pairs(
338+ &Rope::from("foo\nfoo\nfoo\n"),
339+ &Selection::new(
340+ smallvec!(Range::new(2, 4), Range::new(6, 8), Range::new(10, 12)),
341+ 0,
342+ ),
343+ differing_pairs(),
344+ |open, close| {
345+ format!(
346+ "foo{open}{close}\nfoo{open}{close}\nfoo{open}{close}\n",
347+ open = open,
348+ close = close
349+ )
350+ },
351+ &Selection::new(
352+ smallvec!(Range::new(2, 5), Range::new(8, 11), Range::new(14, 17)),
353+ 0,
354+ ),
355+ );
356+ }
357+
358+ /// ([]) -> insert ) -> ()[]
359+ #[test]
360+ fn test_insert_close_inside_pair() {
361+ for (open, close) in PAIRS {
362+ let doc = Rope::from(format!("{}{}", open, close));
363+
364+ test_hooks(
365+ &doc,
366+ &Selection::single(2, 1),
367+ *close,
368+ &doc,
369+ &Selection::single(3, 2),
370+ );
371+ }
372+ }
373+
374+ /// [(]) -> append ) -> [()]
375+ #[test]
376+ fn test_append_close_inside_pair() {
377+ for (open, close) in PAIRS {
378+ let doc = Rope::from(format!("{}{}\n", open, close));
379+
380+ test_hooks(
381+ &doc,
382+ &Selection::single(0, 2),
383+ *close,
384+ &doc,
385+ &Selection::single(0, 3),
386+ );
387+ }
388+ }
389+
390+ /// ([]) ()[]
391+ /// ([]) -> insert ) -> ()[]
392+ /// ([]) ()[]
393+ #[test]
394+ fn test_insert_close_inside_pair_multi_cursor() {
395+ let sel = Selection::new(
396+ smallvec!(Range::new(2, 1), Range::new(5, 4), Range::new(8, 7),),
397+ 0,
398+ );
399+
400+ let expected_sel = Selection::new(
401+ smallvec!(Range::new(3, 2), Range::new(6, 5), Range::new(9, 8),),
402+ 0,
403+ );
404+
405+ for (open, close) in PAIRS {
406+ let doc = Rope::from(format!(
407+ "{open}{close}\n{open}{close}\n{open}{close}\n",
408+ open = open,
409+ close = close
410+ ));
411+
412+ test_hooks(&doc, &sel, *close, &doc, &expected_sel);
413+ }
414+ }
415+
416+ /// [(]) [()]
417+ /// [(]) -> append ) -> [()]
418+ /// [(]) [()]
419+ #[test]
420+ fn test_append_close_inside_pair_multi_cursor() {
421+ let sel = Selection::new(
422+ smallvec!(Range::new(0, 2), Range::new(3, 5), Range::new(6, 8),),
423+ 0,
424+ );
425+
426+ let expected_sel = Selection::new(
427+ smallvec!(Range::new(0, 3), Range::new(3, 6), Range::new(6, 9),),
428+ 0,
429+ );
430+
431+ for (open, close) in PAIRS {
432+ let doc = Rope::from(format!(
433+ "{open}{close}\n{open}{close}\n{open}{close}\n",
434+ open = open,
435+ close = close
436+ ));
437+
438+ test_hooks(&doc, &sel, *close, &doc, &expected_sel);
439+ }
440+ }
441+
442+ /// ([]) -> insert ( -> (([]))
443+ #[test]
444+ fn test_insert_open_inside_pair() {
445+ let sel = Selection::single(2, 1);
446+ let expected_sel = Selection::single(3, 2);
447+
448+ for (open, close) in differing_pairs() {
449+ let doc = Rope::from(format!("{}{}", open, close));
450+ let expected_doc = Rope::from(format!(
451+ "{open}{open}{close}{close}",
452+ open = open,
453+ close = close
454+ ));
455+
456+ test_hooks(&doc, &sel, *open, &expected_doc, &expected_sel);
457+ }
458+ }
459+
460+ /// [word(]) -> append ( -> [word((]))
461+ #[test]
462+ fn test_append_open_inside_pair() {
463+ let sel = Selection::single(0, 6);
464+ let expected_sel = Selection::single(0, 7);
465+
466+ for (open, close) in differing_pairs() {
467+ let doc = Rope::from(format!("word{}{}", open, close));
468+ let expected_doc = Rope::from(format!(
469+ "word{open}{open}{close}{close}",
470+ open = open,
471+ close = close
472+ ));
473+
474+ test_hooks(&doc, &sel, *open, &expected_doc, &expected_sel);
475+ }
476+ }
477+
478+ /// ([]) -> insert " -> ("[]")
479+ #[test]
480+ fn test_insert_nested_open_inside_pair() {
481+ let sel = Selection::single(2, 1);
482+ let expected_sel = Selection::single(3, 2);
483+
484+ for (outer_open, outer_close) in differing_pairs() {
485+ let doc = Rope::from(format!("{}{}", outer_open, outer_close,));
486+
487+ for (inner_open, inner_close) in matching_pairs() {
488+ let expected_doc = Rope::from(format!(
489+ "{}{}{}{}",
490+ outer_open, inner_open, inner_close, outer_close
491+ ));
492+
493+ test_hooks(&doc, &sel, *inner_open, &expected_doc, &expected_sel);
494+ }
495+ }
496+ }
497+
498+ /// [(]) -> append " -> [("]")
499+ #[test]
500+ fn test_append_nested_open_inside_pair() {
501+ let sel = Selection::single(0, 2);
502+ let expected_sel = Selection::single(0, 3);
503+
504+ for (outer_open, outer_close) in differing_pairs() {
505+ let doc = Rope::from(format!("{}{}", outer_open, outer_close,));
506+
507+ for (inner_open, inner_close) in matching_pairs() {
508+ let expected_doc = Rope::from(format!(
509+ "{}{}{}{}",
510+ outer_open, inner_open, inner_close, outer_close
511+ ));
512+
513+ test_hooks(&doc, &sel, *inner_open, &expected_doc, &expected_sel);
514+ }
515+ }
516+ }
517+
518+ /// []word -> insert ( -> ([]word
519+ #[test]
520+ fn test_insert_open_before_non_pair() {
521+ test_hooks_with_pairs(
522+ &Rope::from("word"),
523+ &Selection::single(1, 0),
524+ PAIRS,
525+ |open, _| format!("{}word", open),
526+ &Selection::single(2, 1),
527+ )
528+ }
529+
530+ /// [wor]d -> insert ( -> ([wor]d
531+ #[test]
532+ fn test_insert_open_with_selection() {
533+ test_hooks_with_pairs(
534+ &Rope::from("word"),
535+ &Selection::single(3, 0),
536+ PAIRS,
537+ |open, _| format!("{}word", open),
538+ &Selection::single(4, 1),
539+ )
540+ }
541+
542+ /// [wor]d -> append ) -> [wor)]d
543+ #[test]
544+ fn test_append_close_inside_non_pair_with_selection() {
545+ let sel = Selection::single(0, 4);
546+ let expected_sel = Selection::single(0, 5);
547+
548+ for (_, close) in PAIRS {
549+ let doc = Rope::from("word");
550+ let expected_doc = Rope::from(format!("wor{}d", close));
551+ test_hooks(&doc, &sel, *close, &expected_doc, &expected_sel);
552+ }
553+ }
554+
555+ /// foo[ wor]d -> insert ( -> foo([) wor]d
556+ #[test]
557+ fn test_insert_open_trailing_word_with_selection() {
558+ test_hooks_with_pairs(
559+ &Rope::from("foo word"),
560+ &Selection::single(7, 3),
561+ differing_pairs(),
562+ |open, close| format!("foo{}{} word", open, close),
563+ &Selection::single(9, 4),
564+ )
565+ }
566+
567+ /// we want pairs that are *not* the same char to be inserted after
568+ /// a non-pair char, for cases like functions, but for pairs that are
569+ /// the same char, we want to *not* insert a pair to handle cases like "I'm"
570+ ///
571+ /// word[] -> insert ( -> word([])
572+ /// word[] -> insert ' -> word'[]
573+ #[test]
574+ fn test_insert_open_after_non_pair() {
575+ let doc = Rope::from("word");
576+ let sel = Selection::single(5, 4);
577+ let expected_sel = Selection::single(6, 5);
578+
579+ test_hooks_with_pairs(
580+ &doc,
581+ &sel,
582+ differing_pairs(),
583+ |open, close| format!("word{}{}", open, close),
584+ &expected_sel,
585+ );
586+
587+ test_hooks_with_pairs(
588+ &doc,
589+ &sel,
590+ matching_pairs(),
591+ |open, _| format!("word{}", open),
592+ &expected_sel,
593+ );
594+ }
595+
596+ /// appending with only a cursor should stay a cursor
597+ ///
598+ /// [] -> append to end "foo -> "foo[]"
599+ #[test]
600+ fn test_append_single_cursor() {
601+ test_hooks_with_pairs(
602+ &Rope::from("\n"),
603+ &Selection::single(0, 1),
604+ PAIRS,
605+ |open, close| format!("{}{}\n", open, close),
606+ &Selection::single(1, 2),
607+ );
608+ }
609+}
helix-core/src/chars.rs+5−7
@@ -91,14 +91,12 @@ mod test {
91
91
92 #[test]
92 #[test]
93 fn test_categorize() {
93 fn test_categorize() {
94− #[cfg(not(feature = "unicode-lines"))]
94+ const EOL_TEST_CASE: &'static str = "\n\r\u{000B}\u{000C}\u{0085}\u{2028}\u{2029}";
95− const EOL_TEST_CASE: &str = "\n";
95+ const WORD_TEST_CASE: &'static str =
96− #[cfg(feature = "unicode-lines")]
96+ "_hello_world_あいうえおー12345678901234567890";
97− const EOL_TEST_CASE: &str = "\n\u{000B}\u{000C}\u{0085}\u{2028}\u{2029}";
97+ const PUNCTUATION_TEST_CASE: &'static str =
98− const WORD_TEST_CASE: &str = "_hello_world_あいうえおー12345678901234567890";
99− const PUNCTUATION_TEST_CASE: &str =
100 "!\"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~!”#$%&’()*+、。:;<=>?@「」^`{|}~";
98 "!\"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~!”#$%&’()*+、。:;<=>?@「」^`{|}~";
101− const WHITESPACE_TEST_CASE: &str = "      ";
99+ const WHITESPACE_TEST_CASE: &'static str = "      ";
102
100
103 for ch in EOL_TEST_CASE.chars() {
101 for ch in EOL_TEST_CASE.chars() {
104 assert_eq!(CharCategory::Eol, categorize_char(ch));
102 assert_eq!(CharCategory::Eol, categorize_char(ch));
helix-core/src/comment.rs+26−35
@@ -45,7 +45,7 @@ fn find_line_comment(
45
45
46 // determine margin of 0 or 1 for uncommenting; if any comment token is not followed by a space,
46 // determine margin of 0 or 1 for uncommenting; if any comment token is not followed by a space,
47 // a margin of 0 is used for all lines.
47 // a margin of 0 is used for all lines.
48− if !matches!(line_slice.get_char(pos + token_len), Some(c) if c == ' ') {
48+ if matches!(line_slice.get_char(pos + token_len), Some(c) if c != ' ') {
49 margin = 0;
49 margin = 0;
50 }
50 }
51
51
@@ -68,11 +68,11 @@ pub fn toggle_line_comments(doc: &Rope, selection: &Selection, token: Option<&st
68 let mut min_next_line = 0;
68 let mut min_next_line = 0;
69 for selection in selection {
69 for selection in selection {
70 let (start, end) = selection.line_range(text);
70 let (start, end) = selection.line_range(text);
71− let start = start.clamp(min_next_line, text.len_lines());
71+ let start = start.max(min_next_line).min(text.len_lines());
72 let end = (end + 1).min(text.len_lines());
72 let end = (end + 1).min(text.len_lines());
73
73
74 lines.extend(start..end);
74 lines.extend(start..end);
75− min_next_line = end;
75+ min_next_line = end + 1;
76 }
76 }
77
77
78 let (commented, to_change, min, margin) = find_line_comment(token, text, lines);
78 let (commented, to_change, min, margin) = find_line_comment(token, text, lines);
@@ -100,52 +100,43 @@ mod test {
100
100
101 #[test]
101 #[test]
102 fn test_find_line_comment() {
102 fn test_find_line_comment() {
103+ use crate::State;
104+
103 // four lines, two space indented, except for line 1 which is blank.
105 // four lines, two space indented, except for line 1 which is blank.
104− let mut doc = Rope::from(" 1\n\n 2\n 3");
106+ let doc = Rope::from(" 1\n\n 2\n 3");
107+
108+ let mut state = State::new(doc);
105 // select whole document
109 // select whole document
106− let mut selection = Selection::single(0, doc.len_chars() - 1);
110+ state.selection = Selection::single(0, state.doc.len_chars() - 1);
107
111
108− let text = doc.slice(..);
112+ let text = state.doc.slice(..);
109
113
110 let res = find_line_comment("//", text, 0..3);
114 let res = find_line_comment("//", text, 0..3);
111− // (commented = true, to_change = [line 0, line 2], min = col 2, margin = 0)
115+ // (commented = true, to_change = [line 0, line 2], min = col 2, margin = 1)
112− assert_eq!(res, (false, vec![0, 2], 2, 0));
116+ assert_eq!(res, (false, vec![0, 2], 2, 1));
113
117
114 // comment
118 // comment
115− let transaction = toggle_line_comments(&doc, &selection, None);
119+ let transaction = toggle_line_comments(&state.doc, &state.selection, None);
116− transaction.apply(&mut doc);
120+ transaction.apply(&mut state.doc);
117− selection = selection.map(transaction.changes());
121+ state.selection = state.selection.map(transaction.changes());
118
122
119− assert_eq!(doc, " // 1\n\n // 2\n // 3");
123+ assert_eq!(state.doc, " // 1\n\n // 2\n // 3");
120
124
121 // uncomment
125 // uncomment
122− let transaction = toggle_line_comments(&doc, &selection, None);
126+ let transaction = toggle_line_comments(&state.doc, &state.selection, None);
123− transaction.apply(&mut doc);
127+ transaction.apply(&mut state.doc);
124− selection = selection.map(transaction.changes());
128+ state.selection = state.selection.map(transaction.changes());
125− assert_eq!(doc, " 1\n\n 2\n 3");
129+ assert_eq!(state.doc, " 1\n\n 2\n 3");
126− assert!(selection.len() == 1); // to ignore the selection unused warning
127
130
128 // 0 margin comments
131 // 0 margin comments
129− doc = Rope::from(" //1\n\n //2\n //3");
132+ state.doc = Rope::from(" //1\n\n //2\n //3");
130− // reset the selection.
131− selection = Selection::single(0, doc.len_chars() - 1);
132−
133− let transaction = toggle_line_comments(&doc, &selection, None);
134− transaction.apply(&mut doc);
135− selection = selection.map(transaction.changes());
136− assert_eq!(doc, " 1\n\n 2\n 3");
137− assert!(selection.len() == 1); // to ignore the selection unused warning
138−
139− // 0 margin comments, with no space
140− doc = Rope::from("//");
141 // reset the selection.
133 // reset the selection.
142− selection = Selection::single(0, doc.len_chars() - 1);
134+ state.selection = Selection::single(0, state.doc.len_chars() - 1);
143
135
144− let transaction = toggle_line_comments(&doc, &selection, None);
136+ let transaction = toggle_line_comments(&state.doc, &state.selection, None);
145− transaction.apply(&mut doc);
137+ transaction.apply(&mut state.doc);
146− selection = selection.map(transaction.changes());
138+ state.selection = state.selection.map(transaction.changes());
147− assert_eq!(doc, "");
139+ assert_eq!(state.doc, " 1\n\n 2\n 3");
148− assert!(selection.len() == 1); // to ignore the selection unused warning
149
140
150 // TODO: account for uncommenting with uneven comment indentation
141 // TODO: account for uncommenting with uneven comment indentation
151 }
142 }
helix-core/src/config.rsdeleted−10
@@ -1,10 +0,0 @@
1−/// Syntax configuration loader based on built-in languages.toml.
2−pub fn default_syntax_loader() -> crate::syntax::Configuration {
3− helix_loader::config::default_lang_config()
4− .try_into()
5− .expect("Could not serialize built-in languages.toml")
6−}
7−/// Syntax configuration loader based on user configured languages.toml.
8−pub fn user_syntax_loader() -> Result<crate::syntax::Configuration, toml::de::Error> {
9− helix_loader::config::user_lang_config()?.try_into()
10−}
helix-core/src/diagnostic.rs+1−22
@@ -23,32 +23,11 @@ pub struct Range {
23 pub end: usize,
23 pub end: usize,
24}
24}
25
25
26−#[derive(Debug, Eq, Hash, PartialEq, Clone, Deserialize, Serialize)]
26+/// Corresponds to [`lsp_types::Diagnostic`](https://docs.rs/lsp-types/0.91.0/lsp_types/struct.Diagnostic.html)
27−pub enum NumberOrString {
28− Number(i32),
29− String(String),
30−}
31−
32−#[derive(Debug, Clone)]
33−pub enum DiagnosticTag {
34− Unnecessary,
35− Deprecated,
36−}
37−
38−/// Corresponds to [`lsp_types::Diagnostic`](https://docs.rs/lsp-types/0.94.0/lsp_types/struct.Diagnostic.html)
39#[derive(Debug, Clone)]
27#[derive(Debug, Clone)]
40pub struct Diagnostic {
28pub struct Diagnostic {
41 pub range: Range,
29 pub range: Range,
42− // whether this diagnostic ends at the end of(or inside) a word
43− pub ends_at_word: bool,
44− pub starts_at_word: bool,
45− pub zero_width: bool,
46 pub line: usize,
30 pub line: usize,
47 pub message: String,
31 pub message: String,
48 pub severity: Option<Severity>,
32 pub severity: Option<Severity>,
49− pub code: Option<NumberOrString>,
50− pub language_server_id: usize,
51− pub tags: Vec<DiagnosticTag>,
52− pub source: Option<String>,
53− pub data: Option<serde_json::Value>,
54}
33}
helix-core/src/diff.rs+50−203
@@ -1,221 +1,68 @@
1−use std::ops::Range;
1+use crate::{Rope, Transaction};
2−use std::time::Instant;
3
2
4−use imara_diff::intern::InternedInput;
3+/// Compares `old` and `new` to generate a [`Transaction`] describing
5−use imara_diff::Algorithm;
4+/// the steps required to get from `old` to `new`.
6−use ropey::RopeSlice;
5+pub fn compare_ropes(old: &Rope, new: &Rope) -> Transaction {
7−
6+ // `similar` only works on contiguous data, so a `Rope` has
8−use crate::{ChangeSet, Rope, Tendril, Transaction};
7+ // to be temporarily converted into a `String`.
9−
8+ let old_converted = old.to_string();
10−/// A `imara_diff::Sink` that builds a `ChangeSet` for a character diff of a hunk
9+ let new_converted = new.to_string();
11−struct CharChangeSetBuilder<'a> {
10+
12− res: &'a mut ChangeSet,
11+ // A timeout is set so after 1 seconds, the algorithm will start
13− hunk: &'a InternedInput<char>,
12+ // approximating. This is especially important for big `Rope`s or
14− pos: u32,
13+ // `Rope`s that are extremely dissimilar to each other.
15−}
14+ //
16−
15+ // Note: Ignore the clippy warning, as the trait bounds of
17−impl imara_diff::Sink for CharChangeSetBuilder<'_> {
16+ // `Transaction::change()` require an iterator implementing
18− type Out = ();
17+ // `ExactIterator`.
19− fn process_change(&mut self, before: Range<u32>, after: Range<u32>) {
18+ let mut config = similar::TextDiff::configure();
20− self.res.retain((before.start - self.pos) as usize);
19+ config.timeout(std::time::Duration::from_secs(1));
21− self.res.delete(before.len());
20+
22− self.pos = before.end;
21+ let diff = config.diff_chars(&old_converted, &new_converted);
23−
22+
24− let res = self.hunk.after[after.start as usize..after.end as usize]
23+ // The current position of the change needs to be tracked to
25− .iter()
24+ // construct the `Change`s.
26− .map(|&token| self.hunk.interner[token])
25+ let mut pos = 0;
27− .collect();
26+ Transaction::change(
28−
27+ old,
29− self.res.insert(res);
28+ diff.ops()
30− }
31−
32− fn finish(self) -> Self::Out {
33− self.res.retain(self.hunk.before.len() - self.pos as usize);
34− }
35−}
36−
37−struct LineChangeSetBuilder<'a> {
38− res: ChangeSet,
39− after: RopeSlice<'a>,
40− file: &'a InternedInput<RopeSlice<'a>>,
41− current_hunk: InternedInput<char>,
42− pos: u32,
43−}
44−
45−impl imara_diff::Sink for LineChangeSetBuilder<'_> {
46− type Out = ChangeSet;
47−
48− fn process_change(&mut self, before: Range<u32>, after: Range<u32>) {
49− let len = self.file.before[self.pos as usize..before.start as usize]
50 .iter()
29 .iter()
51− .map(|&it| self.file.interner[it].len_chars())
30+ .map(|op| op.as_tag_tuple())
52− .sum();
31+ .filter_map(|(tag, old_range, new_range)| {
53− self.res.retain(len);
32+ // `old_pos..pos` is equivalent to `start..end` for where
54− self.pos = before.end;
33+ // the change should be applied.
55−
34+ let old_pos = pos;
56− // do not perform diffs on large hunks
35+ pos += old_range.end - old_range.start;
57− let len_before = before.end - before.start;
36+
58− let len_after = after.end - after.start;
37+ match tag {
59−
38+ // Semantically, inserts and replacements are the same thing.
60− // Pure insertions/removals do not require a character diff.
39+ similar::DiffTag::Insert | similar::DiffTag::Replace => {
61− // Very large changes are ignored because their character diff is expensive to compute
40+ // This is the text from the `new` rope that should be
62− // TODO adjust heuristic to detect large changes?
41+ // inserted into `old`.
63− if len_before == 0
42+ let text: &str = {
64− || len_after == 0
43+ let start = new.char_to_byte(new_range.start);
65− || len_after > 5 * len_before
44+ let end = new.char_to_byte(new_range.end);
66− || 5 * len_after < len_before && len_before > 10
45+ &new_converted[start..end]
67− || len_before + len_after > 200
46+ };
68− {
47+ Some((old_pos, pos, Some(text.into())))
69− let remove = self.file.before[before.start as usize..before.end as usize]
70− .iter()
71− .map(|&it| self.file.interner[it].len_chars())
72− .sum();
73− self.res.delete(remove);
74− let mut fragment = Tendril::new();
75− if len_after > 500 {
76− // copying a rope line by line is slower then copying the entire
77− // rope. Use to_string for very large changes instead..
78− if self.file.after.len() == after.end as usize {
79− if after.start == 0 {
80− fragment = self.after.to_string().into();
81− } else {
82− let start = self.after.line_to_char(after.start as usize);
83− fragment = self.after.slice(start..).to_string().into();
84 }
48 }
85− } else if after.start == 0 {
49+ similar::DiffTag::Delete => Some((old_pos, pos, None)),
86− let end = self.after.line_to_char(after.end as usize);
50+ similar::DiffTag::Equal => None,
87− fragment = self.after.slice(..end).to_string().into();
88− } else {
89− let start = self.after.line_to_char(after.start as usize);
90− let end = self.after.line_to_char(after.end as usize);
91− fragment = self.after.slice(start..end).to_string().into();
92 }
51 }
93− } else {
52+ }),
94− for &line in &self.file.after[after.start as usize..after.end as usize] {
53+ )
95− for chunk in self.file.interner[line].chunks() {
96− fragment.push_str(chunk)
97− }
98− }
99− };
100− self.res.insert(fragment);
101− } else {
102− // for reasonably small hunks, generating a ChangeSet from char diff can save memory
103− // TODO use a tokenizer (word diff?) for improved performance
104− let hunk_before = self.file.before[before.start as usize..before.end as usize]
105− .iter()
106− .flat_map(|&it| self.file.interner[it].chars());
107− let hunk_after = self.file.after[after.start as usize..after.end as usize]
108− .iter()
109− .flat_map(|&it| self.file.interner[it].chars());
110− self.current_hunk.update_before(hunk_before);
111− self.current_hunk.update_after(hunk_after);
112−
113− // the histogram heuristic does not work as well
114− // for characters because the same characters often reoccur
115− // use myer diff instead
116− imara_diff::diff(
117− Algorithm::Myers,
118− &self.current_hunk,
119− CharChangeSetBuilder {
120− res: &mut self.res,
121− hunk: &self.current_hunk,
122− pos: 0,
123− },
124− );
125−
126− self.current_hunk.clear();
127− }
128− }
129−
130− fn finish(mut self) -> Self::Out {
131− let len = self.file.before[self.pos as usize..]
132− .iter()
133− .map(|&it| self.file.interner[it].len_chars())
134− .sum();
135−
136− self.res.retain(len);
137− self.res
138− }
139−}
140−
141−struct RopeLines<'a>(RopeSlice<'a>);
142−
143−impl<'a> imara_diff::intern::TokenSource for RopeLines<'a> {
144− type Token = RopeSlice<'a>;
145− type Tokenizer = ropey::iter::Lines<'a>;
146−
147− fn tokenize(&self) -> Self::Tokenizer {
148− self.0.lines()
149− }
150−
151− fn estimate_tokens(&self) -> u32 {
152− // we can provide a perfect estimate which is very nice for performance
153− self.0.len_lines() as u32
154− }
155−}
156−
157−/// Compares `old` and `new` to generate a [`Transaction`] describing
158−/// the steps required to get from `old` to `new`.
159−pub fn compare_ropes(before: &Rope, after: &Rope) -> Transaction {
160− let start = Instant::now();
161− let res = ChangeSet::with_capacity(32);
162− let after = after.slice(..);
163− let file = InternedInput::new(RopeLines(before.slice(..)), RopeLines(after));
164− let builder = LineChangeSetBuilder {
165− res,
166− file: &file,
167− after,
168− pos: 0,
169− current_hunk: InternedInput::default(),
170− };
171−
172− let res = imara_diff::diff(Algorithm::Histogram, &file, builder).into();
173−
174− log::debug!(
175− "rope diff took {}s",
176− Instant::now().duration_since(start).as_secs_f64()
177− );
178− res
179}
54}
180
55
181#[cfg(test)]
56#[cfg(test)]
182mod tests {
57mod tests {
183 use super::*;
58 use super::*;
184
59
185− fn test_identity(a: &str, b: &str) {
186− let mut old = Rope::from(a);
187− let new = Rope::from(b);
188− compare_ropes(&old, &new).apply(&mut old);
189− assert_eq!(old, new);
190− }
191−
192 quickcheck::quickcheck! {
60 quickcheck::quickcheck! {
193 fn test_compare_ropes(a: String, b: String) -> bool {
61 fn test_compare_ropes(a: String, b: String) -> bool {
194 let mut old = Rope::from(a);
62 let mut old = Rope::from(a);
195 let new = Rope::from(b);
63 let new = Rope::from(b);
196 compare_ropes(&old, &new).apply(&mut old);
64 compare_ropes(&old, &new).apply(&mut old);
197− old == new
65+ old.to_string() == new.to_string()
198 }
66 }
199 }
67 }
200−
201− #[test]
202− fn equal_files() {
203− test_identity("foo", "foo");
204− }
205−
206− #[test]
207− fn trailing_newline() {
208− test_identity("foo\n", "foo");
209− test_identity("foo", "foo\n");
210− }
211−
212− #[test]
213− fn new_file() {
214− test_identity("", "foo");
215− }
216−
217− #[test]
218− fn deleted_file() {
219− test_identity("foo", "");
220− }
221}
68}
helix-core/src/doc_formatter.rsdeleted−384
@@ -1,384 +0,0 @@
1−//! The `DocumentFormatter` forms the bridge between the raw document text
2−//! and onscreen positioning. It yields the text graphemes as an iterator
3−//! and traverses (part) of the document text. During that traversal it
4−//! handles grapheme detection, softwrapping and annotations.
5−//! It yields `FormattedGrapheme`s and their corresponding visual coordinates.
6−//!
7−//! As both virtual text and softwrapping can insert additional lines into the document
8−//! it is generally not possible to find the start of the previous visual line.
9−//! Instead the `DocumentFormatter` starts at the last "checkpoint" (usually a linebreak)
10−//! called a "block" and the caller must advance it as needed.
11−
12−use std::borrow::Cow;
13−use std::fmt::Debug;
14−use std::mem::{replace, take};
15−
16−#[cfg(test)]
17−mod test;
18−
19−use unicode_segmentation::{Graphemes, UnicodeSegmentation};
20−
21−use crate::graphemes::{Grapheme, GraphemeStr};
22−use crate::syntax::Highlight;
23−use crate::text_annotations::TextAnnotations;
24−use crate::{Position, RopeGraphemes, RopeSlice};
25−
26−/// TODO make Highlight a u32 to reduce the size of this enum to a single word.
27−#[derive(Debug, Clone, Copy)]
28−pub enum GraphemeSource {
29− Document {
30− codepoints: u32,
31− },
32− /// Inline virtual text can not be highlighted with a `Highlight` iterator
33− /// because it's not part of the document. Instead the `Highlight`
34− /// is emitted right by the document formatter
35− VirtualText {
36− highlight: Option<Highlight>,
37− },
38−}
39−
40−#[derive(Debug, Clone)]
41−pub struct FormattedGrapheme<'a> {
42− pub grapheme: Grapheme<'a>,
43− pub source: GraphemeSource,
44−}
45−
46−impl<'a> FormattedGrapheme<'a> {
47− pub fn new(
48− g: GraphemeStr<'a>,
49− visual_x: usize,
50− tab_width: u16,
51− source: GraphemeSource,
52− ) -> FormattedGrapheme<'a> {
53− FormattedGrapheme {
54− grapheme: Grapheme::new(g, visual_x, tab_width),
55− source,
56− }
57− }
58− /// Returns whether this grapheme is virtual inline text
59− pub fn is_virtual(&self) -> bool {
60− matches!(self.source, GraphemeSource::VirtualText { .. })
61− }
62−
63− pub fn placeholder() -> Self {
64− FormattedGrapheme {
65− grapheme: Grapheme::Other { g: " ".into() },
66− source: GraphemeSource::Document { codepoints: 0 },
67− }
68− }
69−
70− pub fn doc_chars(&self) -> usize {
71− match self.source {
72− GraphemeSource::Document { codepoints } => codepoints as usize,
73− GraphemeSource::VirtualText { .. } => 0,
74− }
75− }
76−
77− pub fn is_whitespace(&self) -> bool {
78− self.grapheme.is_whitespace()
79− }
80−
81− pub fn width(&self) -> usize {
82− self.grapheme.width()
83− }
84−
85− pub fn is_word_boundary(&self) -> bool {
86− self.grapheme.is_word_boundary()
87− }
88−}
89−
90−#[derive(Debug, Clone)]
91−pub struct TextFormat {
92− pub soft_wrap: bool,
93− pub tab_width: u16,
94− pub max_wrap: u16,
95− pub max_indent_retain: u16,
96− pub wrap_indicator: Box<str>,
97− pub wrap_indicator_highlight: Option<Highlight>,
98− pub viewport_width: u16,
99−}
100−
101−// test implementation is basically only used for testing or when softwrap is always disabled
102−impl Default for TextFormat {
103− fn default() -> Self {
104− TextFormat {
105− soft_wrap: false,
106− tab_width: 4,
107− max_wrap: 3,
108− max_indent_retain: 4,
109− wrap_indicator: Box::from(" "),
110− viewport_width: 17,
111− wrap_indicator_highlight: None,
112− }
113− }
114−}
115−
116−#[derive(Debug)]
117−pub struct DocumentFormatter<'t> {
118− text_fmt: &'t TextFormat,
119− annotations: &'t TextAnnotations,
120−
121− /// The visual position at the end of the last yielded word boundary
122− visual_pos: Position,
123− graphemes: RopeGraphemes<'t>,
124− /// The character pos of the `graphemes` iter used for inserting annotations
125− char_pos: usize,
126− /// The line pos of the `graphemes` iter used for inserting annotations
127− line_pos: usize,
128− exhausted: bool,
129−
130− /// Line breaks to be reserved for virtual text
131− /// at the next line break
132− virtual_lines: usize,
133− inline_anntoation_graphemes: Option<(Graphemes<'t>, Option<Highlight>)>,
134−
135− // softwrap specific
136− /// The indentation of the current line
137− /// Is set to `None` if the indentation level is not yet known
138− /// because no non-whitespace graphemes have been encountered yet
139− indent_level: Option<usize>,
140− /// In case a long word needs to be split a single grapheme might need to be wrapped
141− /// while the rest of the word stays on the same line
142− peeked_grapheme: Option<(FormattedGrapheme<'t>, usize)>,
143− /// A first-in first-out (fifo) buffer for the Graphemes of any given word
144− word_buf: Vec<FormattedGrapheme<'t>>,
145− /// The index of the next grapheme that will be yielded from the `word_buf`
146− word_i: usize,
147−}
148−
149−impl<'t> DocumentFormatter<'t> {
150− /// Creates a new formatter at the last block before `char_idx`.
151− /// A block is a chunk which always ends with a linebreak.
152− /// This is usually just a normal line break.
153− /// However very long lines are always wrapped at constant intervals that can be cheaply calculated
154− /// to avoid pathological behaviour.
155− pub fn new_at_prev_checkpoint(
156− text: RopeSlice<'t>,
157− text_fmt: &'t TextFormat,
158− annotations: &'t TextAnnotations,
159− char_idx: usize,
160− ) -> (Self, usize) {
161− // TODO divide long lines into blocks to avoid bad performance for long lines
162− let block_line_idx = text.char_to_line(char_idx.min(text.len_chars()));
163− let block_char_idx = text.line_to_char(block_line_idx);
164− annotations.reset_pos(block_char_idx);
165− (
166− DocumentFormatter {
167− text_fmt,
168− annotations,
169− visual_pos: Position { row: 0, col: 0 },
170− graphemes: RopeGraphemes::new(text.slice(block_char_idx..)),
171− char_pos: block_char_idx,
172− exhausted: false,
173− virtual_lines: 0,
174− indent_level: None,
175− peeked_grapheme: None,
176− word_buf: Vec::with_capacity(64),
177− word_i: 0,
178− line_pos: block_line_idx,
179− inline_anntoation_graphemes: None,
180− },
181− block_char_idx,
182− )
183− }
184−
185− fn next_inline_annotation_grapheme(&mut self) -> Option<(&'t str, Option<Highlight>)> {
186− loop {
187− if let Some(&mut (ref mut annotation, highlight)) =
188− self.inline_anntoation_graphemes.as_mut()
189− {
190− if let Some(grapheme) = annotation.next() {
191− return Some((grapheme, highlight));
192− }
193− }
194−
195− if let Some((annotation, highlight)) =
196− self.annotations.next_inline_annotation_at(self.char_pos)
197− {
198− self.inline_anntoation_graphemes = Some((
199− UnicodeSegmentation::graphemes(&*annotation.text, true),
200− highlight,
201− ))
202− } else {
203− return None;
204− }
205− }
206− }
207−
208− fn advance_grapheme(&mut self, col: usize) -> Option<FormattedGrapheme<'t>> {
209− let (grapheme, source) =
210− if let Some((grapheme, highlight)) = self.next_inline_annotation_grapheme() {
211− (grapheme.into(), GraphemeSource::VirtualText { highlight })
212− } else if let Some(grapheme) = self.graphemes.next() {
213− self.virtual_lines += self.annotations.annotation_lines_at(self.char_pos);
214− let codepoints = grapheme.len_chars() as u32;
215−
216− let overlay = self.annotations.overlay_at(self.char_pos);
217− let grapheme = match overlay {
218− Some((overlay, _)) => overlay.grapheme.as_str().into(),
219− None => Cow::from(grapheme).into(),
220− };
221−
222− self.char_pos += codepoints as usize;
223− (grapheme, GraphemeSource::Document { codepoints })
224− } else {
225− if self.exhausted {
226− return None;
227− }
228− self.exhausted = true;
229− // EOF grapheme is required for rendering
230− // and correct position computations
231− return Some(FormattedGrapheme {
232− grapheme: Grapheme::Other { g: " ".into() },
233− source: GraphemeSource::Document { codepoints: 0 },
234− });
235− };
236−
237− let grapheme = FormattedGrapheme::new(grapheme, col, self.text_fmt.tab_width, source);
238−
239− Some(grapheme)
240− }
241−
242− /// Move a word to the next visual line
243− fn wrap_word(&mut self, virtual_lines_before_word: usize) -> usize {
244− // softwrap this word to the next line
245− let indent_carry_over = if let Some(indent) = self.indent_level {
246− if indent as u16 <= self.text_fmt.max_indent_retain {
247− indent as u16
248− } else {
249− 0
250− }
251− } else {
252− // ensure the indent stays 0
253− self.indent_level = Some(0);
254− 0
255− };
256−
257− self.visual_pos.col = indent_carry_over as usize;
258− self.virtual_lines -= virtual_lines_before_word;
259− self.visual_pos.row += 1 + virtual_lines_before_word;
260− let mut i = 0;
261− let mut word_width = 0;
262− let wrap_indicator = UnicodeSegmentation::graphemes(&*self.text_fmt.wrap_indicator, true)
263− .map(|g| {
264− i += 1;
265− let grapheme = FormattedGrapheme::new(
266− g.into(),
267− self.visual_pos.col + word_width,
268− self.text_fmt.tab_width,
269− GraphemeSource::VirtualText {
270− highlight: self.text_fmt.wrap_indicator_highlight,
271− },
272− );
273− word_width += grapheme.width();
274− grapheme
275− });
276− self.word_buf.splice(0..0, wrap_indicator);
277−
278− for grapheme in &mut self.word_buf[i..] {
279− let visual_x = self.visual_pos.col + word_width;
280− grapheme
281− .grapheme
282− .change_position(visual_x, self.text_fmt.tab_width);
283− word_width += grapheme.width();
284− }
285− word_width
286− }
287−
288− fn advance_to_next_word(&mut self) {
289− self.word_buf.clear();
290− let mut word_width = 0;
291− let virtual_lines_before_word = self.virtual_lines;
292− let mut virtual_lines_before_grapheme = self.virtual_lines;
293−
294− loop {
295− // softwrap word if necessary
296− if word_width + self.visual_pos.col >= self.text_fmt.viewport_width as usize {
297− // wrapping this word would move too much text to the next line
298− // split the word at the line end instead
299− if word_width > self.text_fmt.max_wrap as usize {
300− // Usually we stop accomulating graphemes as soon as softwrapping becomes necessary.
301− // However if the last grapheme is multiple columns wide it might extend beyond the EOL.
302− // The condition below ensures that this grapheme is not cutoff and instead wrapped to the next line
303− if word_width + self.visual_pos.col > self.text_fmt.viewport_width as usize {
304− self.peeked_grapheme = self.word_buf.pop().map(|grapheme| {
305− (grapheme, self.virtual_lines - virtual_lines_before_grapheme)
306− });
307− self.virtual_lines = virtual_lines_before_grapheme;
308− }
309− return;
310− }
311−
312− word_width = self.wrap_word(virtual_lines_before_word);
313− }
314−
315− virtual_lines_before_grapheme = self.virtual_lines;
316−
317− let grapheme = if let Some((grapheme, virtual_lines)) = self.peeked_grapheme.take() {
318− self.virtual_lines += virtual_lines;
319− grapheme
320− } else if let Some(grapheme) = self.advance_grapheme(self.visual_pos.col + word_width) {
321− grapheme
322− } else {
323− return;
324− };
325−
326− // Track indentation
327− if !grapheme.is_whitespace() && self.indent_level.is_none() {
328− self.indent_level = Some(self.visual_pos.col);
329− } else if grapheme.grapheme == Grapheme::Newline {
330− self.indent_level = None;
331− }
332−
333− let is_word_boundary = grapheme.is_word_boundary();
334− word_width += grapheme.width();
335− self.word_buf.push(grapheme);
336−
337− if is_word_boundary {
338− return;
339− }
340− }
341− }
342−
343− /// returns the document line pos of the **next** grapheme that will be yielded
344− pub fn line_pos(&self) -> usize {
345− self.line_pos
346− }
347−
348− /// returns the visual pos of the **next** grapheme that will be yielded
349− pub fn visual_pos(&self) -> Position {
350− self.visual_pos
351− }
352−}
353−
354−impl<'t> Iterator for DocumentFormatter<'t> {
355− type Item = (FormattedGrapheme<'t>, Position);
356−
357− fn next(&mut self) -> Option<Self::Item> {
358− let grapheme = if self.text_fmt.soft_wrap {
359− if self.word_i >= self.word_buf.len() {
360− self.advance_to_next_word();
361− self.word_i = 0;
362− }
363− let grapheme = replace(
364− self.word_buf.get_mut(self.word_i)?,
365− FormattedGrapheme::placeholder(),
366− );
367− self.word_i += 1;
368− grapheme
369− } else {
370− self.advance_grapheme(self.visual_pos.col)?
371− };
372−
373− let pos = self.visual_pos;
374− if grapheme.grapheme == Grapheme::Newline {
375− self.visual_pos.row += 1;
376− self.visual_pos.row += take(&mut self.virtual_lines);
377− self.visual_pos.col = 0;
378− self.line_pos += 1;
379− } else {
380− self.visual_pos.col += grapheme.width();
381− }
382− Some((grapheme, pos))
383− }
384−}
helix-core/src/doc_formatter/test.rsdeleted−182
@@ -1,182 +0,0 @@
1−use std::rc::Rc;
2−
3−use crate::doc_formatter::{DocumentFormatter, TextFormat};
4−use crate::text_annotations::{InlineAnnotation, Overlay, TextAnnotations};
5−
6−impl TextFormat {
7− fn new_test(softwrap: bool) -> Self {
8− TextFormat {
9− soft_wrap: softwrap,
10− tab_width: 2,
11− max_wrap: 3,
12− max_indent_retain: 4,
13− wrap_indicator: ".".into(),
14− wrap_indicator_highlight: None,
15− // use a prime number to allow lining up too often with repeat
16− viewport_width: 17,
17− }
18− }
19−}
20−
21−impl<'t> DocumentFormatter<'t> {
22− fn collect_to_str(&mut self) -> String {
23− use std::fmt::Write;
24− let mut res = String::new();
25− let viewport_width = self.text_fmt.viewport_width;
26− let mut line = 0;
27−
28− for (grapheme, pos) in self {
29− if pos.row != line {
30− line += 1;
31− assert_eq!(pos.row, line);
32− write!(res, "\n{}", ".".repeat(pos.col)).unwrap();
33− assert!(
34− pos.col <= viewport_width as usize,
35− "softwrapped failed {}<={viewport_width}",
36− pos.col
37− );
38− }
39− write!(res, "{}", grapheme.grapheme).unwrap();
40− }
41−
42− res
43− }
44−}
45−
46−fn softwrap_text(text: &str) -> String {
47− DocumentFormatter::new_at_prev_checkpoint(
48− text.into(),
49− &TextFormat::new_test(true),
50− &TextAnnotations::default(),
51− 0,
52− )
53− .0
54− .collect_to_str()
55−}
56−
57−#[test]
58−fn basic_softwrap() {
59− assert_eq!(
60− softwrap_text(&"foo ".repeat(10)),
61− "foo foo foo foo \n.foo foo foo foo \n.foo foo "
62− );
63− assert_eq!(
64− softwrap_text(&"fooo ".repeat(10)),
65− "fooo fooo fooo \n.fooo fooo fooo \n.fooo fooo fooo \n.fooo "
66− );
67−
68− // check that we don't wrap unnecessarily
69− assert_eq!(softwrap_text("\t\txxxx1xxxx2xx\n"), " xxxx1xxxx2xx \n ");
70−}
71−
72−#[test]
73−fn softwrap_indentation() {
74− assert_eq!(
75− softwrap_text("\t\tfoo1 foo2 foo3 foo4 foo5 foo6\n"),
76− " foo1 foo2 \n.....foo3 foo4 \n.....foo5 foo6 \n "
77− );
78− assert_eq!(
79− softwrap_text("\t\t\tfoo1 foo2 foo3 foo4 foo5 foo6\n"),
80− " foo1 foo2 \n.foo3 foo4 foo5 \n.foo6 \n "
81− );
82−}
83−
84−#[test]
85−fn long_word_softwrap() {
86− assert_eq!(
87− softwrap_text("\t\txxxx1xxxx2xxxx3xxxx4xxxx5xxxx6xxxx7xxxx8xxxx9xxx\n"),
88− " xxxx1xxxx2xxx\n.....x3xxxx4xxxx5\n.....xxxx6xxxx7xx\n.....xx8xxxx9xxx \n "
89− );
90− assert_eq!(
91− softwrap_text("xxxxxxxx1xxxx2xxx\n"),
92− "xxxxxxxx1xxxx2xxx\n. \n "
93− );
94− assert_eq!(
95− softwrap_text("\t\txxxx1xxxx 2xxxx3xxxx4xxxx5xxxx6xxxx7xxxx8xxxx9xxx\n"),
96− " xxxx1xxxx \n.....2xxxx3xxxx4x\n.....xxx5xxxx6xxx\n.....x7xxxx8xxxx9\n.....xxx \n "
97− );
98− assert_eq!(
99− softwrap_text("\t\txxxx1xxx 2xxxx3xxxx4xxxx5xxxx6xxxx7xxxx8xxxx9xxx\n"),
100− " xxxx1xxx 2xxx\n.....x3xxxx4xxxx5\n.....xxxx6xxxx7xx\n.....xx8xxxx9xxx \n "
101− );
102−}
103−
104−fn overlay_text(text: &str, char_pos: usize, softwrap: bool, overlays: &[Overlay]) -> String {
105− DocumentFormatter::new_at_prev_checkpoint(
106− text.into(),
107− &TextFormat::new_test(softwrap),
108− TextAnnotations::default().add_overlay(overlays.into(), None),
109− char_pos,
110− )
111− .0
112− .collect_to_str()
113−}
114−
115−#[test]
116−fn overlay() {
117− assert_eq!(
118− overlay_text(
119− "foobar",
120− 0,
121− false,
122− &[Overlay::new(0, "X"), Overlay::new(2, "\t")],
123− ),
124− "Xo bar "
125− );
126− assert_eq!(
127− overlay_text(
128− &"foo ".repeat(10),
129− 0,
130− true,
131− &[
132− Overlay::new(2, "\t"),
133− Overlay::new(5, "\t"),
134− Overlay::new(16, "X"),
135− ]
136− ),
137− "fo f o foo \n.foo Xoo foo foo \n.foo foo foo "
138− );
139−}
140−
141−fn annotate_text(text: &str, softwrap: bool, annotations: &[InlineAnnotation]) -> String {
142− DocumentFormatter::new_at_prev_checkpoint(
143− text.into(),
144− &TextFormat::new_test(softwrap),
145− TextAnnotations::default().add_inline_annotations(annotations.into(), None),
146− 0,
147− )
148− .0
149− .collect_to_str()
150−}
151−
152−#[test]
153−fn annotation() {
154− assert_eq!(
155− annotate_text("bar", false, &[InlineAnnotation::new(0, "foo")]),
156− "foobar "
157− );
158− assert_eq!(
159− annotate_text(
160− &"foo ".repeat(10),
161− true,
162− &[InlineAnnotation::new(0, "foo ")]
163− ),
164− "foo foo foo foo \n.foo foo foo foo \n.foo foo foo "
165− );
166−}
167−#[test]
168−fn annotation_and_overlay() {
169− assert_eq!(
170− DocumentFormatter::new_at_prev_checkpoint(
171− "bbar".into(),
172− &TextFormat::new_test(false),
173− TextAnnotations::default()
174− .add_inline_annotations(Rc::new([InlineAnnotation::new(0, "fooo")]), None)
175− .add_overlay(Rc::new([Overlay::new(0, "\t")]), None),
176− 0,
177− )
178− .0
179− .collect_to_str(),
180− "fooo bar "
181− );
182−}
helix-core/src/fuzzy.rsdeleted−43
@@ -1,43 +0,0 @@
1−use std::ops::DerefMut;
2−
3−use nucleo::pattern::{Atom, AtomKind, CaseMatching};
4−use nucleo::Config;
5−use parking_lot::Mutex;
6−
7−pub struct LazyMutex<T> {
8− inner: Mutex<Option<T>>,
9− init: fn() -> T,
10−}
11−
12−impl<T> LazyMutex<T> {
13− pub const fn new(init: fn() -> T) -> Self {
14− Self {
15− inner: Mutex::new(None),
16− init,
17− }
18− }
19−
20− pub fn lock(&self) -> impl DerefMut<Target = T> + '_ {
21− parking_lot::MutexGuard::map(self.inner.lock(), |val| val.get_or_insert_with(self.init))
22− }
23−}
24−
25−pub static MATCHER: LazyMutex<nucleo::Matcher> = LazyMutex::new(nucleo::Matcher::default);
26−
27−/// convenience function to easily fuzzy match
28−/// on a (relatively small list of inputs). This is not recommended for building a full tui
29−/// application that can match large numbers of matches as all matching is done on the current
30−/// thread, effectively blocking the UI
31−pub fn fuzzy_match<T: AsRef<str>>(
32− pattern: &str,
33− items: impl IntoIterator<Item = T>,
34− path: bool,
35−) -> Vec<(T, u16)> {
36− let mut matcher = MATCHER.lock();
37− matcher.config = Config::DEFAULT;
38− if path {
39− matcher.config.set_match_paths();
40− }
41− let pattern = Atom::new(pattern, CaseMatching::Smart, AtomKind::Fuzzy, false);
42− pattern.match_list(items, &mut matcher)
43−}
helix-core/src/graphemes.rs+6−270
@@ -5,88 +5,7 @@ use ropey::{iter::Chunks, str_utils::byte_to_char_idx, RopeSlice};
5use unicode_segmentation::{GraphemeCursor, GraphemeIncomplete};
5use unicode_segmentation::{GraphemeCursor, GraphemeIncomplete};
6use unicode_width::UnicodeWidthStr;
6use unicode_width::UnicodeWidthStr;
7
7
8−use std::borrow::Cow;
8+use std::fmt;
9−use std::fmt::{self, Debug, Display};
10−use std::marker::PhantomData;
11−use std::ops::Deref;
12−use std::ptr::NonNull;
13−use std::{slice, str};
14−
15−use crate::chars::{char_is_whitespace, char_is_word};
16−use crate::LineEnding;
17−
18−#[inline]
19−pub fn tab_width_at(visual_x: usize, tab_width: u16) -> usize {
20− tab_width as usize - (visual_x % tab_width as usize)
21−}
22−
23−#[derive(Debug, Clone, PartialEq, Eq)]
24−pub enum Grapheme<'a> {
25− Newline,
26− Tab { width: usize },
27− Other { g: GraphemeStr<'a> },
28−}
29−
30−impl<'a> Grapheme<'a> {
31− pub fn new(g: GraphemeStr<'a>, visual_x: usize, tab_width: u16) -> Grapheme<'a> {
32− match g {
33− g if g == "\t" => Grapheme::Tab {
34− width: tab_width_at(visual_x, tab_width),
35− },
36− _ if LineEnding::from_str(&g).is_some() => Grapheme::Newline,
37− _ => Grapheme::Other { g },
38− }
39− }
40−
41− pub fn change_position(&mut self, visual_x: usize, tab_width: u16) {
42− if let Grapheme::Tab { width } = self {
43− *width = tab_width_at(visual_x, tab_width)
44− }
45− }
46−
47− /// Returns the a visual width of this grapheme,
48− #[inline]
49− pub fn width(&self) -> usize {
50− match *self {
51− // width is not cached because we are dealing with
52− // ASCII almost all the time which already has a fastpath
53− // it's okay to convert to u16 here because no codepoint has a width larger
54− // than 2 and graphemes are usually atmost two visible codepoints wide
55− Grapheme::Other { ref g } => grapheme_width(g),
56− Grapheme::Tab { width } => width,
57− Grapheme::Newline => 1,
58− }
59− }
60−
61− pub fn is_whitespace(&self) -> bool {
62− !matches!(&self, Grapheme::Other { g } if !g.chars().all(char_is_whitespace))
63− }
64−
65− // TODO currently word boundaries are used for softwrapping.
66− // This works best for programming languages and well for prose.
67− // This could however be improved in the future by considering unicode
68− // character classes but
69− pub fn is_word_boundary(&self) -> bool {
70− !matches!(&self, Grapheme::Other { g,.. } if g.chars().all(char_is_word))
71− }
72−}
73−
74−impl Display for Grapheme<'_> {
75− fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76− match *self {
77− Grapheme::Newline => write!(f, " "),
78− Grapheme::Tab { width } => {
79− for _ in 0..width {
80− write!(f, " ")?;
81− }
82− Ok(())
83− }
84− Grapheme::Other { ref g } => {
85− write!(f, "{g}")
86− }
87− }
88− }
89−}
90
9
91#[must_use]
10#[must_use]
92pub fn grapheme_width(g: &str) -> usize {
11pub fn grapheme_width(g: &str) -> usize {
@@ -95,7 +14,7 @@ pub fn grapheme_width(g: &str) -> usize {
95 // Point 1: theoretically, ascii control characters should have zero
14 // Point 1: theoretically, ascii control characters should have zero
96 // width, but in our case we actually want them to have width: if they
15 // width, but in our case we actually want them to have width: if they
97 // show up in text, we want to treat them as textual elements that can
16 // show up in text, we want to treat them as textual elements that can
98− // be edited. So we can get away with making all ascii single width
17+ // be editied. So we can get away with making all ascii single width
99 // here.
18 // here.
100 // Point 2: we're only examining the first codepoint here, which means
19 // Point 2: we're only examining the first codepoint here, which means
101 // we're ignoring graphemes formed with combining characters. However,
20 // we're ignoring graphemes formed with combining characters. However,
@@ -108,8 +27,6 @@ pub fn grapheme_width(g: &str) -> usize {
108 // We use max(1) here because all grapeheme clusters--even illformed
27 // We use max(1) here because all grapeheme clusters--even illformed
109 // ones--should have at least some width so they can be edited
28 // ones--should have at least some width so they can be edited
110 // properly.
29 // properly.
111− // TODO properly handle unicode width for all codepoints
112− // example of where unicode width is currently wrong: 🤦🏼‍♂️ (taken from https://hsivonen.fi/string-length/)
113 UnicodeWidthStr::width(g).max(1)
30 UnicodeWidthStr::width(g).max(1)
114 }
31 }
115}
32}
@@ -203,43 +120,6 @@ pub fn nth_next_grapheme_boundary(slice: RopeSlice, char_idx: usize, n: usize) -
203 chunk_char_idx + tmp
120 chunk_char_idx + tmp
204}
121}
205
122
206−#[must_use]
207−pub fn nth_next_grapheme_boundary_byte(slice: RopeSlice, mut byte_idx: usize, n: usize) -> usize {
208− // Bounds check
209− debug_assert!(byte_idx <= slice.len_bytes());
210−
211− // Get the chunk with our byte index in it.
212− let (mut chunk, mut chunk_byte_idx, mut _chunk_char_idx, _) = slice.chunk_at_byte(byte_idx);
213−
214− // Set up the grapheme cursor.
215− let mut gc = GraphemeCursor::new(byte_idx, slice.len_bytes(), true);
216−
217− // Find the nth next grapheme cluster boundary.
218− for _ in 0..n {
219− loop {
220− match gc.next_boundary(chunk, chunk_byte_idx) {
221− Ok(None) => return slice.len_bytes(),
222− Ok(Some(n)) => {
223− byte_idx = n;
224− break;
225− }
226− Err(GraphemeIncomplete::NextChunk) => {
227− chunk_byte_idx += chunk.len();
228− let (a, _, _c, _) = slice.chunk_at_byte(chunk_byte_idx);
229− chunk = a;
230− // chunk_char_idx = c;
231− }
232− Err(GraphemeIncomplete::PreContext(n)) => {
233− let ctx_chunk = slice.chunk_at_byte(n - 1).0;
234− gc.provide_context(ctx_chunk, n - ctx_chunk.len());
235− }
236− _ => unreachable!(),
237− }
238− }
239− }
240− byte_idx
241−}
242−
243/// Finds the next grapheme boundary after the given char position.
123/// Finds the next grapheme boundary after the given char position.
244#[must_use]
124#[must_use]
245#[inline(always)]
125#[inline(always)]
@@ -247,13 +127,6 @@ pub fn next_grapheme_boundary(slice: RopeSlice, char_idx: usize) -> usize {
247 nth_next_grapheme_boundary(slice, char_idx, 1)
127 nth_next_grapheme_boundary(slice, char_idx, 1)
248}
128}
249
129
250−/// Finds the next grapheme boundary after the given byte position.
251−#[must_use]
252−#[inline(always)]
253−pub fn next_grapheme_boundary_byte(slice: RopeSlice, byte_idx: usize) -> usize {
254− nth_next_grapheme_boundary_byte(slice, byte_idx, 1)
255−}
256−
257/// Returns the passed char index if it's already a grapheme boundary,
130/// Returns the passed char index if it's already a grapheme boundary,
258/// or the next grapheme boundary char index if not.
131/// or the next grapheme boundary char index if not.
259#[must_use]
132#[must_use]
@@ -278,23 +151,6 @@ pub fn ensure_grapheme_boundary_prev(slice: RopeSlice, char_idx: usize) -> usize
278 }
151 }
279}
152}
280
153
281−/// Returns the passed byte index if it's already a grapheme boundary,
282−/// or the next grapheme boundary byte index if not.
283−#[must_use]
284−#[inline]
285−pub fn ensure_grapheme_boundary_next_byte(slice: RopeSlice, byte_idx: usize) -> usize {
286− if byte_idx == 0 {
287− byte_idx
288− } else {
289− // TODO: optimize so we're not constructing grapheme cursor twice
290− if is_grapheme_boundary_byte(slice, byte_idx) {
291− byte_idx
292− } else {
293− next_grapheme_boundary_byte(slice, byte_idx)
294− }
295− }
296−}
297−
298/// Returns whether the given char position is a grapheme boundary.
154/// Returns whether the given char position is a grapheme boundary.
299#[must_use]
155#[must_use]
300pub fn is_grapheme_boundary(slice: RopeSlice, char_idx: usize) -> bool {
156pub fn is_grapheme_boundary(slice: RopeSlice, char_idx: usize) -> bool {
@@ -323,31 +179,6 @@ pub fn is_grapheme_boundary(slice: RopeSlice, char_idx: usize) -> bool {
323 }
179 }
324}
180}
325
181
326−/// Returns whether the given byte position is a grapheme boundary.
327−#[must_use]
328−pub fn is_grapheme_boundary_byte(slice: RopeSlice, byte_idx: usize) -> bool {
329− // Bounds check
330− debug_assert!(byte_idx <= slice.len_bytes());
331−
332− // Get the chunk with our byte index in it.
333− let (chunk, chunk_byte_idx, _, _) = slice.chunk_at_byte(byte_idx);
334−
335− // Set up the grapheme cursor.
336− let mut gc = GraphemeCursor::new(byte_idx, slice.len_bytes(), true);
337−
338− // Determine if the given position is a grapheme cluster boundary.
339− loop {
340− match gc.is_boundary(chunk, chunk_byte_idx) {
341− Ok(n) => return n,
342− Err(GraphemeIncomplete::PreContext(n)) => {
343− let (ctx_chunk, ctx_byte_start, _, _) = slice.chunk_at_byte(n - 1);
344− gc.provide_context(ctx_chunk, ctx_byte_start);
345− }
346− Err(_) => unreachable!(),
347− }
348− }
349−}
350−
351/// An iterator over the graphemes of a `RopeSlice`.
182/// An iterator over the graphemes of a `RopeSlice`.
352#[derive(Clone)]
183#[derive(Clone)]
353pub struct RopeGraphemes<'a> {
184pub struct RopeGraphemes<'a> {
@@ -416,7 +247,10 @@ impl<'a> Iterator for RopeGraphemes<'a> {
416 }
247 }
417
248
418 if a < self.cur_chunk_start {
249 if a < self.cur_chunk_start {
419− Some(self.text.byte_slice(a..b))
250+ let a_char = self.text.byte_to_char(a);
251+ let b_char = self.text.byte_to_char(b);
252+
253+ Some(self.text.slice(a_char..b_char))
420 } else {
254 } else {
421 let a2 = a - self.cur_chunk_start;
255 let a2 = a - self.cur_chunk_start;
422 let b2 = b - self.cur_chunk_start;
256 let b2 = b - self.cur_chunk_start;
@@ -424,101 +258,3 @@ impl<'a> Iterator for RopeGraphemes<'a> {
424 }
258 }
425 }
259 }
426}
260}
427−
428−/// A highly compressed Cow<'a, str> that holds
429−/// atmost u31::MAX bytes and is readonly
430−pub struct GraphemeStr<'a> {
431− ptr: NonNull<u8>,
432− len: u32,
433− phantom: PhantomData<&'a str>,
434−}
435−
436−impl GraphemeStr<'_> {
437− const MASK_OWNED: u32 = 1 << 31;
438−
439− fn compute_len(&self) -> usize {
440− (self.len & !Self::MASK_OWNED) as usize
441− }
442−}
443−
444−impl Deref for GraphemeStr<'_> {
445− type Target = str;
446− fn deref(&self) -> &Self::Target {
447− unsafe {
448− let bytes = slice::from_raw_parts(self.ptr.as_ptr(), self.compute_len());
449− str::from_utf8_unchecked(bytes)
450− }
451− }
452−}
453−
454−impl Drop for GraphemeStr<'_> {
455− fn drop(&mut self) {
456− if self.len & Self::MASK_OWNED != 0 {
457− // free allocation
458− unsafe {
459− drop(Box::from_raw(slice::from_raw_parts_mut(
460− self.ptr.as_ptr(),
461− self.compute_len(),
462− )));
463− }
464− }
465− }
466−}
467−
468−impl<'a> From<&'a str> for GraphemeStr<'a> {
469− fn from(g: &'a str) -> Self {
470− GraphemeStr {
471− ptr: unsafe { NonNull::new_unchecked(g.as_bytes().as_ptr() as *mut u8) },
472− len: i32::try_from(g.len()).unwrap() as u32,
473− phantom: PhantomData,
474− }
475− }
476−}
477−
478−impl<'a> From<String> for GraphemeStr<'a> {
479− fn from(g: String) -> Self {
480− let len = g.len();
481− let ptr = Box::into_raw(g.into_bytes().into_boxed_slice()) as *mut u8;
482− GraphemeStr {
483− ptr: unsafe { NonNull::new_unchecked(ptr) },
484− len: (i32::try_from(len).unwrap() as u32) | Self::MASK_OWNED,
485− phantom: PhantomData,
486− }
487− }
488−}
489−
490−impl<'a> From<Cow<'a, str>> for GraphemeStr<'a> {
491− fn from(g: Cow<'a, str>) -> Self {
492− match g {
493− Cow::Borrowed(g) => g.into(),
494− Cow::Owned(g) => g.into(),
495− }
496− }
497−}
498−
499−impl<T: Deref<Target = str>> PartialEq<T> for GraphemeStr<'_> {
500− fn eq(&self, other: &T) -> bool {
501− self.deref() == other.deref()
502− }
503−}
504−impl PartialEq<str> for GraphemeStr<'_> {
505− fn eq(&self, other: &str) -> bool {
506− self.deref() == other
507− }
508−}
509−impl Eq for GraphemeStr<'_> {}
510−impl Debug for GraphemeStr<'_> {
511− fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
512− Debug::fmt(self.deref(), f)
513− }
514−}
515−impl Display for GraphemeStr<'_> {
516− fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
517− Display::fmt(self.deref(), f)
518− }
519−}
520−impl Clone for GraphemeStr<'_> {
521− fn clone(&self) -> Self {
522− self.deref().to_owned().into()
523− }
524−}
helix-core/src/history.rs+16−44
@@ -1,15 +1,9 @@
1−use crate::{Assoc, ChangeSet, Range, Rope, Selection, Transaction};
1+use crate::{Assoc, ChangeSet, Range, Rope, State, Transaction};
2use once_cell::sync::Lazy;
2use once_cell::sync::Lazy;
3use regex::Regex;
3use regex::Regex;
4use std::num::NonZeroUsize;
4use std::num::NonZeroUsize;
5use std::time::{Duration, Instant};
5use std::time::{Duration, Instant};
6
6
7−#[derive(Debug, Clone)]
8−pub struct State {
9− pub doc: Rope,
10− pub selection: Selection,
11−}
12−
13/// Stores the history of changes to a buffer.
7/// Stores the history of changes to a buffer.
14///
8///
15/// Currently the history is represented as a vector of revisions. The vector
9/// Currently the history is represented as a vector of revisions. The vector
@@ -28,10 +22,10 @@ pub struct State {
28///
22///
29/// The current revision is the one currently displayed in the buffer.
23/// The current revision is the one currently displayed in the buffer.
30///
24///
31−/// Committing a new revision to the history will update the last child of the
25+/// Commiting a new revision to the history will update the last child of the
32/// current revision, and push a new revision to the end of the vector.
26/// current revision, and push a new revision to the end of the vector.
33///
27///
34−/// Revisions are committed with a timestamp. :earlier and :later can be used
28+/// Revisions are commited with a timestamp. :earlier and :later can be used
35/// to jump to the closest revision to a moment in time relative to the timestamp
29/// to jump to the closest revision to a moment in time relative to the timestamp
36/// of the current revision plus (:later) or minus (:earlier) the duration
30/// of the current revision plus (:later) or minus (:earlier) the duration
37/// given to the command. If a single integer is given, the editor will instead
31/// given to the command. If a single integer is given, the editor will instead
@@ -39,7 +33,7 @@ pub struct State {
39///
33///
40/// Limitations:
34/// Limitations:
41/// * Changes in selections currently don't commit history changes. The selection
35/// * Changes in selections currently don't commit history changes. The selection
42−/// will only be updated to the state after a committed buffer change.
36+/// will only be updated to the state after a commited buffer change.
43/// * The vector of history revisions is currently unbounded. This might
37/// * The vector of history revisions is currently unbounded. This might
44/// cause the memory consumption to grow significantly large during long
38/// cause the memory consumption to grow significantly large during long
45/// editing sessions.
39/// editing sessions.
@@ -54,7 +48,7 @@ pub struct History {
54}
48}
55
49
56/// A single point in history. See [History] for more information.
50/// A single point in history. See [History] for more information.
57−#[derive(Debug, Clone)]
51+#[derive(Debug)]
58struct Revision {
52struct Revision {
59 parent: usize,
53 parent: usize,
60 last_child: Option<NonZeroUsize>,
54 last_child: Option<NonZeroUsize>,
@@ -72,8 +66,8 @@ impl Default for History {
72 revisions: vec![Revision {
66 revisions: vec![Revision {
73 parent: 0,
67 parent: 0,
74 last_child: None,
68 last_child: None,
75− transaction: Transaction::from(ChangeSet::new("".into())),
69+ transaction: Transaction::from(ChangeSet::new(&Rope::new())),
76− inversion: Transaction::from(ChangeSet::new("".into())),
70+ inversion: Transaction::from(ChangeSet::new(&Rope::new())),
77 timestamp: Instant::now(),
71 timestamp: Instant::now(),
78 }],
72 }],
79 current: 0,
73 current: 0,
@@ -119,21 +113,6 @@ impl History {
119 self.current == 0
113 self.current == 0
120 }
114 }
121
115
122− /// Returns the changes since the given revision composed into a transaction.
123− /// Returns None if there are no changes between the current and given revisions.
124− pub fn changes_since(&self, revision: usize) -> Option<Transaction> {
125− let lca = self.lowest_common_ancestor(revision, self.current);
126− let up = self.path_up(revision, lca);
127− let down = self.path_up(self.current, lca);
128− let up_txns = up
129− .iter()
130− .rev()
131− .map(|&n| self.revisions[n].inversion.clone());
132− let down_txns = down.iter().map(|&n| self.revisions[n].transaction.clone());
133−
134− down_txns.chain(up_txns).reduce(|acc, tx| tx.compose(acc))
135− }
136−
137 /// Undo the last edit.
116 /// Undo the last edit.
138 pub fn undo(&mut self) -> Option<&Transaction> {
117 pub fn undo(&mut self) -> Option<&Transaction> {
139 if self.at_root() {
118 if self.at_root() {
@@ -198,7 +177,7 @@ impl History {
198 }
177 }
199 }
178 }
200
179
201− /// List of nodes on the way from `n` to 'a`. Doesn't include `a`.
180+ /// List of nodes on the way from `n` to 'a`. Doesn`t include `a`.
202 /// Includes `n` unless `a == n`. `a` must be an ancestor of `n`.
181 /// Includes `n` unless `a == n`. `a` must be an ancestor of `n`.
203 fn path_up(&self, mut n: usize, a: usize) -> Vec<usize> {
182 fn path_up(&self, mut n: usize, a: usize) -> Vec<usize> {
204 let mut path = Vec::new();
183 let mut path = Vec::new();
@@ -303,13 +282,13 @@ impl History {
303}
282}
304
283
305/// Whether to undo by a number of edits or a duration of time.
284/// Whether to undo by a number of edits or a duration of time.
306−#[derive(Debug, PartialEq, Eq, Clone, Copy)]
285+#[derive(Debug, PartialEq, Clone, Copy)]
307pub enum UndoKind {
286pub enum UndoKind {
308 Steps(usize),
287 Steps(usize),
309 TimePeriod(std::time::Duration),
288 TimePeriod(std::time::Duration),
310}
289}
311
290
312−/// A subset of systemd.time time span syntax units.
291+/// A subset of sytemd.time time span syntax units.
313const TIME_UNITS: &[(&[&str], &str, u64)] = &[
292const TIME_UNITS: &[(&[&str], &str, u64)] = &[
314 (&["seconds", "second", "sec", "s"], "seconds", 1),
293 (&["seconds", "second", "sec", "s"], "seconds", 1),
315 (&["minutes", "minute", "min", "m"], "minutes", 60),
294 (&["minutes", "minute", "min", "m"], "minutes", 60),
@@ -387,16 +366,12 @@ impl std::str::FromStr for UndoKind {
387#[cfg(test)]
366#[cfg(test)]
388mod test {
367mod test {
389 use super::*;
368 use super::*;
390− use crate::Selection;
391
369
392 #[test]
370 #[test]
393 fn test_undo_redo() {
371 fn test_undo_redo() {
394 let mut history = History::default();
372 let mut history = History::default();
395 let doc = Rope::from("hello");
373 let doc = Rope::from("hello");
396− let mut state = State {
374+ let mut state = State::new(doc);
397− doc,
398− selection: Selection::point(0),
399− };
400
375
401 let transaction1 =
376 let transaction1 =
402 Transaction::change(&state.doc, vec![(5, 5, Some(" world!".into()))].into_iter());
377 Transaction::change(&state.doc, vec![(5, 5, Some(" world!".into()))].into_iter());
@@ -445,10 +420,7 @@ mod test {
445 fn test_earlier_later() {
420 fn test_earlier_later() {
446 let mut history = History::default();
421 let mut history = History::default();
447 let doc = Rope::from("a\n");
422 let doc = Rope::from("a\n");
448− let mut state = State {
423+ let mut state = State::new(doc);
449− doc,
450− selection: Selection::point(0),
451− };
452
424
453 fn undo(history: &mut History, state: &mut State) {
425 fn undo(history: &mut History, state: &mut State) {
454 if let Some(transaction) = history.undo() {
426 if let Some(transaction) = history.undo() {
@@ -476,8 +448,8 @@ mod test {
476 change: crate::transaction::Change,
448 change: crate::transaction::Change,
477 instant: Instant,
449 instant: Instant,
478 ) {
450 ) {
479− let txn = Transaction::change(&state.doc, vec![change].into_iter());
451+ let txn = Transaction::change(&state.doc, vec![change.clone()].into_iter());
480− history.commit_revision_at_timestamp(&txn, state, instant);
452+ history.commit_revision_at_timestamp(&txn, &state, instant);
481 txn.apply(&mut state.doc);
453 txn.apply(&mut state.doc);
482 }
454 }
483
455
@@ -574,8 +546,8 @@ mod test {
574
546
575 // Units are validated.
547 // Units are validated.
576 assert_eq!(
548 assert_eq!(
577− "1 millennium".parse::<UndoKind>(),
549+ "1 millenium".parse::<UndoKind>(),
578− Err("incorrect time unit: millennium".to_string())
550+ Err("incorrect time unit: millenium".to_string())
579 );
551 );
580
552
581 // Units can't be specified twice.
553 // Units can't be specified twice.
helix-core/src/increment/date_time.rs+264−94
@@ -1,53 +1,113 @@
1−use chrono::{Duration, NaiveDate, NaiveDateTime, NaiveTime};
1+use chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
2use once_cell::sync::Lazy;
2use once_cell::sync::Lazy;
3use regex::Regex;
3use regex::Regex;
4−use std::fmt::Write;
4+use ropey::RopeSlice;
5−
6−/// Increment a Date or DateTime
7−///
8−/// If just a Date is selected the day will be incremented.
9−/// If a DateTime is selected the second will be incremented.
10−pub fn increment(selected_text: &str, amount: i64) -> Option<String> {
11− if selected_text.is_empty() {
12− return None;
13− }
14
5
15− FORMATS.iter().find_map(|format| {
6+use std::borrow::Cow;
16− let captures = format.regex.captures(selected_text)?;
7+use std::cmp;
17− if captures.len() - 1 != format.fields.len() {
18− return None;
19− }
20
8
21− let date_time = captures.get(0)?;
9+use super::Increment;
22− let has_date = format.fields.iter().any(|f| f.unit.is_date());
10+use crate::{Range, Tendril};
23− let has_time = format.fields.iter().any(|f| f.unit.is_time());
11+
24− let date_time = &selected_text[date_time.start()..date_time.end()];
12+#[derive(Debug, PartialEq, Eq)]
25− match (has_date, has_time) {
13+pub struct DateTimeIncrementor {
26− (true, true) => {
14+ date_time: NaiveDateTime,
27− let date_time = NaiveDateTime::parse_from_str(date_time, format.fmt).ok()?;
15+ range: Range,
28− Some(
16+ fmt: &'static str,
29− date_time
17+ field: DateField,
30− .checked_add_signed(Duration::minutes(amount))?
18+}
31− .format(format.fmt)
19+
32− .to_string(),
20+impl DateTimeIncrementor {
33− )
21+ pub fn from_range(text: RopeSlice, range: Range) -> Option<DateTimeIncrementor> {
34− }
22+ let range = if range.is_empty() {
35− (true, false) => {
23+ if range.anchor < text.len_chars() {
36− let date = NaiveDate::parse_from_str(date_time, format.fmt).ok()?;
24+ // Treat empty range as a cursor range.
37− Some(
25+ range.put_cursor(text, range.anchor + 1, true)
38− date.checked_add_signed(Duration::days(amount))?
26+ } else {
39− .format(format.fmt)
27+ // The range is empty and at the end of the text.
40− .to_string(),
28+ return None;
41− )
42 }
29 }
43− (false, true) => {
30+ } else {
44− let time = NaiveTime::parse_from_str(date_time, format.fmt).ok()?;
31+ range
45− let (adjusted_time, _) = time.overflowing_add_signed(Duration::minutes(amount));
32+ };
46− Some(adjusted_time.format(format.fmt).to_string())
33+
34+ FORMATS.iter().find_map(|format| {
35+ let from = range.from().saturating_sub(format.max_len);
36+ let to = (range.from() + format.max_len).min(text.len_chars());
37+
38+ let (from_in_text, to_in_text) = (range.from() - from, range.to() - from);
39+ let text: Cow<str> = text.slice(from..to).into();
40+
41+ let captures = format.regex.captures(&text)?;
42+ if captures.len() - 1 != format.fields.len() {
43+ return None;
47 }
44 }
48− (false, false) => None,
45+
46+ let date_time = captures.get(0)?;
47+ let offset = range.from() - from_in_text;
48+ let range = Range::new(date_time.start() + offset, date_time.end() + offset);
49+
50+ let field = captures
51+ .iter()
52+ .skip(1)
53+ .enumerate()
54+ .find_map(|(i, capture)| {
55+ let capture = capture?;
56+ let capture_range = capture.range();
57+
58+ if capture_range.contains(&from_in_text)
59+ && capture_range.contains(&(to_in_text - 1))
60+ {
61+ Some(format.fields[i])
62+ } else {
63+ None
64+ }
65+ })?;
66+
67+ let has_date = format.fields.iter().any(|f| f.unit.is_date());
68+ let has_time = format.fields.iter().any(|f| f.unit.is_time());
69+
70+ let date_time = &text[date_time.start()..date_time.end()];
71+ let date_time = match (has_date, has_time) {
72+ (true, true) => NaiveDateTime::parse_from_str(date_time, format.fmt).ok()?,
73+ (true, false) => {
74+ let date = NaiveDate::parse_from_str(date_time, format.fmt).ok()?;
75+
76+ date.and_hms(0, 0, 0)
77+ }
78+ (false, true) => {
79+ let time = NaiveTime::parse_from_str(date_time, format.fmt).ok()?;
80+
81+ NaiveDate::from_ymd(0, 1, 1).and_time(time)
82+ }
83+ (false, false) => return None,
84+ };
85+
86+ Some(DateTimeIncrementor {
87+ date_time,
88+ range,
89+ fmt: format.fmt,
90+ field,
91+ })
92+ })
93+ }
94+}
95+
96+impl Increment for DateTimeIncrementor {
97+ fn increment(&self, amount: i64) -> (Range, Tendril) {
98+ let date_time = match self.field.unit {
99+ DateUnit::Years => add_years(self.date_time, amount),
100+ DateUnit::Months => add_months(self.date_time, amount),
101+ DateUnit::Days => add_duration(self.date_time, Duration::days(amount)),
102+ DateUnit::Hours => add_duration(self.date_time, Duration::hours(amount)),
103+ DateUnit::Minutes => add_duration(self.date_time, Duration::minutes(amount)),
104+ DateUnit::Seconds => add_duration(self.date_time, Duration::seconds(amount)),
105+ DateUnit::AmPm => toggle_am_pm(self.date_time),
49 }
106 }
50− })
107+ .unwrap_or(self.date_time);
108+
109+ (self.range, date_time.format(self.fmt).to_string().into())
110+ }
51}
111}
52
112
53static FORMATS: Lazy<Vec<Format>> = Lazy::new(|| {
113static FORMATS: Lazy<Vec<Format>> = Lazy::new(|| {
@@ -83,7 +143,7 @@ impl Format {
83 fn new(fmt: &'static str) -> Self {
143 fn new(fmt: &'static str) -> Self {
84 let mut remaining = fmt;
144 let mut remaining = fmt;
85 let mut fields = Vec::new();
145 let mut fields = Vec::new();
86− let mut regex = "^".to_string();
146+ let mut regex = String::new();
87 let mut max_len = 0;
147 let mut max_len = 0;
88
148
89 while let Some(i) = remaining.find('%') {
149 while let Some(i) = remaining.find('%') {
@@ -102,10 +162,9 @@ impl Format {
102 fields.push(field);
162 fields.push(field);
103 max_len += field.max_len + remaining[..i].len();
163 max_len += field.max_len + remaining[..i].len();
104 regex += &remaining[..i];
164 regex += &remaining[..i];
105− write!(regex, "({})", field.regex).unwrap();
165+ regex += &format!("({})", field.regex);
106 remaining = &after[spec_len..];
166 remaining = &after[spec_len..];
107 }
167 }
108− regex += "$";
109
168
110 let regex = Regex::new(&regex).unwrap();
169 let regex = Regex::new(&regex).unwrap();
111
170
@@ -136,82 +195,82 @@ struct DateField {
136impl DateField {
195impl DateField {
137 fn from_specifier(specifier: &str) -> Option<Self> {
196 fn from_specifier(specifier: &str) -> Option<Self> {
138 match specifier {
197 match specifier {
139− "Y" => Some(Self {
198+ "Y" => Some(DateField {
140 regex: r"\d{4}",
199 regex: r"\d{4}",
141 unit: DateUnit::Years,
200 unit: DateUnit::Years,
142 max_len: 5,
201 max_len: 5,
143 }),
202 }),
144− "y" => Some(Self {
203+ "y" => Some(DateField {
145 regex: r"\d\d",
204 regex: r"\d\d",
146 unit: DateUnit::Years,
205 unit: DateUnit::Years,
147 max_len: 2,
206 max_len: 2,
148 }),
207 }),
149− "m" => Some(Self {
208+ "m" => Some(DateField {
150 regex: r"[0-1]\d",
209 regex: r"[0-1]\d",
151 unit: DateUnit::Months,
210 unit: DateUnit::Months,
152 max_len: 2,
211 max_len: 2,
153 }),
212 }),
154− "d" => Some(Self {
213+ "d" => Some(DateField {
155 regex: r"[0-3]\d",
214 regex: r"[0-3]\d",
156 unit: DateUnit::Days,
215 unit: DateUnit::Days,
157 max_len: 2,
216 max_len: 2,
158 }),
217 }),
159− "-d" => Some(Self {
218+ "-d" => Some(DateField {
160 regex: r"[1-3]?\d",
219 regex: r"[1-3]?\d",
161 unit: DateUnit::Days,
220 unit: DateUnit::Days,
162 max_len: 2,
221 max_len: 2,
163 }),
222 }),
164− "a" => Some(Self {
223+ "a" => Some(DateField {
165 regex: r"Sun|Mon|Tue|Wed|Thu|Fri|Sat",
224 regex: r"Sun|Mon|Tue|Wed|Thu|Fri|Sat",
166 unit: DateUnit::Days,
225 unit: DateUnit::Days,
167 max_len: 3,
226 max_len: 3,
168 }),
227 }),
169− "A" => Some(Self {
228+ "A" => Some(DateField {
170 regex: r"Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday",
229 regex: r"Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday",
171 unit: DateUnit::Days,
230 unit: DateUnit::Days,
172 max_len: 9,
231 max_len: 9,
173 }),
232 }),
174− "b" | "h" => Some(Self {
233+ "b" | "h" => Some(DateField {
175 regex: r"Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec",
234 regex: r"Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec",
176 unit: DateUnit::Months,
235 unit: DateUnit::Months,
177 max_len: 3,
236 max_len: 3,
178 }),
237 }),
179− "B" => Some(Self {
238+ "B" => Some(DateField {
180 regex: r"January|February|March|April|May|June|July|August|September|October|November|December",
239 regex: r"January|February|March|April|May|June|July|August|September|October|November|December",
181 unit: DateUnit::Months,
240 unit: DateUnit::Months,
182 max_len: 9,
241 max_len: 9,
183 }),
242 }),
184− "H" => Some(Self {
243+ "H" => Some(DateField {
185 regex: r"[0-2]\d",
244 regex: r"[0-2]\d",
186 unit: DateUnit::Hours,
245 unit: DateUnit::Hours,
187 max_len: 2,
246 max_len: 2,
188 }),
247 }),
189− "M" => Some(Self {
248+ "M" => Some(DateField {
190 regex: r"[0-5]\d",
249 regex: r"[0-5]\d",
191 unit: DateUnit::Minutes,
250 unit: DateUnit::Minutes,
192 max_len: 2,
251 max_len: 2,
193 }),
252 }),
194− "S" => Some(Self {
253+ "S" => Some(DateField {
195 regex: r"[0-5]\d",
254 regex: r"[0-5]\d",
196 unit: DateUnit::Seconds,
255 unit: DateUnit::Seconds,
197 max_len: 2,
256 max_len: 2,
198 }),
257 }),
199− "I" => Some(Self {
258+ "I" => Some(DateField {
200 regex: r"[0-1]\d",
259 regex: r"[0-1]\d",
201 unit: DateUnit::Hours,
260 unit: DateUnit::Hours,
202 max_len: 2,
261 max_len: 2,
203 }),
262 }),
204− "-I" => Some(Self {
263+ "-I" => Some(DateField {
205 regex: r"1?\d",
264 regex: r"1?\d",
206 unit: DateUnit::Hours,
265 unit: DateUnit::Hours,
207 max_len: 2,
266 max_len: 2,
208 }),
267 }),
209− "P" => Some(Self {
268+ "P" => Some(DateField {
210 regex: r"am|pm",
269 regex: r"am|pm",
211 unit: DateUnit::AmPm,
270 unit: DateUnit::AmPm,
212 max_len: 2,
271 max_len: 2,
213 }),
272 }),
214− "p" => Some(Self {
273+ "p" => Some(DateField {
215 regex: r"AM|PM",
274 regex: r"AM|PM",
216 unit: DateUnit::AmPm,
275 unit: DateUnit::AmPm,
217 max_len: 2,
276 max_len: 2,
@@ -245,47 +304,155 @@ impl DateUnit {
245 }
304 }
246}
305}
247
306
307+fn ndays_in_month(year: i32, month: u32) -> u32 {
308+ // The first day of the next month...
309+ let (y, m) = if month == 12 {
310+ (year + 1, 1)
311+ } else {
312+ (year, month + 1)
313+ };
314+ let d = NaiveDate::from_ymd(y, m, 1);
315+
316+ // ...is preceded by the last day of the original month.
317+ d.pred().day()
318+}
319+
320+fn add_months(date_time: NaiveDateTime, amount: i64) -> Option<NaiveDateTime> {
321+ let month = (date_time.month0() as i64).checked_add(amount)?;
322+ let year = date_time.year() + i32::try_from(month / 12).ok()?;
323+ let year = if month.is_negative() { year - 1 } else { year };
324+
325+ // Normalize month
326+ let month = month % 12;
327+ let month = if month.is_negative() {
328+ month + 12
329+ } else {
330+ month
331+ } as u32
332+ + 1;
333+
334+ let day = cmp::min(date_time.day(), ndays_in_month(year, month));
335+
336+ Some(NaiveDate::from_ymd(year, month, day).and_time(date_time.time()))
337+}
338+
339+fn add_years(date_time: NaiveDateTime, amount: i64) -> Option<NaiveDateTime> {
340+ let year = i32::try_from((date_time.year() as i64).checked_add(amount)?).ok()?;
341+ let ndays = ndays_in_month(year, date_time.month());
342+
343+ if date_time.day() > ndays {
344+ let d = NaiveDate::from_ymd(year, date_time.month(), ndays);
345+ Some(d.succ().and_time(date_time.time()))
346+ } else {
347+ date_time.with_year(year)
348+ }
349+}
350+
351+fn add_duration(date_time: NaiveDateTime, duration: Duration) -> Option<NaiveDateTime> {
352+ date_time.checked_add_signed(duration)
353+}
354+
355+fn toggle_am_pm(date_time: NaiveDateTime) -> Option<NaiveDateTime> {
356+ if date_time.hour() < 12 {
357+ add_duration(date_time, Duration::hours(12))
358+ } else {
359+ add_duration(date_time, Duration::hours(-12))
360+ }
361+}
362+
248#[cfg(test)]
363#[cfg(test)]
249mod test {
364mod test {
250 use super::*;
365 use super::*;
366+ use crate::Rope;
251
367
252 #[test]
368 #[test]
253 fn test_increment_date_times() {
369 fn test_increment_date_times() {
254 let tests = [
370 let tests = [
255 // (original, cursor, amount, expected)
371 // (original, cursor, amount, expected)
256− ("2020-02-28", 1, "2020-02-29"),
372+ ("2020-02-28", 0, 1, "2021-02-28"),
257− ("2020-02-29", 1, "2020-03-01"),
373+ ("2020-02-29", 0, 1, "2021-03-01"),
258− ("2020-01-31", 1, "2020-02-01"),
374+ ("2020-01-31", 5, 1, "2020-02-29"),
259− ("2020-01-20", 1, "2020-01-21"),
375+ ("2020-01-20", 5, 1, "2020-02-20"),
260− ("2021-01-01", -1, "2020-12-31"),
376+ ("2021-01-01", 5, -1, "2020-12-01"),
261− ("2021-01-31", -2, "2021-01-29"),
377+ ("2021-01-31", 5, -2, "2020-11-30"),
262− ("2020-02-28", 1, "2020-02-29"),
378+ ("2020-02-28", 8, 1, "2020-02-29"),
263− ("2021-02-28", 1, "2021-03-01"),
379+ ("2021-02-28", 8, 1, "2021-03-01"),
264− ("2021-03-01", -1, "2021-02-28"),
380+ ("2021-02-28", 0, -1, "2020-02-28"),
265− ("2020-02-29", -1, "2020-02-28"),
381+ ("2021-03-01", 0, -1, "2020-03-01"),
266− ("2020-02-20", -1, "2020-02-19"),
382+ ("2020-02-29", 5, -1, "2020-01-29"),
267− ("2021-03-01", -1, "2021-02-28"),
383+ ("2020-02-20", 5, -1, "2020-01-20"),
268− ("1980/12/21", 100, "1981/03/31"),
384+ ("2020-02-29", 8, -1, "2020-02-28"),
269− ("1980/12/21", -100, "1980/09/12"),
385+ ("2021-03-01", 8, -1, "2021-02-28"),
270− ("1980/12/21", 1000, "1983/09/17"),
386+ ("1980/12/21", 8, 100, "1981/03/31"),
271− ("1980/12/21", -1000, "1978/03/27"),
387+ ("1980/12/21", 8, -100, "1980/09/12"),
272− ("2021-11-24 07:12:23", 1, "2021-11-24 07:13:23"),
388+ ("1980/12/21", 8, 1000, "1983/09/17"),
273− ("2021-11-24 07:12", 1, "2021-11-24 07:13"),
389+ ("1980/12/21", 8, -1000, "1978/03/27"),
274− ("Wed Nov 24 2021", 1, "Thu Nov 25 2021"),
390+ ("2021-11-24 07:12:23", 0, 1, "2022-11-24 07:12:23"),
275− ("24-Nov-2021", 1, "25-Nov-2021"),
391+ ("2021-11-24 07:12:23", 5, 1, "2021-12-24 07:12:23"),
276− ("2021 Nov 24", 1, "2021 Nov 25"),
392+ ("2021-11-24 07:12:23", 8, 1, "2021-11-25 07:12:23"),
277− ("Nov 24, 2021", 1, "Nov 25, 2021"),
393+ ("2021-11-24 07:12:23", 11, 1, "2021-11-24 08:12:23"),
278− ("7:21:53 am", 1, "7:22:53 am"),
394+ ("2021-11-24 07:12:23", 14, 1, "2021-11-24 07:13:23"),
279− ("7:21:53 AM", 1, "7:22:53 AM"),
395+ ("2021-11-24 07:12:23", 17, 1, "2021-11-24 07:12:24"),
280− ("7:21 am", 1, "7:22 am"),
396+ ("2021/11/24 07:12:23", 0, 1, "2022/11/24 07:12:23"),
281− ("23:24:23", 1, "23:25:23"),
397+ ("2021/11/24 07:12:23", 5, 1, "2021/12/24 07:12:23"),
282− ("23:24", 1, "23:25"),
398+ ("2021/11/24 07:12:23", 8, 1, "2021/11/25 07:12:23"),
283− ("23:59", 1, "00:00"),
399+ ("2021/11/24 07:12:23", 11, 1, "2021/11/24 08:12:23"),
284− ("23:59:59", 1, "00:00:59"),
400+ ("2021/11/24 07:12:23", 14, 1, "2021/11/24 07:13:23"),
401+ ("2021/11/24 07:12:23", 17, 1, "2021/11/24 07:12:24"),
402+ ("2021-11-24 07:12", 0, 1, "2022-11-24 07:12"),
403+ ("2021-11-24 07:12", 5, 1, "2021-12-24 07:12"),
404+ ("2021-11-24 07:12", 8, 1, "2021-11-25 07:12"),
405+ ("2021-11-24 07:12", 11, 1, "2021-11-24 08:12"),
406+ ("2021-11-24 07:12", 14, 1, "2021-11-24 07:13"),
407+ ("2021/11/24 07:12", 0, 1, "2022/11/24 07:12"),
408+ ("2021/11/24 07:12", 5, 1, "2021/12/24 07:12"),
409+ ("2021/11/24 07:12", 8, 1, "2021/11/25 07:12"),
410+ ("2021/11/24 07:12", 11, 1, "2021/11/24 08:12"),
411+ ("2021/11/24 07:12", 14, 1, "2021/11/24 07:13"),
412+ ("Wed Nov 24 2021", 0, 1, "Thu Nov 25 2021"),
413+ ("Wed Nov 24 2021", 4, 1, "Fri Dec 24 2021"),
414+ ("Wed Nov 24 2021", 8, 1, "Thu Nov 25 2021"),
415+ ("Wed Nov 24 2021", 11, 1, "Thu Nov 24 2022"),
416+ ("24-Nov-2021", 0, 1, "25-Nov-2021"),
417+ ("24-Nov-2021", 3, 1, "24-Dec-2021"),
418+ ("24-Nov-2021", 7, 1, "24-Nov-2022"),
419+ ("2021 Nov 24", 0, 1, "2022 Nov 24"),
420+ ("2021 Nov 24", 5, 1, "2021 Dec 24"),
421+ ("2021 Nov 24", 9, 1, "2021 Nov 25"),
422+ ("Nov 24, 2021", 0, 1, "Dec 24, 2021"),
423+ ("Nov 24, 2021", 4, 1, "Nov 25, 2021"),
424+ ("Nov 24, 2021", 8, 1, "Nov 24, 2022"),
425+ ("7:21:53 am", 0, 1, "8:21:53 am"),
426+ ("7:21:53 am", 3, 1, "7:22:53 am"),
427+ ("7:21:53 am", 5, 1, "7:21:54 am"),
428+ ("7:21:53 am", 8, 1, "7:21:53 pm"),
429+ ("7:21:53 AM", 0, 1, "8:21:53 AM"),
430+ ("7:21:53 AM", 3, 1, "7:22:53 AM"),
431+ ("7:21:53 AM", 5, 1, "7:21:54 AM"),
432+ ("7:21:53 AM", 8, 1, "7:21:53 PM"),
433+ ("7:21 am", 0, 1, "8:21 am"),
434+ ("7:21 am", 3, 1, "7:22 am"),
435+ ("7:21 am", 5, 1, "7:21 pm"),
436+ ("7:21 AM", 0, 1, "8:21 AM"),
437+ ("7:21 AM", 3, 1, "7:22 AM"),
438+ ("7:21 AM", 5, 1, "7:21 PM"),
439+ ("23:24:23", 1, 1, "00:24:23"),
440+ ("23:24:23", 3, 1, "23:25:23"),
441+ ("23:24:23", 6, 1, "23:24:24"),
442+ ("23:24", 1, 1, "00:24"),
443+ ("23:24", 3, 1, "23:25"),
285 ];
444 ];
286
445
287− for (original, amount, expected) in tests {
446+ for (original, cursor, amount, expected) in tests {
288− assert_eq!(increment(original, amount).unwrap(), expected);
447+ let rope = Rope::from_str(original);
448+ let range = Range::new(cursor, cursor + 1);
449+ assert_eq!(
450+ DateTimeIncrementor::from_range(rope.slice(..), range)
451+ .unwrap()
452+ .increment(amount)
453+ .1,
454+ expected.into()
455+ );
289 }
456 }
290 }
457 }
291
458
@@ -314,7 +481,10 @@ mod test {
314 ];
481 ];
315
482
316 for invalid in tests {
483 for invalid in tests {
317− assert_eq!(increment(invalid, 1), None)
484+ let rope = Rope::from_str(invalid);
485+ let range = Range::new(0, 1);
486+
487+ assert_eq!(DateTimeIncrementor::from_range(rope.slice(..), range), None)
318 }
488 }
319 }
489 }
320}
490}
helix-core/src/increment/integer.rsdeleted−235
@@ -1,235 +0,0 @@
1−const SEPARATOR: char = '_';
2−
3−/// Increment an integer.
4−///
5−/// Supported bases:
6−/// 2 with prefix 0b
7−/// 8 with prefix 0o
8−/// 10 with no prefix
9−/// 16 with prefix 0x
10−///
11−/// An integer can contain `_` as a separator but may not start or end with a separator.
12−/// Base 10 integers can go negative, but bases 2, 8, and 16 cannot.
13−/// All addition and subtraction is saturating.
14−pub fn increment(selected_text: &str, amount: i64) -> Option<String> {
15− if selected_text.is_empty()
16− || selected_text.ends_with(SEPARATOR)
17− || selected_text.starts_with(SEPARATOR)
18− {
19− return None;
20− }
21−
22− let radix = if selected_text.starts_with("0x") {
23− 16
24− } else if selected_text.starts_with("0o") {
25− 8
26− } else if selected_text.starts_with("0b") {
27− 2
28− } else {
29− 10
30− };
31−
32− // Get separator indexes from right to left.
33− let separator_rtl_indexes: Vec<usize> = selected_text
34− .chars()
35− .rev()
36− .enumerate()
37− .filter_map(|(i, c)| if c == SEPARATOR { Some(i) } else { None })
38− .collect();
39−
40− let word: String = selected_text.chars().filter(|&c| c != SEPARATOR).collect();
41−
42− let mut new_text = if radix == 10 {
43− let number = &word;
44− let value = i128::from_str_radix(number, radix).ok()?;
45− let new_value = value.saturating_add(amount as i128);
46−
47− let format_length = match (value.is_negative(), new_value.is_negative()) {
48− (true, false) => number.len() - 1,
49− (false, true) => number.len() + 1,
50− _ => number.len(),
51− } - separator_rtl_indexes.len();
52−
53− if number.starts_with('0') || number.starts_with("-0") {
54− format!("{:01$}", new_value, format_length)
55− } else {
56− format!("{}", new_value)
57− }
58− } else {
59− let number = &word[2..];
60− let value = u128::from_str_radix(number, radix).ok()?;
61− let new_value = (value as i128).saturating_add(amount as i128);
62− let new_value = if new_value < 0 { 0 } else { new_value };
63− let format_length = selected_text.len() - 2 - separator_rtl_indexes.len();
64−
65− match radix {
66− 2 => format!("0b{:01$b}", new_value, format_length),
67− 8 => format!("0o{:01$o}", new_value, format_length),
68− 16 => {
69− let (lower_count, upper_count): (usize, usize) =
70− number.chars().fold((0, 0), |(lower, upper), c| {
71− (
72− lower + c.is_ascii_lowercase() as usize,
73− upper + c.is_ascii_uppercase() as usize,
74− )
75− });
76− if upper_count > lower_count {
77− format!("0x{:01$X}", new_value, format_length)
78− } else {
79− format!("0x{:01$x}", new_value, format_length)
80− }
81− }
82− _ => unimplemented!("radix not supported: {}", radix),
83− }
84− };
85−
86− // Add separators from original number.
87− for &rtl_index in &separator_rtl_indexes {
88− if rtl_index < new_text.len() {
89− let new_index = new_text.len().saturating_sub(rtl_index);
90− if new_index > 0 {
91− new_text.insert(new_index, SEPARATOR);
92− }
93− }
94− }
95−
96− // Add in additional separators if necessary.
97− if new_text.len() > selected_text.len() && !separator_rtl_indexes.is_empty() {
98− let spacing = match separator_rtl_indexes.as_slice() {
99− [.., b, a] => a - b - 1,
100− _ => separator_rtl_indexes[0],
101− };
102−
103− let prefix_length = if radix == 10 { 0 } else { 2 };
104− if let Some(mut index) = new_text.find(SEPARATOR) {
105− while index - prefix_length > spacing {
106− index -= spacing;
107− new_text.insert(index, SEPARATOR);
108− }
109− }
110− }
111−
112− Some(new_text)
113−}
114−
115−#[cfg(test)]
116−mod test {
117− use super::*;
118−
119− #[test]
120− fn test_increment_basic_decimal_numbers() {
121− let tests = [
122− ("100", 1, "101"),
123− ("100", -1, "99"),
124− ("99", 1, "100"),
125− ("100", 1000, "1100"),
126− ("100", -1000, "-900"),
127− ("-1", 1, "0"),
128− ("-1", 2, "1"),
129− ("1", -1, "0"),
130− ("1", -2, "-1"),
131− ];
132−
133− for (original, amount, expected) in tests {
134− assert_eq!(increment(original, amount).unwrap(), expected);
135− }
136− }
137−
138− #[test]
139− fn test_increment_basic_hexadecimal_numbers() {
140− let tests = [
141− ("0x0100", 1, "0x0101"),
142− ("0x0100", -1, "0x00ff"),
143− ("0x0001", -1, "0x0000"),
144− ("0x0000", -1, "0x0000"),
145− ("0xffffffffffffffff", 1, "0x10000000000000000"),
146− ("0xffffffffffffffff", 2, "0x10000000000000001"),
147− ("0xffffffffffffffff", -1, "0xfffffffffffffffe"),
148− ("0xABCDEF1234567890", 1, "0xABCDEF1234567891"),
149− ("0xabcdef1234567890", 1, "0xabcdef1234567891"),
150− ];
151−
152− for (original, amount, expected) in tests {
153− assert_eq!(increment(original, amount).unwrap(), expected);
154− }
155− }
156−
157− #[test]
158− fn test_increment_basic_octal_numbers() {
159− let tests = [
160− ("0o0107", 1, "0o0110"),
161− ("0o0110", -1, "0o0107"),
162− ("0o0001", -1, "0o0000"),
163− ("0o7777", 1, "0o10000"),
164− ("0o1000", -1, "0o0777"),
165− ("0o0107", 10, "0o0121"),
166− ("0o0000", -1, "0o0000"),
167− ("0o1777777777777777777777", 1, "0o2000000000000000000000"),
168− ("0o1777777777777777777777", 2, "0o2000000000000000000001"),
169− ("0o1777777777777777777777", -1, "0o1777777777777777777776"),
170− ];
171−
172− for (original, amount, expected) in tests {
173− assert_eq!(increment(original, amount).unwrap(), expected);
174− }
175− }
176−
177− #[test]
178− fn test_increment_basic_binary_numbers() {
179− let tests = [
180− ("0b00000100", 1, "0b00000101"),
181− ("0b00000100", -1, "0b00000011"),
182− ("0b00000100", 2, "0b00000110"),
183− ("0b00000100", -2, "0b00000010"),
184− ("0b00000001", -1, "0b00000000"),
185− ("0b00111111", 10, "0b01001001"),
186− ("0b11111111", 1, "0b100000000"),
187− ("0b10000000", -1, "0b01111111"),
188− ("0b0000", -1, "0b0000"),
189− (
190− "0b1111111111111111111111111111111111111111111111111111111111111111",
191− 1,
192− "0b10000000000000000000000000000000000000000000000000000000000000000",
193− ),
194− (
195− "0b1111111111111111111111111111111111111111111111111111111111111111",
196− 2,
197− "0b10000000000000000000000000000000000000000000000000000000000000001",
198− ),
199− (
200− "0b1111111111111111111111111111111111111111111111111111111111111111",
201− -1,
202− "0b1111111111111111111111111111111111111111111111111111111111111110",
203− ),
204− ];
205−
206− for (original, amount, expected) in tests {
207− assert_eq!(increment(original, amount).unwrap(), expected);
208− }
209− }
210−
211− #[test]
212− fn test_increment_with_separators() {
213− let tests = [
214− ("999_999", 1, "1_000_000"),
215− ("1_000_000", -1, "999_999"),
216− ("-999_999", -1, "-1_000_000"),
217− ("0x0000_0000_0001", 0x1_ffff_0000, "0x0001_ffff_0001"),
218− ("0x0000_0000", -1, "0x0000_0000"),
219− ("0x0000_0000_0000", -1, "0x0000_0000_0000"),
220− ("0b01111111_11111111", 1, "0b10000000_00000000"),
221− ("0b11111111_11111111", 1, "0b1_00000000_00000000"),
222− ];
223−
224− for (original, amount, expected) in tests {
225− assert_eq!(increment(original, amount).unwrap(), expected);
226− }
227− }
228−
229− #[test]
230− fn test_leading_and_trailing_separators_arent_a_match() {
231− assert_eq!(increment("9_", 1), None);
232− assert_eq!(increment("_9", 1), None);
233− assert_eq!(increment("_9_", 1), None);
234− }
235−}
helix-core/src/increment/mod.rs+5−7
@@ -1,10 +1,8 @@
1−mod date_time;
1+pub mod date_time;
2−mod integer;
2+pub mod number;
3
3
4−pub fn integer(selected_text: &str, amount: i64) -> Option<String> {
4+use crate::{Range, Tendril};
5− integer::increment(selected_text, amount)
6−}
7
5
8−pub fn date_time(selected_text: &str, amount: i64) -> Option<String> {
6+pub trait Increment {
9− date_time::increment(selected_text, amount)
7+ fn increment(&self, amount: i64) -> (Range, Tendril);
10}
8}
helix-core/src/increment/number.rsnew file+507
@@ -0,0 +1,507 @@
1+use std::borrow::Cow;
2+
3+use ropey::RopeSlice;
4+
5+use super::Increment;
6+
7+use crate::{
8+ textobject::{textobject_word, TextObject},
9+ Range, Tendril,
10+};
11+
12+#[derive(Debug, PartialEq, Eq)]
13+pub struct NumberIncrementor<'a> {
14+ value: i64,
15+ radix: u32,
16+ range: Range,
17+
18+ text: RopeSlice<'a>,
19+}
20+
21+impl<'a> NumberIncrementor<'a> {
22+ /// Return information about number under rang if there is one.
23+ pub fn from_range(text: RopeSlice, range: Range) -> Option<NumberIncrementor> {
24+ // If the cursor is on the minus sign of a number we want to get the word textobject to the
25+ // right of it.
26+ let range = if range.to() < text.len_chars()
27+ && range.to() - range.from() <= 1
28+ && text.char(range.from()) == '-'
29+ {
30+ Range::new(range.from() + 1, range.to() + 1)
31+ } else {
32+ range
33+ };
34+
35+ let range = textobject_word(text, range, TextObject::Inside, 1, false);
36+
37+ // If there is a minus sign to the left of the word object, we want to include it in the range.
38+ let range = if range.from() > 0 && text.char(range.from() - 1) == '-' {
39+ range.extend(range.from() - 1, range.from())
40+ } else {
41+ range
42+ };
43+
44+ let word: String = text
45+ .slice(range.from()..range.to())
46+ .chars()
47+ .filter(|&c| c != '_')
48+ .collect();
49+ let (radix, prefixed) = if word.starts_with("0x") {
50+ (16, true)
51+ } else if word.starts_with("0o") {
52+ (8, true)
53+ } else if word.starts_with("0b") {
54+ (2, true)
55+ } else {
56+ (10, false)
57+ };
58+
59+ let number = if prefixed { &word[2..] } else { &word };
60+
61+ let value = i128::from_str_radix(number, radix).ok()?;
62+ if (value.is_positive() && value.leading_zeros() < 64)
63+ || (value.is_negative() && value.leading_ones() < 64)
64+ {
65+ return None;
66+ }
67+
68+ let value = value as i64;
69+ Some(NumberIncrementor {
70+ range,
71+ value,
72+ radix,
73+ text,
74+ })
75+ }
76+}
77+
78+impl<'a> Increment for NumberIncrementor<'a> {
79+ fn increment(&self, amount: i64) -> (Range, Tendril) {
80+ let old_text: Cow<str> = self.text.slice(self.range.from()..self.range.to()).into();
81+ let old_length = old_text.len();
82+ let new_value = self.value.wrapping_add(amount);
83+
84+ // Get separator indexes from right to left.
85+ let separator_rtl_indexes: Vec<usize> = old_text
86+ .chars()
87+ .rev()
88+ .enumerate()
89+ .filter_map(|(i, c)| if c == '_' { Some(i) } else { None })
90+ .collect();
91+
92+ let format_length = if self.radix == 10 {
93+ match (self.value.is_negative(), new_value.is_negative()) {
94+ (true, false) => old_length - 1,
95+ (false, true) => old_length + 1,
96+ _ => old_text.len(),
97+ }
98+ } else {
99+ old_text.len() - 2
100+ } - separator_rtl_indexes.len();
101+
102+ let mut new_text = match self.radix {
103+ 2 => format!("0b{:01$b}", new_value, format_length),
104+ 8 => format!("0o{:01$o}", new_value, format_length),
105+ 10 if old_text.starts_with('0') || old_text.starts_with("-0") => {
106+ format!("{:01$}", new_value, format_length)
107+ }
108+ 10 => format!("{}", new_value),
109+ 16 => {
110+ let (lower_count, upper_count): (usize, usize) =
111+ old_text.chars().skip(2).fold((0, 0), |(lower, upper), c| {
112+ (
113+ lower + c.is_ascii_lowercase().then(|| 1).unwrap_or(0),
114+ upper + c.is_ascii_uppercase().then(|| 1).unwrap_or(0),
115+ )
116+ });
117+ if upper_count > lower_count {
118+ format!("0x{:01$X}", new_value, format_length)
119+ } else {
120+ format!("0x{:01$x}", new_value, format_length)
121+ }
122+ }
123+ _ => unimplemented!("radix not supported: {}", self.radix),
124+ };
125+
126+ // Add separators from original number.
127+ for &rtl_index in &separator_rtl_indexes {
128+ if rtl_index < new_text.len() {
129+ let new_index = new_text.len() - rtl_index;
130+ new_text.insert(new_index, '_');
131+ }
132+ }
133+
134+ // Add in additional separators if necessary.
135+ if new_text.len() > old_length && !separator_rtl_indexes.is_empty() {
136+ let spacing = match separator_rtl_indexes.as_slice() {
137+ [.., b, a] => a - b - 1,
138+ _ => separator_rtl_indexes[0],
139+ };
140+
141+ let prefix_length = if self.radix == 10 { 0 } else { 2 };
142+ if let Some(mut index) = new_text.find('_') {
143+ while index - prefix_length > spacing {
144+ index -= spacing;
145+ new_text.insert(index, '_');
146+ }
147+ }
148+ }
149+
150+ (self.range, new_text.into())
151+ }
152+}
153+
154+#[cfg(test)]
155+mod test {
156+ use super::*;
157+ use crate::Rope;
158+
159+ #[test]
160+ fn test_decimal_at_point() {
161+ let rope = Rope::from_str("Test text 12345 more text.");
162+ let range = Range::point(12);
163+ assert_eq!(
164+ NumberIncrementor::from_range(rope.slice(..), range),
165+ Some(NumberIncrementor {
166+ range: Range::new(10, 15),
167+ value: 12345,
168+ radix: 10,
169+ text: rope.slice(..),
170+ })
171+ );
172+ }
173+
174+ #[test]
175+ fn test_uppercase_hexadecimal_at_point() {
176+ let rope = Rope::from_str("Test text 0x123ABCDEF more text.");
177+ let range = Range::point(12);
178+ assert_eq!(
179+ NumberIncrementor::from_range(rope.slice(..), range),
180+ Some(NumberIncrementor {
181+ range: Range::new(10, 21),
182+ value: 0x123ABCDEF,
183+ radix: 16,
184+ text: rope.slice(..),
185+ })
186+ );
187+ }
188+
189+ #[test]
190+ fn test_lowercase_hexadecimal_at_point() {
191+ let rope = Rope::from_str("Test text 0xfa3b4e more text.");
192+ let range = Range::point(12);
193+ assert_eq!(
194+ NumberIncrementor::from_range(rope.slice(..), range),
195+ Some(NumberIncrementor {
196+ range: Range::new(10, 18),
197+ value: 0xfa3b4e,
198+ radix: 16,
199+ text: rope.slice(..),
200+ })
201+ );
202+ }
203+
204+ #[test]
205+ fn test_octal_at_point() {
206+ let rope = Rope::from_str("Test text 0o1074312 more text.");
207+ let range = Range::point(12);
208+ assert_eq!(
209+ NumberIncrementor::from_range(rope.slice(..), range),
210+ Some(NumberIncrementor {
211+ range: Range::new(10, 19),
212+ value: 0o1074312,
213+ radix: 8,
214+ text: rope.slice(..),
215+ })
216+ );
217+ }
218+
219+ #[test]
220+ fn test_binary_at_point() {
221+ let rope = Rope::from_str("Test text 0b10111010010101 more text.");
222+ let range = Range::point(12);
223+ assert_eq!(
224+ NumberIncrementor::from_range(rope.slice(..), range),
225+ Some(NumberIncrementor {
226+ range: Range::new(10, 26),
227+ value: 0b10111010010101,
228+ radix: 2,
229+ text: rope.slice(..),
230+ })
231+ );
232+ }
233+
234+ #[test]
235+ fn test_negative_decimal_at_point() {
236+ let rope = Rope::from_str("Test text -54321 more text.");
237+ let range = Range::point(12);
238+ assert_eq!(
239+ NumberIncrementor::from_range(rope.slice(..), range),
240+ Some(NumberIncrementor {
241+ range: Range::new(10, 16),
242+ value: -54321,
243+ radix: 10,
244+ text: rope.slice(..),
245+ })
246+ );
247+ }
248+
249+ #[test]
250+ fn test_decimal_with_leading_zeroes_at_point() {
251+ let rope = Rope::from_str("Test text 000045326 more text.");
252+ let range = Range::point(12);
253+ assert_eq!(
254+ NumberIncrementor::from_range(rope.slice(..), range),
255+ Some(NumberIncrementor {
256+ range: Range::new(10, 19),
257+ value: 45326,
258+ radix: 10,
259+ text: rope.slice(..),
260+ })
261+ );
262+ }
263+
264+ #[test]
265+ fn test_negative_decimal_cursor_on_minus_sign() {
266+ let rope = Rope::from_str("Test text -54321 more text.");
267+ let range = Range::point(10);
268+ assert_eq!(
269+ NumberIncrementor::from_range(rope.slice(..), range),
270+ Some(NumberIncrementor {
271+ range: Range::new(10, 16),
272+ value: -54321,
273+ radix: 10,
274+ text: rope.slice(..),
275+ })
276+ );
277+ }
278+
279+ #[test]
280+ fn test_number_under_range_start_of_rope() {
281+ let rope = Rope::from_str("100");
282+ let range = Range::point(0);
283+ assert_eq!(
284+ NumberIncrementor::from_range(rope.slice(..), range),
285+ Some(NumberIncrementor {
286+ range: Range::new(0, 3),
287+ value: 100,
288+ radix: 10,
289+ text: rope.slice(..),
290+ })
291+ );
292+ }
293+
294+ #[test]
295+ fn test_number_under_range_end_of_rope() {
296+ let rope = Rope::from_str("100");
297+ let range = Range::point(2);
298+ assert_eq!(
299+ NumberIncrementor::from_range(rope.slice(..), range),
300+ Some(NumberIncrementor {
301+ range: Range::new(0, 3),
302+ value: 100,
303+ radix: 10,
304+ text: rope.slice(..),
305+ })
306+ );
307+ }
308+
309+ #[test]
310+ fn test_number_surrounded_by_punctuation() {
311+ let rope = Rope::from_str(",100;");
312+ let range = Range::point(1);
313+ assert_eq!(
314+ NumberIncrementor::from_range(rope.slice(..), range),
315+ Some(NumberIncrementor {
316+ range: Range::new(1, 4),
317+ value: 100,
318+ radix: 10,
319+ text: rope.slice(..),
320+ })
321+ );
322+ }
323+
324+ #[test]
325+ fn test_not_a_number_point() {
326+ let rope = Rope::from_str("Test text 45326 more text.");
327+ let range = Range::point(6);
328+ assert_eq!(NumberIncrementor::from_range(rope.slice(..), range), None);
329+ }
330+
331+ #[test]
332+ fn test_number_too_large_at_point() {
333+ let rope = Rope::from_str("Test text 0xFFFFFFFFFFFFFFFFF more text.");
334+ let range = Range::point(12);
335+ assert_eq!(NumberIncrementor::from_range(rope.slice(..), range), None);
336+ }
337+
338+ #[test]
339+ fn test_number_cursor_one_right_of_number() {
340+ let rope = Rope::from_str("100 ");
341+ let range = Range::point(3);
342+ assert_eq!(NumberIncrementor::from_range(rope.slice(..), range), None);
343+ }
344+
345+ #[test]
346+ fn test_number_cursor_one_left_of_number() {
347+ let rope = Rope::from_str(" 100");
348+ let range = Range::point(0);
349+ assert_eq!(NumberIncrementor::from_range(rope.slice(..), range), None);
350+ }
351+
352+ #[test]
353+ fn test_increment_basic_decimal_numbers() {
354+ let tests = [
355+ ("100", 1, "101"),
356+ ("100", -1, "99"),
357+ ("99", 1, "100"),
358+ ("100", 1000, "1100"),
359+ ("100", -1000, "-900"),
360+ ("-1", 1, "0"),
361+ ("-1", 2, "1"),
362+ ("1", -1, "0"),
363+ ("1", -2, "-1"),
364+ ];
365+
366+ for (original, amount, expected) in tests {
367+ let rope = Rope::from_str(original);
368+ let range = Range::point(0);
369+ assert_eq!(
370+ NumberIncrementor::from_range(rope.slice(..), range)
371+ .unwrap()
372+ .increment(amount)
373+ .1,
374+ expected.into()
375+ );
376+ }
377+ }
378+
379+ #[test]
380+ fn test_increment_basic_hexadedimal_numbers() {
381+ let tests = [
382+ ("0x0100", 1, "0x0101"),
383+ ("0x0100", -1, "0x00ff"),
384+ ("0x0001", -1, "0x0000"),
385+ ("0x0000", -1, "0xffffffffffffffff"),
386+ ("0xffffffffffffffff", 1, "0x0000000000000000"),
387+ ("0xffffffffffffffff", 2, "0x0000000000000001"),
388+ ("0xffffffffffffffff", -1, "0xfffffffffffffffe"),
389+ ("0xABCDEF1234567890", 1, "0xABCDEF1234567891"),
390+ ("0xabcdef1234567890", 1, "0xabcdef1234567891"),
391+ ];
392+
393+ for (original, amount, expected) in tests {
394+ let rope = Rope::from_str(original);
395+ let range = Range::point(0);
396+ assert_eq!(
397+ NumberIncrementor::from_range(rope.slice(..), range)
398+ .unwrap()
399+ .increment(amount)
400+ .1,
401+ expected.into()
402+ );
403+ }
404+ }
405+
406+ #[test]
407+ fn test_increment_basic_octal_numbers() {
408+ let tests = [
409+ ("0o0107", 1, "0o0110"),
410+ ("0o0110", -1, "0o0107"),
411+ ("0o0001", -1, "0o0000"),
412+ ("0o7777", 1, "0o10000"),
413+ ("0o1000", -1, "0o0777"),
414+ ("0o0107", 10, "0o0121"),
415+ ("0o0000", -1, "0o1777777777777777777777"),
416+ ("0o1777777777777777777777", 1, "0o0000000000000000000000"),
417+ ("0o1777777777777777777777", 2, "0o0000000000000000000001"),
418+ ("0o1777777777777777777777", -1, "0o1777777777777777777776"),
419+ ];
420+
421+ for (original, amount, expected) in tests {
422+ let rope = Rope::from_str(original);
423+ let range = Range::point(0);
424+ assert_eq!(
425+ NumberIncrementor::from_range(rope.slice(..), range)
426+ .unwrap()
427+ .increment(amount)
428+ .1,
429+ expected.into()
430+ );
431+ }
432+ }
433+
434+ #[test]
435+ fn test_increment_basic_binary_numbers() {
436+ let tests = [
437+ ("0b00000100", 1, "0b00000101"),
438+ ("0b00000100", -1, "0b00000011"),
439+ ("0b00000100", 2, "0b00000110"),
440+ ("0b00000100", -2, "0b00000010"),
441+ ("0b00000001", -1, "0b00000000"),
442+ ("0b00111111", 10, "0b01001001"),
443+ ("0b11111111", 1, "0b100000000"),
444+ ("0b10000000", -1, "0b01111111"),
445+ (
446+ "0b0000",
447+ -1,
448+ "0b1111111111111111111111111111111111111111111111111111111111111111",
449+ ),
450+ (
451+ "0b1111111111111111111111111111111111111111111111111111111111111111",
452+ 1,
453+ "0b0000000000000000000000000000000000000000000000000000000000000000",
454+ ),
455+ (
456+ "0b1111111111111111111111111111111111111111111111111111111111111111",
457+ 2,
458+ "0b0000000000000000000000000000000000000000000000000000000000000001",
459+ ),
460+ (
461+ "0b1111111111111111111111111111111111111111111111111111111111111111",
462+ -1,
463+ "0b1111111111111111111111111111111111111111111111111111111111111110",
464+ ),
465+ ];
466+
467+ for (original, amount, expected) in tests {
468+ let rope = Rope::from_str(original);
469+ let range = Range::point(0);
470+ assert_eq!(
471+ NumberIncrementor::from_range(rope.slice(..), range)
472+ .unwrap()
473+ .increment(amount)
474+ .1,
475+ expected.into()
476+ );
477+ }
478+ }
479+
480+ #[test]
481+ fn test_increment_with_separators() {
482+ let tests = [
483+ ("999_999", 1, "1_000_000"),
484+ ("1_000_000", -1, "999_999"),
485+ ("-999_999", -1, "-1_000_000"),
486+ ("0x0000_0000_0001", 0x1_ffff_0000, "0x0001_ffff_0001"),
487+ ("0x0000_0000_0001", 0x1_ffff_0000, "0x0001_ffff_0001"),
488+ ("0x0000_0000_0001", 0x1_ffff_0000, "0x0001_ffff_0001"),
489+ ("0x0000_0000", -1, "0xffff_ffff_ffff_ffff"),
490+ ("0x0000_0000_0000", -1, "0xffff_ffff_ffff_ffff"),
491+ ("0b01111111_11111111", 1, "0b10000000_00000000"),
492+ ("0b11111111_11111111", 1, "0b1_00000000_00000000"),
493+ ];
494+
495+ for (original, amount, expected) in tests {
496+ let rope = Rope::from_str(original);
497+ let range = Range::point(0);
498+ assert_eq!(
499+ NumberIncrementor::from_range(rope.slice(..), range)
500+ .unwrap()
501+ .increment(amount)
502+ .1,
503+ expected.into()
504+ );
505+ }
506+ }
507+}
helix-core/src/indent.rs+224−1014
@@ -1,14 +1,8 @@
1−use std::{borrow::Cow, collections::HashMap};
2−
3−use tree_sitter::{Query, QueryCursor, QueryPredicateArg};
4−
5use crate::{
1use crate::{
6 chars::{char_is_line_ending, char_is_whitespace},
2 chars::{char_is_line_ending, char_is_whitespace},
7− find_first_non_whitespace_char,
3+ syntax::{IndentQuery, LanguageConfiguration, Syntax},
8− graphemes::{grapheme_width, tab_width_at},
9− syntax::{IndentationHeuristic, LanguageConfiguration, RopeProvider, Syntax},
10 tree_sitter::Node,
4 tree_sitter::Node,
11− Position, Rope, RopeGraphemes, RopeSlice,
5+ Rope, RopeSlice,
12};
6};
13
7
14/// Enum representing indentation style.
8/// Enum representing indentation style.
@@ -20,10 +14,6 @@ pub enum IndentStyle {
20 Spaces(u8),
14 Spaces(u8),
21}
15}
22
16
23−// 16 spaces
24−const INDENTS: &str = " ";
25−pub const MAX_INDENT: u8 = 16;
26−
27impl IndentStyle {
17impl IndentStyle {
28 /// Creates an `IndentStyle` from an indentation string.
18 /// Creates an `IndentStyle` from an indentation string.
29 ///
19 ///
@@ -32,10 +22,10 @@ impl IndentStyle {
32 #[inline]
22 #[inline]
33 pub fn from_str(indent: &str) -> Self {
23 pub fn from_str(indent: &str) -> Self {
34 // XXX: do we care about validating the input more than this? Probably not...?
24 // XXX: do we care about validating the input more than this? Probably not...?
35− debug_assert!(!indent.is_empty() && indent.len() <= MAX_INDENT as usize);
25+ debug_assert!(!indent.is_empty() && indent.len() <= 8);
36
26
37 if indent.starts_with(' ') {
27 if indent.starts_with(' ') {
38− IndentStyle::Spaces(indent.len().clamp(1, MAX_INDENT as usize) as u8)
28+ IndentStyle::Spaces(indent.len() as u8)
39 } else {
29 } else {
40 IndentStyle::Tabs
30 IndentStyle::Tabs
41 }
31 }
@@ -45,24 +35,23 @@ impl IndentStyle {
45 pub fn as_str(&self) -> &'static str {
35 pub fn as_str(&self) -> &'static str {
46 match *self {
36 match *self {
47 IndentStyle::Tabs => "\t",
37 IndentStyle::Tabs => "\t",
38+ IndentStyle::Spaces(1) => " ",
39+ IndentStyle::Spaces(2) => " ",
40+ IndentStyle::Spaces(3) => " ",
41+ IndentStyle::Spaces(4) => " ",
42+ IndentStyle::Spaces(5) => " ",
43+ IndentStyle::Spaces(6) => " ",
44+ IndentStyle::Spaces(7) => " ",
45+ IndentStyle::Spaces(8) => " ",
46+
47+ // Unsupported indentation style. This should never happen,
48+ // but just in case fall back to two spaces.
48 IndentStyle::Spaces(n) => {
49 IndentStyle::Spaces(n) => {
49− // Unsupported indentation style. This should never happen,
50+ debug_assert!(n > 0 && n <= 8); // Always triggers. `debug_panic!()` wanted.
50− debug_assert!(n > 0 && n <= MAX_INDENT);
51+ " "
51−
52− // Either way, clamp to the nearest supported value
53− let closest_n = n.clamp(1, MAX_INDENT) as usize;
54− &INDENTS[0..closest_n]
55 }
52 }
56 }
53 }
57 }
54 }
58−
59− #[inline]
60− pub fn indent_width(&self, tab_width: usize) -> usize {
61− match *self {
62− IndentStyle::Tabs => tab_width,
63− IndentStyle::Spaces(width) => width as usize,
64− }
65− }
66}
55}
67
56
68/// Attempts to detect the indentation style used in a document.
57/// Attempts to detect the indentation style used in a document.
@@ -73,9 +62,9 @@ pub fn auto_detect_indent_style(document_text: &Rope) -> Option<IndentStyle> {
73 // Build a histogram of the indentation *increases* between
62 // Build a histogram of the indentation *increases* between
74 // subsequent lines, ignoring lines that are all whitespace.
63 // subsequent lines, ignoring lines that are all whitespace.
75 //
64 //
76− // Index 0 is for tabs, the rest are 1-MAX_INDENT spaces.
65+ // Index 0 is for tabs, the rest are 1-8 spaces.
77− let histogram: [usize; MAX_INDENT as usize + 1] = {
66+ let histogram: [usize; 9] = {
78− let mut histogram = [0; MAX_INDENT as usize + 1];
67+ let mut histogram = [0; 9];
79 let mut prev_line_is_tabs = false;
68 let mut prev_line_is_tabs = false;
80 let mut prev_line_leading_count = 0usize;
69 let mut prev_line_leading_count = 0usize;
81
70
@@ -134,7 +123,7 @@ pub fn auto_detect_indent_style(document_text: &Rope) -> Option<IndentStyle> {
134 histogram[0] += 1;
123 histogram[0] += 1;
135 } else {
124 } else {
136 let amount = leading_count - prev_line_leading_count;
125 let amount = leading_count - prev_line_leading_count;
137− if amount <= MAX_INDENT as usize {
126+ if amount <= 8 {
138 histogram[amount] += 1;
127 histogram[amount] += 1;
139 }
128 }
140 }
129 }
@@ -184,831 +173,119 @@ pub fn auto_detect_indent_style(document_text: &Rope) -> Option<IndentStyle> {
184
173
185/// To determine indentation of a newly inserted line, figure out the indentation at the last col
174/// To determine indentation of a newly inserted line, figure out the indentation at the last col
186/// of the previous line.
175/// of the previous line.
187−pub fn indent_level_for_line(line: RopeSlice, tab_width: usize, indent_width: usize) -> usize {
176+pub fn indent_level_for_line(line: RopeSlice, tab_width: usize) -> usize {
188 let mut len = 0;
177 let mut len = 0;
189 for ch in line.chars() {
178 for ch in line.chars() {
190 match ch {
179 match ch {
191− '\t' => len += tab_width_at(len, tab_width as u16),
180+ '\t' => len += tab_width,
192 ' ' => len += 1,
181 ' ' => len += 1,
193 _ => break,
182 _ => break,
194 }
183 }
195 }
184 }
196
185
197− len / indent_width
186+ len / tab_width
198}
187}
199
188
200−/// Create a string of tabs & spaces that has the same visual width as the given RopeSlice (independent of the tab width).
189+/// Find the highest syntax node at position.
201−fn whitespace_with_same_width(text: RopeSlice) -> String {
190+/// This is to identify the column where this node (e.g., an HTML closing tag) ends.
202− let mut s = String::new();
191+fn get_highest_syntax_node_at_bytepos(syntax: &Syntax, pos: usize) -> Option<Node> {
203− for grapheme in RopeGraphemes::new(text) {
192+ let tree = syntax.tree();
204− if grapheme == "\t" {
205− s.push('\t');
206− } else {
207− s.extend(std::iter::repeat(' ').take(grapheme_width(&Cow::from(grapheme))));
208− }
209− }
210− s
211−}
212
193
213−fn add_indent_level(
194+ // named_descendant
214− mut base_indent: String,
195+ let mut node = match tree.root_node().descendant_for_byte_range(pos, pos) {
215− added_indent_level: isize,
196+ Some(node) => node,
216− indent_style: &IndentStyle,
197+ None => return None,
217− tab_width: usize,
198+ };
218−) -> String {
219− if added_indent_level >= 0 {
220− // Adding a non-negative indent is easy, we can simply append the indent string
221− base_indent.push_str(&indent_style.as_str().repeat(added_indent_level as usize));
222− base_indent
223− } else {
224− // In this case, we want to return a prefix of `base_indent`.
225− // Since the width of a tab depends on its offset, we cannot simply iterate over
226− // the chars of `base_indent` in reverse until we have the desired indent reduction,
227− // instead we iterate over them twice in forward direction.
228− let base_indent_rope = RopeSlice::from(base_indent.as_str());
229− #[allow(deprecated)]
230− let base_indent_width =
231− crate::visual_coords_at_pos(base_indent_rope, base_indent_rope.len_chars(), tab_width)
232− .col;
233− let target_indent_width = base_indent_width
234− .saturating_sub((-added_indent_level) as usize * indent_style.indent_width(tab_width));
235− #[allow(deprecated)]
236− let char_end_idx = crate::pos_at_visual_coords(
237− base_indent_rope,
238− Position {
239− row: 0,
240− col: target_indent_width,
241− },
242− tab_width,
243− );
244− let byte_end_idx = base_indent_rope.char_to_byte(char_end_idx);
245− base_indent.truncate(byte_end_idx);
246− base_indent
247− }
248−}
249
199
250−/// Computes for node and all ancestors whether they are the first node on their line.
200+ while let Some(parent) = node.parent() {
251−/// The first entry in the return value represents the root node, the last one the node itself
201+ if parent.start_byte() == node.start_byte() {
252−fn get_first_in_line(mut node: Node, new_line_byte_pos: Option<usize>) -> Vec<bool> {
202+ node = parent
253− let mut first_in_line = Vec::new();
254− loop {
255− if let Some(prev) = node.prev_sibling() {
256− // If we insert a new line, the first node at/after the cursor is considered to be the first in its line
257− let first = prev.end_position().row != node.start_position().row
258− || new_line_byte_pos.map_or(false, |byte_pos| {
259− node.start_byte() >= byte_pos && prev.start_byte() < byte_pos
260− });
261− first_in_line.push(Some(first));
262− } else {
263− // Nodes that have no previous siblings are first in their line if and only if their parent is
264− // (which we don't know yet)
265− first_in_line.push(None);
266− }
267− if let Some(parent) = node.parent() {
268− node = parent;
269 } else {
203 } else {
270 break;
204 break;
271 }
205 }
272 }
206 }
273
207
274− let mut result = Vec::with_capacity(first_in_line.len());
208+ Some(node)
275− let mut parent_is_first = true; // The root node is by definition the first node in its line
276− for first in first_in_line.into_iter().rev() {
277− if let Some(first) = first {
278− result.push(first);
279− parent_is_first = first;
280− } else {
281− result.push(parent_is_first);
282− }
283− }
284− result
285−}
286−
287−/// The total indent for some line of code.
288−/// This is usually constructed in one of 2 ways:
289−/// - Successively add indent captures to get the (added) indent from a single line
290−/// - Successively add the indent results for each line
291−/// The string that this indentation defines starts with the string contained in the align field (unless it is None), followed by:
292−/// - max(0, indent - outdent) tabs, if tabs are used for indentation
293−/// - max(0, indent - outdent)*indent_width spaces, if spaces are used for indentation
294−#[derive(Default, Debug, PartialEq, Eq, Clone)]
295−pub struct Indentation<'a> {
296− indent: usize,
297− indent_always: usize,
298− outdent: usize,
299− outdent_always: usize,
300− /// The alignment, as a string containing only tabs & spaces. Storing this as a string instead of e.g.
301− /// the (visual) width ensures that the alignment is preserved even if the tab width changes.
302− align: Option<RopeSlice<'a>>,
303−}
304−
305−impl<'a> Indentation<'a> {
306− /// Add some other [Indentation] to this.
307− /// The added indent should be the total added indent from one line.
308− /// Indent should always be added starting from the bottom (or equivalently, the innermost tree-sitter node).
309− fn add_line(&mut self, added: Indentation<'a>) {
310− // Align overrides the indent from outer scopes.
311− if self.align.is_some() {
312− return;
313− }
314− if added.align.is_some() {
315− self.align = added.align;
316− return;
317− }
318− self.indent += added.indent;
319− self.indent_always += added.indent_always;
320− self.outdent += added.outdent;
321− self.outdent_always += added.outdent_always;
322− }
323−
324− /// Add an indent capture to this indent.
325− /// Only captures that apply to the same line should be added together in this way (otherwise use `add_line`)
326− /// and the captures should be added starting from the innermost tree-sitter node (currently this only matters
327− /// if multiple `@align` patterns occur on the same line).
328− fn add_capture(&mut self, added: IndentCaptureType<'a>) {
329− match added {
330− IndentCaptureType::Indent => {
331− if self.indent_always == 0 {
332− self.indent = 1;
333− }
334− }
335− IndentCaptureType::IndentAlways => {
336− // any time we encounter an `indent.always` on the same line, we
337− // want to cancel out all regular indents
338− self.indent_always += 1;
339− self.indent = 0;
340− }
341− IndentCaptureType::Outdent => {
342− if self.outdent_always == 0 {
343− self.outdent = 1;
344− }
345− }
346− IndentCaptureType::OutdentAlways => {
347− self.outdent_always += 1;
348− self.outdent = 0;
349− }
350− IndentCaptureType::Align(align) => {
351− if self.align.is_none() {
352− self.align = Some(align);
353− }
354− }
355− }
356− }
357− fn net_indent(&self) -> isize {
358− (self.indent + self.indent_always) as isize
359− - ((self.outdent + self.outdent_always) as isize)
360− }
361− /// Convert `self` into a string, taking into account the computed and actual indentation of some other line.
362− fn relative_indent(
363− &self,
364− other_computed_indent: &Self,
365− other_leading_whitespace: RopeSlice,
366− indent_style: &IndentStyle,
367− tab_width: usize,
368− ) -> Option<String> {
369− if self.align == other_computed_indent.align {
370− // If self and baseline are either not aligned to anything or both aligned the same way,
371− // we can simply take `other_leading_whitespace` and add some indent / outdent to it (in the second
372− // case, the alignment should already be accounted for in `other_leading_whitespace`).
373− let indent_diff = self.net_indent() - other_computed_indent.net_indent();
374− Some(add_indent_level(
375− String::from(other_leading_whitespace),
376− indent_diff,
377− indent_style,
378− tab_width,
379− ))
380− } else {
381− // If the alignment of both lines is different, we cannot compare their indentation in any meaningful way
382− None
383− }
384− }
385− pub fn to_string(&self, indent_style: &IndentStyle, tab_width: usize) -> String {
386− add_indent_level(
387− self.align
388− .map_or_else(String::new, whitespace_with_same_width),
389− self.net_indent(),
390− indent_style,
391− tab_width,
392− )
393− }
394−}
395−
396−/// An indent definition which corresponds to a capture from the indent query
397−#[derive(Debug)]
398−struct IndentCapture<'a> {
399− capture_type: IndentCaptureType<'a>,
400− scope: IndentScope,
401−}
402−#[derive(Debug, Clone, PartialEq)]
403−enum IndentCaptureType<'a> {
404− Indent,
405− IndentAlways,
406− Outdent,
407− OutdentAlways,
408− /// Alignment given as a string of whitespace
409− Align(RopeSlice<'a>),
410−}
411−
412−impl<'a> IndentCaptureType<'a> {
413− fn default_scope(&self) -> IndentScope {
414− match self {
415− IndentCaptureType::Indent | IndentCaptureType::IndentAlways => IndentScope::Tail,
416− IndentCaptureType::Outdent | IndentCaptureType::OutdentAlways => IndentScope::All,
417− IndentCaptureType::Align(_) => IndentScope::All,
418− }
419− }
420−}
421−/// This defines which part of a node an [IndentCapture] applies to.
422−/// Each [IndentCaptureType] has a default scope, but the scope can be changed
423−/// with `#set!` property declarations.
424−#[derive(Debug, Clone, Copy)]
425−enum IndentScope {
426− /// The indent applies to the whole node
427− All,
428− /// The indent applies to everything except for the first line of the node
429− Tail,
430−}
431−
432−/// A capture from the indent query which does not define an indent but extends
433−/// the range of a node. This is used before the indent is calculated.
434−#[derive(Debug)]
435−enum ExtendCapture {
436− Extend,
437− PreventOnce,
438−}
439−
440−/// The result of running a tree-sitter indent query. This stores for
441−/// each node (identified by its ID) the relevant captures (already filtered
442−/// by predicates).
443−#[derive(Debug)]
444−struct IndentQueryResult<'a> {
445− indent_captures: HashMap<usize, Vec<IndentCapture<'a>>>,
446− extend_captures: HashMap<usize, Vec<ExtendCapture>>,
447−}
448−
449−fn get_node_start_line(node: Node, new_line_byte_pos: Option<usize>) -> usize {
450− let mut node_line = node.start_position().row;
451− // Adjust for the new line that will be inserted
452− if new_line_byte_pos.map_or(false, |pos| node.start_byte() >= pos) {
453− node_line += 1;
454− }
455− node_line
456}
209}
457−fn get_node_end_line(node: Node, new_line_byte_pos: Option<usize>) -> usize {
458− let mut node_line = node.end_position().row;
459− // Adjust for the new line that will be inserted (with a strict inequality since end_byte is exclusive)
460− if new_line_byte_pos.map_or(false, |pos| node.end_byte() > pos) {
461− node_line += 1;
462− }
463− node_line
464−}
465−
466−fn query_indents<'a>(
467− query: &Query,
468− syntax: &Syntax,
469− cursor: &mut QueryCursor,
470− text: RopeSlice<'a>,
471− range: std::ops::Range<usize>,
472− new_line_byte_pos: Option<usize>,
473−) -> IndentQueryResult<'a> {
474− let mut indent_captures: HashMap<usize, Vec<IndentCapture>> = HashMap::new();
475− let mut extend_captures: HashMap<usize, Vec<ExtendCapture>> = HashMap::new();
476− cursor.set_byte_range(range);
477
210
478− // Iterate over all captures from the query
211+/// Calculate the indentation at a given treesitter node.
479− for m in cursor.matches(query, syntax.tree().root_node(), RopeProvider(text)) {
212+/// If newline is false, then any "indent" nodes on the line are ignored ("outdent" still applies).
480− // Skip matches where not all custom predicates are fulfilled
213+/// This is because the indentation is only increased starting at the second line of the node.
481− if !query.general_predicates(m.pattern_index).iter().all(|pred| {
214+fn calculate_indentation(
482− match pred.operator.as_ref() {
215+ query: &IndentQuery,
483− "not-kind-eq?" => match (pred.args.get(0), pred.args.get(1)) {
216+ node: Option<Node>,
484− (
217+ line: usize,
485− Some(QueryPredicateArg::Capture(capture_idx)),
218+ newline: bool,
486− Some(QueryPredicateArg::String(kind)),
219+) -> usize {
487− ) => {
220+ let mut increment: isize = 0;
488− let node = m.nodes_for_capture_index(*capture_idx).next();
489− match node {
490− Some(node) => node.kind()!=kind.as_ref(),
491− _ => true,
492− }
493− }
494− _ => {
495− panic!("Invalid indent query: Arguments to \"not-kind-eq?\" must be a capture and a string");
496− }
497− },
498− "same-line?" | "not-same-line?" => {
499− match (pred.args.get(0), pred.args.get(1)) {
500− (
501− Some(QueryPredicateArg::Capture(capt1)),
502− Some(QueryPredicateArg::Capture(capt2))
503− ) => {
504− let n1 = m.nodes_for_capture_index(*capt1).next();
505− let n2 = m.nodes_for_capture_index(*capt2).next();
506− match (n1, n2) {
507− (Some(n1), Some(n2)) => {
508− let n1_line = get_node_start_line(n1, new_line_byte_pos);
509− let n2_line = get_node_start_line(n2, new_line_byte_pos);
510− let same_line = n1_line == n2_line;
511− same_line==(pred.operator.as_ref()=="same-line?")
512− }
513− _ => true,
514− }
515− }
516− _ => {
517− panic!("Invalid indent query: Arguments to \"{}\" must be 2 captures", pred.operator);
518− }
519− }
520− }
521− "one-line?" | "not-one-line?" => match pred.args.get(0) {
522− Some(QueryPredicateArg::Capture(capture_idx)) => {
523− let node = m.nodes_for_capture_index(*capture_idx).next();
524−
525− match node {
526− Some(node) => {
527− let (start_line, end_line) = (get_node_start_line(node,new_line_byte_pos), get_node_end_line(node, new_line_byte_pos));
528− let one_line = end_line == start_line;
529− one_line != (pred.operator.as_ref() == "not-one-line?")
530− },
531− _ => true,
532− }
533− }
534− _ => {
535− panic!("Invalid indent query: Arguments to \"not-kind-eq?\" must be a capture and a string");
536− }
537− },
538− _ => {
539− panic!(
540− "Invalid indent query: Unknown predicate (\"{}\")",
541− pred.operator
542− );
543− }
544− }
545− }) {
546− continue;
547− }
548− // A list of pairs (node_id, indent_capture) that are added by this match.
549− // They cannot be added to indent_captures immediately since they may depend on other captures (such as an @anchor).
550− let mut added_indent_captures: Vec<(usize, IndentCapture)> = Vec::new();
551− // The row/column position of the optional anchor in this query
552− let mut anchor: Option<tree_sitter::Node> = None;
553− for capture in m.captures {
554− let capture_name = query.capture_names()[capture.index as usize].as_str();
555− let capture_type = match capture_name {
556− "indent" => IndentCaptureType::Indent,
557− "indent.always" => IndentCaptureType::IndentAlways,
558− "outdent" => IndentCaptureType::Outdent,
559− "outdent.always" => IndentCaptureType::OutdentAlways,
560− // The alignment will be updated to the correct value at the end, when the anchor is known.
561− "align" => IndentCaptureType::Align(RopeSlice::from("")),
562− "anchor" => {
563− if anchor.is_some() {
564− log::error!("Invalid indent query: Encountered more than one @anchor in the same match.")
565− } else {
566− anchor = Some(capture.node);
567− }
568− continue;
569− }
570− "extend" => {
571− extend_captures
572− .entry(capture.node.id())
573− .or_insert_with(|| Vec::with_capacity(1))
574− .push(ExtendCapture::Extend);
575− continue;
576− }
577− "extend.prevent-once" => {
578− extend_captures
579− .entry(capture.node.id())
580− .or_insert_with(|| Vec::with_capacity(1))
581− .push(ExtendCapture::PreventOnce);
582− continue;
583− }
584− _ => {
585− // Ignore any unknown captures (these may be needed for predicates such as #match?)
586− continue;
587− }
588− };
589− let scope = capture_type.default_scope();
590− let mut indent_capture = IndentCapture {
591− capture_type,
592− scope,
593− };
594− // Apply additional settings for this capture
595− for property in query.property_settings(m.pattern_index) {
596− match property.key.as_ref() {
597− "scope" => {
598− indent_capture.scope = match property.value.as_deref() {
599− Some("all") => IndentScope::All,
600− Some("tail") => IndentScope::Tail,
601− Some(s) => {
602− panic!("Invalid indent query: Unknown value for \"scope\" property (\"{}\")", s);
603− }
604− None => {
605− panic!(
606− "Invalid indent query: Missing value for \"scope\" property"
607− );
608− }
609− }
610− }
611− _ => {
612− panic!(
613− "Invalid indent query: Unknown property \"{}\"",
614− property.key
615− );
616− }
617− }
618− }
619− added_indent_captures.push((capture.node.id(), indent_capture))
620− }
621− for (node_id, mut capture) in added_indent_captures {
622− // Set the anchor for all align queries.
623− if let IndentCaptureType::Align(_) = capture.capture_type {
624− let anchor = match anchor {
625− None => {
626− log::error!(
627− "Invalid indent query: @align requires an accompanying @anchor."
628− );
629− continue;
630− }
631− Some(anchor) => anchor,
632− };
633− capture.capture_type = IndentCaptureType::Align(
634− text.line(anchor.start_position().row)
635− .byte_slice(0..anchor.start_position().column),
636− );
637− }
638− indent_captures
639− .entry(node_id)
640− .or_insert_with(|| Vec::with_capacity(1))
641− .push(capture);
642− }
643− }
644
221
645− let result = IndentQueryResult {
222+ let mut node = match node {
646− indent_captures,
223+ Some(node) => node,
647− extend_captures,
224+ None => return 0,
648 };
225 };
649
226
650− log::trace!("indent result = {:?}", result);
227+ let mut current_line = line;
651−
228+ let mut consider_indent = newline;
652− result
229+ let mut increment_from_line: isize = 0;
653−}
654−
655−/// Handle extend queries. deepest_preceding is the deepest descendant of node that directly precedes the cursor position.
656−/// Any ancestor of deepest_preceding which is also a descendant of node may be "extended". In that case, node will be updated,
657−/// so that the indent computation starts with the correct syntax node.
658−fn extend_nodes<'a>(
659− node: &mut Node<'a>,
660− mut deepest_preceding: Node<'a>,
661− extend_captures: &HashMap<usize, Vec<ExtendCapture>>,
662− text: RopeSlice,
663− line: usize,
664− tab_width: usize,
665− indent_width: usize,
666−) {
667− let mut stop_extend = false;
668
230
669− while deepest_preceding != *node {
231+ loop {
670− let mut extend_node = false;
232+ let node_kind = node.kind();
671− // This will be set to true if this node is captured, regardless of whether
233+ let start = node.start_position().row;
672− // it actually will be extended (e.g. because the cursor isn't indented
234+ if current_line != start {
673− // more than the node).
235+ // Indent/dedent by at most one per line:
674− let mut node_captured = false;
236+ // .map(|a| { <-- ({ is two scopes
675− if let Some(captures) = extend_captures.get(&deepest_preceding.id()) {
237+ // let len = 1; <-- indents one level
676− for capture in captures {
238+ // }) <-- }) is two scopes
677− match capture {
239+ if consider_indent || increment_from_line < 0 {
678− ExtendCapture::PreventOnce => {
240+ increment += increment_from_line.signum();
679− stop_extend = true;
680− }
681− ExtendCapture::Extend => {
682− node_captured = true;
683− // We extend the node if
684− // - the cursor is on the same line as the end of the node OR
685− // - the line that the cursor is on is more indented than the
686− // first line of the node
687− if deepest_preceding.end_position().row == line {
688− extend_node = true;
689− } else {
690− let cursor_indent =
691− indent_level_for_line(text.line(line), tab_width, indent_width);
692− let node_indent = indent_level_for_line(
693− text.line(deepest_preceding.start_position().row),
694− tab_width,
695− indent_width,
696− );
697− if cursor_indent > node_indent {
698− extend_node = true;
699− }
700− }
701− }
702− }
703 }
241 }
242+ increment_from_line = 0;
243+ current_line = start;
244+ consider_indent = true;
704 }
245 }
705− // If we encountered some `StopExtend` capture before, we don't
706− // extend the node even if we otherwise would
707− if node_captured && stop_extend {
708− stop_extend = false;
709− } else if extend_node && !stop_extend {
710− *node = deepest_preceding;
711− break;
712− }
713− // If the tree contains a syntax error, `deepest_preceding` may not
714− // have a parent despite being a descendant of `node`.
715− deepest_preceding = match deepest_preceding.parent() {
716− Some(parent) => parent,
717− None => return,
718− }
719− }
720−}
721−
722−/// Prepare an indent query by computing:
723−/// - The node from which to start the query (this is non-trivial due to `@extend` captures)
724−/// - The indent captures for all relevant nodes.
725−#[allow(clippy::too_many_arguments)]
726−fn init_indent_query<'a, 'b>(
727− query: &Query,
728− syntax: &'a Syntax,
729− text: RopeSlice<'b>,
730− tab_width: usize,
731− indent_width: usize,
732− line: usize,
733− byte_pos: usize,
734− new_line_byte_pos: Option<usize>,
735−) -> Option<(Node<'a>, HashMap<usize, Vec<IndentCapture<'b>>>)> {
736− // The innermost tree-sitter node which is considered for the indent
737− // computation. It may change if some predeceding node is extended
738− let mut node = syntax
739− .tree()
740− .root_node()
741− .descendant_for_byte_range(byte_pos, byte_pos)?;
742
246
743− let (query_result, deepest_preceding) = {
247+ if query.outdent.contains(node_kind) {
744− // The query range should intersect with all nodes directly preceding
248+ increment_from_line -= 1;
745− // the position of the indent query in case one of them is extended.
746− let mut deepest_preceding = None; // The deepest node preceding the indent query position
747− let mut tree_cursor = node.walk();
748− for child in node.children(&mut tree_cursor) {
749− if child.byte_range().end <= byte_pos {
750− deepest_preceding = Some(child);
751− }
752 }
249 }
753− deepest_preceding = deepest_preceding.map(|mut prec| {
250+ if query.indent.contains(node_kind) {
754− // Get the deepest directly preceding node
251+ increment_from_line += 1;
755− while prec.child_count() > 0 {
756− prec = prec.child(prec.child_count() - 1).unwrap();
757− }
758− prec
759− });
760− let query_range = deepest_preceding
761− .map(|prec| prec.byte_range().end - 1..byte_pos + 1)
762− .unwrap_or(byte_pos..byte_pos + 1);
763−
764− crate::syntax::PARSER.with(|ts_parser| {
765− let mut ts_parser = ts_parser.borrow_mut();
766− let mut cursor = ts_parser.cursors.pop().unwrap_or_else(QueryCursor::new);
767− let query_result = query_indents(
768− query,
769− syntax,
770− &mut cursor,
771− text,
772− query_range,
773− new_line_byte_pos,
774− );
775− ts_parser.cursors.push(cursor);
776− (query_result, deepest_preceding)
777− })
778− };
779− let extend_captures = query_result.extend_captures;
780−
781− // Check for extend captures, potentially changing the node that the indent calculation starts with
782− if let Some(deepest_preceding) = deepest_preceding {
783− extend_nodes(
784− &mut node,
785− deepest_preceding,
786− &extend_captures,
787− text,
788− line,
789− tab_width,
790− indent_width,
791− );
792− }
793− Some((node, query_result.indent_captures))
794−}
795−
796−/// Use the syntax tree to determine the indentation for a given position.
797−/// This can be used in 2 ways:
798−///
799−/// - To get the correct indentation for an existing line (new_line=false), not necessarily equal to the current indentation.
800−/// - In this case, pos should be inside the first tree-sitter node on that line.
801−/// In most cases, this can just be the first non-whitespace on that line.
802−/// - To get the indentation for a new line (new_line=true). This behaves like the first usecase if the part of the current line
803−/// after pos were moved to a new line.
804−///
805−/// The indentation is determined by traversing all the tree-sitter nodes containing the position.
806−/// Each of these nodes produces some [Indentation] for:
807−///
808−/// - The line of the (beginning of the) node. This is defined by the scope `all` if this is the first node on its line.
809−/// - The line after the node. This is defined by:
810−/// - The scope `tail`.
811−/// - The scope `all` if this node is not the first node on its line.
812−/// Intuitively, `all` applies to everything contained in this node while `tail` applies to everything except for the first line of the node.
813−/// The indents from different nodes for the same line are then combined.
814−/// The result [Indentation] is simply the sum of the [Indentation] for all lines.
815−///
816−/// Specifying which line exactly an [Indentation] applies to is important because indents on the same line combine differently than indents on different lines:
817−/// ```ignore
818−/// some_function(|| {
819−/// // Both the function parameters as well as the contained block should be indented.
820−/// // Because they are on the same line, this only yields one indent level
821−/// });
822−/// ```
823−///
824−/// ```ignore
825−/// some_function(
826−/// param1,
827−/// || {
828−/// // Here we get 2 indent levels because the 'parameters' and the 'block' node begin on different lines
829−/// },
830−/// );
831−/// ```
832−#[allow(clippy::too_many_arguments)]
833−pub fn treesitter_indent_for_pos<'a>(
834− query: &Query,
835− syntax: &Syntax,
836− tab_width: usize,
837− indent_width: usize,
838− text: RopeSlice<'a>,
839− line: usize,
840− pos: usize,
841− new_line: bool,
842−) -> Option<Indentation<'a>> {
843− let byte_pos = text.char_to_byte(pos);
844− let new_line_byte_pos = new_line.then_some(byte_pos);
845− let (mut node, mut indent_captures) = init_indent_query(
846− query,
847− syntax,
848− text,
849− tab_width,
850− indent_width,
851− line,
852− byte_pos,
853− new_line_byte_pos,
854− )?;
855− let mut first_in_line = get_first_in_line(node, new_line.then_some(byte_pos));
856−
857− let mut result = Indentation::default();
858− // We always keep track of all the indent changes on one line, in order to only indent once
859− // even if there are multiple "indent" nodes on the same line
860− let mut indent_for_line = Indentation::default();
861− let mut indent_for_line_below = Indentation::default();
862−
863− loop {
864− // This can safely be unwrapped because `first_in_line` contains
865− // one entry for each ancestor of the node (which is what we iterate over)
866− let is_first = *first_in_line.last().unwrap();
867−
868− // Apply all indent definitions for this node.
869− // Since we only iterate over each node once, we can remove the
870− // corresponding captures from the HashMap to avoid cloning them.
871− if let Some(definitions) = indent_captures.remove(&node.id()) {
872− for definition in definitions {
873− match definition.scope {
874− IndentScope::All => {
875− if is_first {
876− indent_for_line.add_capture(definition.capture_type);
877− } else {
878− indent_for_line_below.add_capture(definition.capture_type);
879− }
880− }
881− IndentScope::Tail => {
882− indent_for_line_below.add_capture(definition.capture_type);
883− }
884− }
885− }
886 }
252 }
887
253
888 if let Some(parent) = node.parent() {
254 if let Some(parent) = node.parent() {
889− let node_line = get_node_start_line(node, new_line_byte_pos);
890− let parent_line = get_node_start_line(parent, new_line_byte_pos);
891−
892− if node_line != parent_line {
893− // Don't add indent for the line below the line of the query
894− if node_line < line + (new_line as usize) {
895− result.add_line(indent_for_line_below);
896− }
897−
898− if node_line == parent_line + 1 {
899− indent_for_line_below = indent_for_line;
900− } else {
901− result.add_line(indent_for_line);
902− indent_for_line_below = Indentation::default();
903− }
904−
905− indent_for_line = Indentation::default();
906− }
907−
908 node = parent;
255 node = parent;
909− first_in_line.pop();
910 } else {
256 } else {
911− // Only add the indentation for the line below if that line
912− // is not after the line that the indentation is calculated for.
913− if (node.start_position().row < line)
914− || (new_line && node.start_position().row == line && node.start_byte() < byte_pos)
915− {
916− result.add_line(indent_for_line_below);
917− }
918− result.add_line(indent_for_line);
919 break;
257 break;
920 }
258 }
921 }
259 }
922− Some(result)
260+ if consider_indent || increment_from_line < 0 {
261+ increment += increment_from_line.signum();
262+ }
263+ increment.max(0) as usize
923}
264}
924
265
925−/// Returns the indentation for a new line.
266+// TODO: two usecases: if we are triggering this for a new, blank line:
926−/// This is done either using treesitter, or if that's not available by copying the indentation from the current line
267+// - it should return 0 when mass indenting stuff
927−#[allow(clippy::too_many_arguments)]
268+// - it should look up the wrapper node and count it too when we press o/O
928−pub fn indent_for_newline(
269+pub fn suggested_indent_for_pos(
929 language_config: Option<&LanguageConfiguration>,
270 language_config: Option<&LanguageConfiguration>,
930 syntax: Option<&Syntax>,
271 syntax: Option<&Syntax>,
931− indent_heuristic: &IndentationHeuristic,
932− indent_style: &IndentStyle,
933− tab_width: usize,
934 text: RopeSlice,
272 text: RopeSlice,
935− line_before: usize,
273+ pos: usize,
936− line_before_end_pos: usize,
274+ line: usize,
937− current_line: usize,
275+ new_line: bool,
938−) -> String {
276+) -> Option<usize> {
939− let indent_width = indent_style.indent_width(tab_width);
277+ if let (Some(query), Some(syntax)) = (
940− if let (
941− IndentationHeuristic::TreeSitter | IndentationHeuristic::Hybrid,
942− Some(query),
943− Some(syntax),
944− ) = (
945− indent_heuristic,
946 language_config.and_then(|config| config.indent_query()),
278 language_config.and_then(|config| config.indent_query()),
947 syntax,
279 syntax,
948 ) {
280 ) {
949− if let Some(indent) = treesitter_indent_for_pos(
281+ let byte_start = text.char_to_byte(pos);
950− query,
282+ let node = get_highest_syntax_node_at_bytepos(syntax, byte_start);
951− syntax,
283+ // TODO: special case for comments
952− tab_width,
284+ // TODO: if preserve_leading_whitespace
953− indent_width,
285+ Some(calculate_indentation(query, node, line, new_line))
954− text,
286+ } else {
955− line_before,
287+ None
956− line_before_end_pos,
957− true,
958− ) {
959− if *indent_heuristic == IndentationHeuristic::Hybrid {
960− // We want to compute the indentation not only based on the
961− // syntax tree but also on the actual indentation of a previous
962− // line. This makes indentation computation more resilient to
963− // incomplete queries, incomplete source code & differing indentation
964− // styles for the same language.
965− // However, using the indent of a previous line as a baseline may not
966− // make sense, e.g. if it has a different alignment than the new line.
967− // In order to prevent edge cases with long running times, we only try
968− // a constant number of (non-empty) lines.
969− const MAX_ATTEMPTS: usize = 4;
970− let mut num_attempts = 0;
971− for line_idx in (0..=line_before).rev() {
972− let line = text.line(line_idx);
973− let first_non_whitespace_char = match find_first_non_whitespace_char(line) {
974− Some(i) => i,
975− None => {
976− continue;
977− }
978− };
979− if let Some(indent) = (|| {
980− let computed_indent = treesitter_indent_for_pos(
981− query,
982− syntax,
983− tab_width,
984− indent_width,
985− text,
986− line_idx,
987− text.line_to_char(line_idx) + first_non_whitespace_char,
988− false,
989− )?;
990− let leading_whitespace = line.slice(0..first_non_whitespace_char);
991− indent.relative_indent(
992− &computed_indent,
993− leading_whitespace,
994− indent_style,
995− tab_width,
996− )
997− })() {
998− return indent;
999− }
1000− num_attempts += 1;
1001− if num_attempts == MAX_ATTEMPTS {
1002− break;
1003− }
1004− }
1005− }
1006− return indent.to_string(indent_style, tab_width);
1007− };
1008 }
288 }
1009− // Fallback in case we either don't have indent queries or they failed for some reason
1010− let indent_level = indent_level_for_line(text.line(current_line), tab_width, indent_width);
1011− indent_style.as_str().repeat(indent_level)
1012}
289}
1013
290
1014pub fn get_scopes(syntax: Option<&Syntax>, text: RopeSlice, pos: usize) -> Vec<&'static str> {
291pub fn get_scopes(syntax: Option<&Syntax>, text: RopeSlice, pos: usize) -> Vec<&'static str> {
@@ -1044,229 +321,162 @@ mod test {
1044 #[test]
321 #[test]
1045 fn test_indent_level() {
322 fn test_indent_level() {
1046 let tab_width = 4;
323 let tab_width = 4;
1047− let indent_width = 4;
1048 let line = Rope::from(" fn new"); // 8 spaces
324 let line = Rope::from(" fn new"); // 8 spaces
1049− assert_eq!(
325+ assert_eq!(indent_level_for_line(line.slice(..), tab_width), 2);
1050− indent_level_for_line(line.slice(..), tab_width, indent_width),
1051− 2
1052− );
1053 let line = Rope::from("\t\t\tfn new"); // 3 tabs
326 let line = Rope::from("\t\t\tfn new"); // 3 tabs
1054− assert_eq!(
327+ assert_eq!(indent_level_for_line(line.slice(..), tab_width), 3);
1055− indent_level_for_line(line.slice(..), tab_width, indent_width),
1056− 3
1057− );
1058 // mixed indentation
328 // mixed indentation
1059 let line = Rope::from("\t \tfn new"); // 1 tab, 4 spaces, tab
329 let line = Rope::from("\t \tfn new"); // 1 tab, 4 spaces, tab
1060− assert_eq!(
330+ assert_eq!(indent_level_for_line(line.slice(..), tab_width), 3);
1061− indent_level_for_line(line.slice(..), tab_width, indent_width),
1062− 3
1063− );
1064− }
1065−
1066− #[test]
1067− fn test_large_indent_level() {
1068− let tab_width = 16;
1069− let indent_width = 16;
1070− let line = Rope::from(" fn new"); // 16 spaces
1071− assert_eq!(
1072− indent_level_for_line(line.slice(..), tab_width, indent_width),
1073− 1
1074− );
1075− let line = Rope::from(" fn new"); // 32 spaces
1076− assert_eq!(
1077− indent_level_for_line(line.slice(..), tab_width, indent_width),
1078− 2
1079− );
1080 }
331 }
1081
332
1082 #[test]
333 #[test]
1083− fn add_capture() {
334+ fn test_suggested_indent_for_line() {
1084− let indent = || Indentation {
335+ let doc = Rope::from(
1085− indent: 1,
336+ "
1086− ..Default::default()
337+use std::{
1087− };
338+ io::{self, stdout, Stdout, Write},
1088− let indent_always = || Indentation {
339+ path::PathBuf,
1089− indent_always: 1,
340+ sync::Arc,
1090− ..Default::default()
341+ time::Duration,
1091− };
342+}
1092− let outdent = || Indentation {
343+mod test {
1093− outdent: 1,
344+ fn hello_world() {
1094− ..Default::default()
345+ 1 + 1;
1095− };
1096− let outdent_always = || Indentation {
1097− outdent_always: 1,
1098− ..Default::default()
1099− };
1100
346
1101− fn add_capture<'a>(
347+ let does_indentation_work = 1;
1102− mut indent: Indentation<'a>,
1103− capture: IndentCaptureType<'a>,
1104− ) -> Indentation<'a> {
1105− indent.add_capture(capture);
1106− indent
1107− }
1108
348
1109− // adding an indent to no indent makes an indent
349+ let test_function = function_with_param(this_param,
1110− assert_eq!(
350+ that_param
1111− indent(),
1112− add_capture(Indentation::default(), IndentCaptureType::Indent)
1113− );
1114− assert_eq!(
1115− indent_always(),
1116− add_capture(Indentation::default(), IndentCaptureType::IndentAlways)
1117− );
1118− assert_eq!(
1119− outdent(),
1120− add_capture(Indentation::default(), IndentCaptureType::Outdent)
1121− );
1122− assert_eq!(
1123− outdent_always(),
1124− add_capture(Indentation::default(), IndentCaptureType::OutdentAlways)
1125 );
351 );
1126
352
1127− // adding an indent to an already indented has no effect
353+ let test_function = function_with_param(
1128− assert_eq!(indent(), add_capture(indent(), IndentCaptureType::Indent));
354+ this_param,
1129− assert_eq!(
355+ that_param
1130− outdent(),
1131− add_capture(outdent(), IndentCaptureType::Outdent)
1132 );
356 );
1133
357
1134− // adding an always to a regular makes it always
358+ let test_function = function_with_proper_indent(param1,
1135− assert_eq!(
359+ param2,
1136− indent_always(),
1137− add_capture(indent(), IndentCaptureType::IndentAlways)
1138− );
1139− assert_eq!(
1140− outdent_always(),
1141− add_capture(outdent(), IndentCaptureType::OutdentAlways)
1142 );
360 );
1143
361
1144− // adding an always to an always is additive
362+ let selection = Selection::new(
1145− assert_eq!(
363+ changes
1146− Indentation {
364+ .clone()
1147− indent_always: 2,
365+ .map(|(start, end, text): (usize, usize, Option<Tendril>)| {
1148− ..Default::default()
366+ let len = text.map(|text| text.len()).unwrap() - 1; // minus newline
1149− },
367+ let pos = start + len;
1150− add_capture(indent_always(), IndentCaptureType::IndentAlways)
368+ Range::new(pos, pos)
1151− );
369+ })
1152− assert_eq!(
370+ .collect(),
1153− Indentation {
371+ 0,
1154− outdent_always: 2,
1155− ..Default::default()
1156− },
1157− add_capture(outdent_always(), IndentCaptureType::OutdentAlways)
1158 );
372 );
1159
373
1160− // adding regular to always should be associative
374+ return;
1161− assert_eq!(
1162− Indentation {
1163− indent_always: 1,
1164− ..Default::default()
1165− },
1166− add_capture(
1167− add_capture(indent(), IndentCaptureType::Indent),
1168− IndentCaptureType::IndentAlways
1169− )
1170− );
1171− assert_eq!(
1172− Indentation {
1173− indent_always: 1,
1174− ..Default::default()
1175− },
1176− add_capture(
1177− add_capture(indent(), IndentCaptureType::IndentAlways),
1178− IndentCaptureType::Indent
1179− )
1180− );
1181− assert_eq!(
1182− Indentation {
1183− outdent_always: 1,
1184− ..Default::default()
1185− },
1186− add_capture(
1187− add_capture(outdent(), IndentCaptureType::Outdent),
1188− IndentCaptureType::OutdentAlways
1189− )
1190− );
1191− assert_eq!(
1192− Indentation {
1193− outdent_always: 1,
1194− ..Default::default()
1195− },
1196− add_capture(
1197− add_capture(outdent(), IndentCaptureType::OutdentAlways),
1198− IndentCaptureType::Outdent
1199− )
1200− );
1201 }
375 }
376+}
1202
377
1203− #[test]
378+impl<A, D> MyTrait<A, D> for YourType
1204− fn test_relative_indent() {
379+where
1205− let indent_style = IndentStyle::Spaces(4);
380+ A: TraitB + TraitC,
1206− let tab_width: usize = 4;
381+ D: TraitE + TraitF,
1207− let no_align = [
382+{
1208− Indentation::default(),
383+
1209− Indentation {
384+}
1210− indent: 1,
385+#[test]
1211− ..Default::default()
386+//
1212− },
387+match test {
1213− Indentation {
388+ Some(a) => 1,
1214− indent: 5,
389+ None => {
1215− outdent: 1,
390+ unimplemented!()
1216− ..Default::default()
391+ }
1217− },
392+}
1218− ];
393+std::panic::set_hook(Box::new(move |info| {
1219− let align = no_align.clone().map(|indent| Indentation {
394+ hook(info);
1220− align: Some(RopeSlice::from("12345")),
395+}));
1221− ..indent
396+
1222− });
397+{ { {
1223− let different_align = Indentation {
398+ 1
1224− align: Some(RopeSlice::from("123456")),
399+}}}
1225− ..Default::default()
400+
1226− };
401+pub fn change<I>(document: &Document, changes: I) -> Self
402+where
403+ I: IntoIterator<Item = Change> + ExactSizeIterator,
404+{
405+ [
406+ 1,
407+ 2,
408+ 3,
409+ ];
410+ (
411+ 1,
412+ 2
413+ );
414+ true
415+}
416+",
417+ );
1227
418
1228− // Check that relative and absolute indentation computation are the same when the line we compare to is
419+ let doc = Rope::from(doc);
1229− // indented as we expect.
420+ use crate::diagnostic::Severity;
1230− let check_consistency = |indent: &Indentation, other: &Indentation| {
421+ use crate::syntax::{
1231− assert_eq!(
422+ Configuration, IndentationConfiguration, LanguageConfiguration, Loader,
1232− indent.relative_indent(
1233− other,
1234− RopeSlice::from(other.to_string(&indent_style, tab_width).as_str()),
1235− &indent_style,
1236− tab_width
1237− ),
1238− Some(indent.to_string(&indent_style, tab_width))
1239− );
1240 };
423 };
1241− for a in &no_align {
424+ use once_cell::sync::OnceCell;
1242− for b in &no_align {
425+ let loader = Loader::new(Configuration {
1243− check_consistency(a, b);
426+ language: vec![LanguageConfiguration {
1244− }
427+ scope: "source.rust".to_string(),
1245− }
428+ file_types: vec!["rs".to_string()],
1246− for a in &align {
429+ shebangs: vec![],
1247− for b in &align {
430+ language_id: "Rust".to_string(),
1248− check_consistency(a, b);
431+ highlight_config: OnceCell::new(),
432+ config: None,
433+ //
434+ injection_regex: None,
435+ roots: vec![],
436+ comment_token: None,
437+ auto_format: false,
438+ diagnostic_severity: Severity::Warning,
439+ tree_sitter_library: None,
440+ language_server: None,
441+ indent: Some(IndentationConfiguration {
442+ tab_width: 4,
443+ unit: String::from(" "),
444+ }),
445+ indent_query: OnceCell::new(),
446+ textobject_query: OnceCell::new(),
447+ }],
448+ });
449+
450+ // set runtime path so we can find the queries
451+ let mut runtime = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
452+ runtime.push("../runtime");
453+ std::env::set_var("HELIX_RUNTIME", runtime.to_str().unwrap());
454+
455+ let language_config = loader.language_config_for_scope("source.rust").unwrap();
456+ let highlight_config = language_config.highlight_config(&[]).unwrap();
457+ let syntax = Syntax::new(&doc, highlight_config.clone());
458+ let text = doc.slice(..);
459+ let tab_width = 4;
460+
461+ for i in 0..doc.len_lines() {
462+ let line = text.line(i);
463+ if let Some(pos) = crate::find_first_non_whitespace_char(line) {
464+ let indent = indent_level_for_line(line, tab_width);
465+ assert_eq!(
466+ suggested_indent_for_pos(
467+ Some(&language_config),
468+ Some(&syntax),
469+ text,
470+ text.line_to_char(i) + pos,
471+ i,
472+ false
473+ ),
474+ Some(indent),
475+ "line {}: \"{}\"",
476+ i,
477+ line
478+ );
1249 }
479 }
1250 }
480 }
1251−
1252− // Relative indent computation makes no sense if the alignment differs
1253− assert_eq!(
1254− align[0].relative_indent(
1255− &no_align[0],
1256− RopeSlice::from(" "),
1257− &indent_style,
1258− tab_width
1259− ),
1260− None
1261− );
1262− assert_eq!(
1263− align[0].relative_indent(
1264− &different_align,
1265− RopeSlice::from(" "),
1266− &indent_style,
1267− tab_width
1268− ),
1269− None
1270− );
1271 }
481 }
1272}
482}
helix-core/src/lib.rs+181−23
@@ -3,11 +3,8 @@ pub use encoding_rs as encoding;
3pub mod auto_pairs;
3pub mod auto_pairs;
4pub mod chars;
4pub mod chars;
5pub mod comment;
5pub mod comment;
6−pub mod config;
7pub mod diagnostic;
6pub mod diagnostic;
8pub mod diff;
7pub mod diff;
9−pub mod doc_formatter;
10−pub mod fuzzy;
11pub mod graphemes;
8pub mod graphemes;
12pub mod history;
9pub mod history;
13pub mod increment;
10pub mod increment;
@@ -19,16 +16,15 @@ pub mod movement;
19pub mod object;
16pub mod object;
20pub mod path;
17pub mod path;
21mod position;
18mod position;
19+pub mod register;
22pub mod search;
20pub mod search;
23pub mod selection;
21pub mod selection;
24pub mod shellwords;
22pub mod shellwords;
23+mod state;
25pub mod surround;
24pub mod surround;
26pub mod syntax;
25pub mod syntax;
27−pub mod test;
28−pub mod text_annotations;
29pub mod textobject;
26pub mod textobject;
30mod transaction;
27mod transaction;
31−pub mod wrap;
32
28
33pub mod unicode {
29pub mod unicode {
34 pub use unicode_general_category as category;
30 pub use unicode_general_category as category;
@@ -36,37 +32,199 @@ pub mod unicode {
36 pub use unicode_width as width;
32 pub use unicode_width as width;
37}
33}
38
34
39−pub use helix_loader::find_workspace;
35+static RUNTIME_DIR: once_cell::sync::Lazy<std::path::PathBuf> =
36+ once_cell::sync::Lazy::new(runtime_dir);
40
37
41pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option<usize> {
38pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option<usize> {
42 line.chars().position(|ch| !ch.is_whitespace())
39 line.chars().position(|ch| !ch.is_whitespace())
43}
40}
44−mod rope_reader;
45
41
46−pub use rope_reader::RopeReader;
42+/// Find project root.
47−pub use ropey::{self, str_utils, Rope, RopeBuilder, RopeSlice};
43+///
44+/// Order of detection:
45+/// * Top-most folder containing a root marker in current git repository
46+/// * Git repostory root if no marker detected
47+/// * Top-most folder containing a root marker if not git repository detected
48+/// * Current working directory as fallback
49+pub fn find_root(root: Option<&str>, root_markers: &[String]) -> Option<std::path::PathBuf> {
50+ let current_dir = std::env::current_dir().expect("unable to determine current directory");
48
51
49−// pub use tendril::StrTendril as Tendril;
52+ let root = match root {
50−pub use smartstring::SmartString;
53+ Some(root) => {
54+ let root = std::path::Path::new(root);
55+ if root.is_absolute() {
56+ root.to_path_buf()
57+ } else {
58+ current_dir.join(root)
59+ }
60+ }
61+ None => current_dir.clone(),
62+ };
51
63
52−pub type Tendril = SmartString<smartstring::LazyCompact>;
64+ let mut top_marker = None;
65+ for ancestor in root.ancestors() {
66+ for marker in root_markers {
67+ if ancestor.join(marker).exists() {
68+ top_marker = Some(ancestor);
69+ break;
70+ }
71+ }
72+ // don't go higher than repo
73+ if ancestor.join(".git").is_dir() {
74+ // Use workspace if detected from marker
75+ return Some(top_marker.unwrap_or(ancestor).to_path_buf());
76+ }
77+ }
78+
79+ // In absence of git repo, use workspace if detected
80+ if top_marker.is_some() {
81+ top_marker.map(|a| a.to_path_buf())
82+ } else {
83+ Some(current_dir)
84+ }
85+}
86+
87+pub fn runtime_dir() -> std::path::PathBuf {
88+ if let Ok(dir) = std::env::var("HELIX_RUNTIME") {
89+ return dir.into();
90+ }
91+
92+ const RT_DIR: &str = "runtime";
93+ let conf_dir = config_dir().join(RT_DIR);
94+ if conf_dir.exists() {
95+ return conf_dir;
96+ }
97+
98+ if let Ok(dir) = std::env::var("CARGO_MANIFEST_DIR") {
99+ // this is the directory of the crate being run by cargo, we need the workspace path so we take the parent
100+ return std::path::PathBuf::from(dir).parent().unwrap().join(RT_DIR);
101+ }
102+
103+ // fallback to location of the executable being run
104+ std::env::current_exe()
105+ .ok()
106+ .and_then(|path| path.parent().map(|path| path.to_path_buf().join(RT_DIR)))
107+ .unwrap()
108+}
109+
110+pub fn config_dir() -> std::path::PathBuf {
111+ // TODO: allow env var override
112+ let strategy = choose_base_strategy().expect("Unable to find the config directory!");
113+ let mut path = strategy.config_dir();
114+ path.push("helix");
115+ path
116+}
117+
118+pub fn cache_dir() -> std::path::PathBuf {
119+ // TODO: allow env var override
120+ let strategy = choose_base_strategy().expect("Unable to find the config directory!");
121+ let mut path = strategy.cache_dir();
122+ path.push("helix");
123+ path
124+}
125+
126+// right overrides left
127+pub fn merge_toml_values(left: toml::Value, right: toml::Value) -> toml::Value {
128+ use toml::Value;
129+
130+ fn get_name(v: &Value) -> Option<&str> {
131+ v.get("name").and_then(Value::as_str)
132+ }
133+
134+ match (left, right) {
135+ (Value::Array(mut left_items), Value::Array(right_items)) => {
136+ left_items.reserve(right_items.len());
137+ for rvalue in right_items {
138+ let lvalue = get_name(&rvalue)
139+ .and_then(|rname| left_items.iter().position(|v| get_name(v) == Some(rname)))
140+ .map(|lpos| left_items.remove(lpos));
141+ let mvalue = match lvalue {
142+ Some(lvalue) => merge_toml_values(lvalue, rvalue),
143+ None => rvalue,
144+ };
145+ left_items.push(mvalue);
146+ }
147+ Value::Array(left_items)
148+ }
149+ (Value::Table(mut left_map), Value::Table(right_map)) => {
150+ for (rname, rvalue) in right_map {
151+ match left_map.remove(&rname) {
152+ Some(lvalue) => {
153+ let merged_value = merge_toml_values(lvalue, rvalue);
154+ left_map.insert(rname, merged_value);
155+ }
156+ None => {
157+ left_map.insert(rname, rvalue);
158+ }
159+ }
160+ }
161+ Value::Table(left_map)
162+ }
163+ // Catch everything else we didn't handle, and use the right value
164+ (_, value) => value,
165+ }
166+}
167+
168+#[cfg(test)]
169+mod merge_toml_tests {
170+ use super::merge_toml_values;
171+
172+ #[test]
173+ fn language_tomls() {
174+ use toml::Value;
175+
176+ const USER: &str = "
177+ [[language]]
178+ name = \"nix\"
179+ test = \"bbb\"
180+ indent = { tab-width = 4, unit = \" \", test = \"aaa\" }
181+ ";
182+
183+ let base: Value = toml::from_slice(include_bytes!("../../languages.toml"))
184+ .expect("Couldn't parse built-in languages config");
185+ let user: Value = toml::from_str(USER).unwrap();
186+
187+ let merged = merge_toml_values(base, user);
188+ let languages = merged.get("language").unwrap().as_array().unwrap();
189+ let nix = languages
190+ .iter()
191+ .find(|v| v.get("name").unwrap().as_str().unwrap() == "nix")
192+ .unwrap();
193+ let nix_indent = nix.get("indent").unwrap();
194+
195+ // We changed tab-width and unit in indent so check them if they are the new values
196+ assert_eq!(
197+ nix_indent.get("tab-width").unwrap().as_integer().unwrap(),
198+ 4
199+ );
200+ assert_eq!(nix_indent.get("unit").unwrap().as_str().unwrap(), " ");
201+ // We added a new keys, so check them
202+ assert_eq!(nix.get("test").unwrap().as_str().unwrap(), "bbb");
203+ assert_eq!(nix_indent.get("test").unwrap().as_str().unwrap(), "aaa");
204+ // We didn't change comment-token so it should be same
205+ assert_eq!(nix.get("comment-token").unwrap().as_str().unwrap(), "#");
206+ }
207+}
208+
209+pub use etcetera::home_dir;
210+
211+use etcetera::base_strategy::{choose_base_strategy, BaseStrategy};
212+
213+pub use ropey::{Rope, RopeBuilder, RopeSlice};
214+
215+pub use tendril::StrTendril as Tendril;
53
216
54#[doc(inline)]
217#[doc(inline)]
55pub use {regex, tree_sitter};
218pub use {regex, tree_sitter};
56
219
57pub use graphemes::RopeGraphemes;
220pub use graphemes::RopeGraphemes;
58−pub use position::{
221+pub use position::{coords_at_pos, pos_at_coords, visual_coords_at_pos, Position};
59− char_idx_at_visual_offset, coords_at_pos, pos_at_coords, visual_offset_from_anchor,
60− visual_offset_from_block, Position, VisualOffsetError,
61−};
62−#[allow(deprecated)]
63−pub use position::{pos_at_visual_coords, visual_coords_at_pos};
64−
65pub use selection::{Range, Selection};
222pub use selection::{Range, Selection};
66−pub use smallvec::{smallvec, SmallVec};
223+pub use smallvec::SmallVec;
67pub use syntax::Syntax;
224pub use syntax::Syntax;
68
225
69pub use diagnostic::Diagnostic;
226pub use diagnostic::Diagnostic;
227+pub use state::State;
70
228
71−pub use line_ending::{LineEnding, NATIVE_LINE_ENDING};
229+pub use line_ending::{LineEnding, DEFAULT_LINE_ENDING};
72−pub use transaction::{Assoc, Change, ChangeSet, Deletion, Operation, Transaction};
230+pub use transaction::{Assoc, Change, ChangeSet, Operation, Transaction};
helix-core/src/line_ending.rs+15−78
@@ -1,27 +1,21 @@
1use crate::{Rope, RopeSlice};
1use crate::{Rope, RopeSlice};
2
2
3#[cfg(target_os = "windows")]
3#[cfg(target_os = "windows")]
4−pub const NATIVE_LINE_ENDING: LineEnding = LineEnding::Crlf;
4+pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::Crlf;
5#[cfg(not(target_os = "windows"))]
5#[cfg(not(target_os = "windows"))]
6−pub const NATIVE_LINE_ENDING: LineEnding = LineEnding::LF;
6+pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::LF;
7
7
8/// Represents one of the valid Unicode line endings.
8/// Represents one of the valid Unicode line endings.
9−#[derive(PartialEq, Eq, Copy, Clone, Debug)]
9+#[derive(PartialEq, Copy, Clone, Debug)]
10pub enum LineEnding {
10pub enum LineEnding {
11 Crlf, // CarriageReturn followed by LineFeed
11 Crlf, // CarriageReturn followed by LineFeed
12 LF, // U+000A -- LineFeed
12 LF, // U+000A -- LineFeed
13− #[cfg(feature = "unicode-lines")]
13+ VT, // U+000B -- VerticalTab
14− VT, // U+000B -- VerticalTab
14+ FF, // U+000C -- FormFeed
15− #[cfg(feature = "unicode-lines")]
15+ CR, // U+000D -- CarriageReturn
16− FF, // U+000C -- FormFeed
16+ Nel, // U+0085 -- NextLine
17− #[cfg(feature = "unicode-lines")]
17+ LS, // U+2028 -- Line Separator
18− CR, // U+000D -- CarriageReturn
18+ PS, // U+2029 -- ParagraphSeparator
19− #[cfg(feature = "unicode-lines")]
20− Nel, // U+0085 -- NextLine
21− #[cfg(feature = "unicode-lines")]
22− LS, // U+2028 -- Line Separator
23− #[cfg(feature = "unicode-lines")]
24− PS, // U+2029 -- ParagraphSeparator
25}
19}
26
20
27impl LineEnding {
21impl LineEnding {
@@ -38,17 +32,11 @@ impl LineEnding {
38 match self {
32 match self {
39 Self::Crlf => "\u{000D}\u{000A}",
33 Self::Crlf => "\u{000D}\u{000A}",
40 Self::LF => "\u{000A}",
34 Self::LF => "\u{000A}",
41− #[cfg(feature = "unicode-lines")]
42 Self::VT => "\u{000B}",
35 Self::VT => "\u{000B}",
43− #[cfg(feature = "unicode-lines")]
44 Self::FF => "\u{000C}",
36 Self::FF => "\u{000C}",
45− #[cfg(feature = "unicode-lines")]
46 Self::CR => "\u{000D}",
37 Self::CR => "\u{000D}",
47− #[cfg(feature = "unicode-lines")]
48 Self::Nel => "\u{0085}",
38 Self::Nel => "\u{0085}",
49− #[cfg(feature = "unicode-lines")]
50 Self::LS => "\u{2028}",
39 Self::LS => "\u{2028}",
51− #[cfg(feature = "unicode-lines")]
52 Self::PS => "\u{2029}",
40 Self::PS => "\u{2029}",
53 }
41 }
54 }
42 }
@@ -57,17 +45,11 @@ impl LineEnding {
57 pub const fn from_char(ch: char) -> Option<LineEnding> {
45 pub const fn from_char(ch: char) -> Option<LineEnding> {
58 match ch {
46 match ch {
59 '\u{000A}' => Some(LineEnding::LF),
47 '\u{000A}' => Some(LineEnding::LF),
60− #[cfg(feature = "unicode-lines")]
61 '\u{000B}' => Some(LineEnding::VT),
48 '\u{000B}' => Some(LineEnding::VT),
62− #[cfg(feature = "unicode-lines")]
63 '\u{000C}' => Some(LineEnding::FF),
49 '\u{000C}' => Some(LineEnding::FF),
64− #[cfg(feature = "unicode-lines")]
65 '\u{000D}' => Some(LineEnding::CR),
50 '\u{000D}' => Some(LineEnding::CR),
66− #[cfg(feature = "unicode-lines")]
67 '\u{0085}' => Some(LineEnding::Nel),
51 '\u{0085}' => Some(LineEnding::Nel),
68− #[cfg(feature = "unicode-lines")]
69 '\u{2028}' => Some(LineEnding::LS),
52 '\u{2028}' => Some(LineEnding::LS),
70− #[cfg(feature = "unicode-lines")]
71 '\u{2029}' => Some(LineEnding::PS),
53 '\u{2029}' => Some(LineEnding::PS),
72 // Not a line ending
54 // Not a line ending
73 _ => None,
55 _ => None,
@@ -83,17 +65,11 @@ impl LineEnding {
83 match g {
65 match g {
84 "\u{000D}\u{000A}" => Some(LineEnding::Crlf),
66 "\u{000D}\u{000A}" => Some(LineEnding::Crlf),
85 "\u{000A}" => Some(LineEnding::LF),
67 "\u{000A}" => Some(LineEnding::LF),
86− #[cfg(feature = "unicode-lines")]
87 "\u{000B}" => Some(LineEnding::VT),
68 "\u{000B}" => Some(LineEnding::VT),
88− #[cfg(feature = "unicode-lines")]
89 "\u{000C}" => Some(LineEnding::FF),
69 "\u{000C}" => Some(LineEnding::FF),
90− #[cfg(feature = "unicode-lines")]
91 "\u{000D}" => Some(LineEnding::CR),
70 "\u{000D}" => Some(LineEnding::CR),
92− #[cfg(feature = "unicode-lines")]
93 "\u{0085}" => Some(LineEnding::Nel),
71 "\u{0085}" => Some(LineEnding::Nel),
94− #[cfg(feature = "unicode-lines")]
95 "\u{2028}" => Some(LineEnding::LS),
72 "\u{2028}" => Some(LineEnding::LS),
96− #[cfg(feature = "unicode-lines")]
97 "\u{2029}" => Some(LineEnding::PS),
73 "\u{2029}" => Some(LineEnding::PS),
98 // Not a line ending
74 // Not a line ending
99 _ => None,
75 _ => None,
@@ -119,20 +95,13 @@ pub fn str_is_line_ending(s: &str) -> bool {
119 LineEnding::from_str(s).is_some()
95 LineEnding::from_str(s).is_some()
120}
96}
121
97
122−#[inline]
123−pub fn rope_is_line_ending(r: RopeSlice) -> bool {
124− r.chunks().all(str_is_line_ending)
125−}
126−
127/// Attempts to detect what line ending the passed document uses.
98/// Attempts to detect what line ending the passed document uses.
128pub fn auto_detect_line_ending(doc: &Rope) -> Option<LineEnding> {
99pub fn auto_detect_line_ending(doc: &Rope) -> Option<LineEnding> {
129 // Return first matched line ending. Not all possible line endings
100 // Return first matched line ending. Not all possible line endings
130 // are being matched, as they might be special-use only
101 // are being matched, as they might be special-use only
131 for line in doc.lines().take(100) {
102 for line in doc.lines().take(100) {
132 match get_line_ending(&line) {
103 match get_line_ending(&line) {
133− None => {}
104+ None | Some(LineEnding::VT) | Some(LineEnding::FF) | Some(LineEnding::PS) => {}
134− #[cfg(feature = "unicode-lines")]
135− Some(LineEnding::VT) | Some(LineEnding::FF) | Some(LineEnding::PS) => {}
136 ending => return ending,
105 ending => return ending,
137 }
106 }
138 }
107 }
@@ -159,19 +128,6 @@ pub fn get_line_ending(line: &RopeSlice) -> Option<LineEnding> {
159 LineEnding::from_str(g2).or_else(|| LineEnding::from_str(g1))
128 LineEnding::from_str(g2).or_else(|| LineEnding::from_str(g1))
160}
129}
161
130
162−#[cfg(not(feature = "unicode-lines"))]
163−/// Returns the passed line's line ending, if any.
164−pub fn get_line_ending_of_str(line: &str) -> Option<LineEnding> {
165− if line.ends_with("\u{000D}\u{000A}") {
166− Some(LineEnding::Crlf)
167− } else if line.ends_with('\u{000A}') {
168− Some(LineEnding::LF)
169− } else {
170− None
171− }
172−}
173−
174−#[cfg(feature = "unicode-lines")]
175/// Returns the passed line's line ending, if any.
131/// Returns the passed line's line ending, if any.
176pub fn get_line_ending_of_str(line: &str) -> Option<LineEnding> {
132pub fn get_line_ending_of_str(line: &str) -> Option<LineEnding> {
177 if line.ends_with("\u{000D}\u{000A}") {
133 if line.ends_with("\u{000D}\u{000A}") {
@@ -203,13 +159,6 @@ pub fn line_end_char_index(slice: &RopeSlice, line: usize) -> usize {
203 .unwrap_or(0)
159 .unwrap_or(0)
204}
160}
205
161
206−pub fn line_end_byte_index(slice: &RopeSlice, line: usize) -> usize {
207− slice.line_to_byte(line + 1)
208− - get_line_ending(&slice.line(line))
209− .map(|le| le.as_str().len())
210− .unwrap_or(0)
211−}
212−
213/// Fetches line `line_idx` from the passed rope slice, sans any line ending.
162/// Fetches line `line_idx` from the passed rope slice, sans any line ending.
214pub fn line_without_line_ending<'a>(slice: &'a RopeSlice, line_idx: usize) -> RopeSlice<'a> {
163pub fn line_without_line_ending<'a>(slice: &'a RopeSlice, line_idx: usize) -> RopeSlice<'a> {
215 let start = slice.line_to_char(line_idx);
164 let start = slice.line_to_char(line_idx);
@@ -262,7 +211,6 @@ mod line_ending_tests {
262
211
263 #[test]
212 #[test]
264 fn str_to_line_ending() {
213 fn str_to_line_ending() {
265− #[cfg(feature = "unicode-lines")]
266 assert_eq!(LineEnding::from_str("\r"), Some(LineEnding::CR));
214 assert_eq!(LineEnding::from_str("\r"), Some(LineEnding::CR));
267 assert_eq!(LineEnding::from_str("\n"), Some(LineEnding::LF));
215 assert_eq!(LineEnding::from_str("\n"), Some(LineEnding::LF));
268 assert_eq!(LineEnding::from_str("\r\n"), Some(LineEnding::Crlf));
216 assert_eq!(LineEnding::from_str("\r\n"), Some(LineEnding::Crlf));
@@ -272,7 +220,6 @@ mod line_ending_tests {
272 #[test]
220 #[test]
273 fn rope_slice_to_line_ending() {
221 fn rope_slice_to_line_ending() {
274 let r = Rope::from_str("hello\r\n");
222 let r = Rope::from_str("hello\r\n");
275− #[cfg(feature = "unicode-lines")]
276 assert_eq!(
223 assert_eq!(
277 LineEnding::from_rope_slice(&r.slice(5..6)),
224 LineEnding::from_rope_slice(&r.slice(5..6)),
278 Some(LineEnding::CR)
225 Some(LineEnding::CR)
@@ -291,7 +238,6 @@ mod line_ending_tests {
291 #[test]
238 #[test]
292 fn get_line_ending_rope_slice() {
239 fn get_line_ending_rope_slice() {
293 let r = Rope::from_str("Hello\rworld\nhow\r\nare you?");
240 let r = Rope::from_str("Hello\rworld\nhow\r\nare you?");
294− #[cfg(feature = "unicode-lines")]
295 assert_eq!(get_line_ending(&r.slice(..6)), Some(LineEnding::CR));
241 assert_eq!(get_line_ending(&r.slice(..6)), Some(LineEnding::CR));
296 assert_eq!(get_line_ending(&r.slice(..12)), Some(LineEnding::LF));
242 assert_eq!(get_line_ending(&r.slice(..12)), Some(LineEnding::LF));
297 assert_eq!(get_line_ending(&r.slice(..17)), Some(LineEnding::Crlf));
243 assert_eq!(get_line_ending(&r.slice(..17)), Some(LineEnding::Crlf));
@@ -301,28 +247,19 @@ mod line_ending_tests {
301 #[test]
247 #[test]
302 fn get_line_ending_str() {
248 fn get_line_ending_str() {
303 let text = "Hello\rworld\nhow\r\nare you?";
249 let text = "Hello\rworld\nhow\r\nare you?";
304− #[cfg(feature = "unicode-lines")]
305 assert_eq!(get_line_ending_of_str(&text[..6]), Some(LineEnding::CR));
250 assert_eq!(get_line_ending_of_str(&text[..6]), Some(LineEnding::CR));
306 assert_eq!(get_line_ending_of_str(&text[..12]), Some(LineEnding::LF));
251 assert_eq!(get_line_ending_of_str(&text[..12]), Some(LineEnding::LF));
307 assert_eq!(get_line_ending_of_str(&text[..17]), Some(LineEnding::Crlf));
252 assert_eq!(get_line_ending_of_str(&text[..17]), Some(LineEnding::Crlf));
308− assert_eq!(get_line_ending_of_str(text), None);
253+ assert_eq!(get_line_ending_of_str(&text[..]), None);
309 }
254 }
310
255
311 #[test]
256 #[test]
312 fn line_end_char_index_rope_slice() {
257 fn line_end_char_index_rope_slice() {
313 let r = Rope::from_str("Hello\rworld\nhow\r\nare you?");
258 let r = Rope::from_str("Hello\rworld\nhow\r\nare you?");
314 let s = &r.slice(..);
259 let s = &r.slice(..);
315− #[cfg(not(feature = "unicode-lines"))]
260+ assert_eq!(line_end_char_index(s, 0), 5);
316− {
261+ assert_eq!(line_end_char_index(s, 1), 11);
317− assert_eq!(line_end_char_index(s, 0), 11);
262+ assert_eq!(line_end_char_index(s, 2), 15);
318− assert_eq!(line_end_char_index(s, 1), 15);
263+ assert_eq!(line_end_char_index(s, 3), 25);
319− assert_eq!(line_end_char_index(s, 2), 25);
320− }
321− #[cfg(feature = "unicode-lines")]
322− {
323− assert_eq!(line_end_char_index(s, 0), 5);
324− assert_eq!(line_end_char_index(s, 1), 11);
325− assert_eq!(line_end_char_index(s, 2), 15);
326− }
327 }
264 }
328}
265}
helix-core/src/match_brackets.rs+29−232
@@ -1,15 +1,7 @@
1−use std::iter;
2−
3−use ropey::RopeSlice;
4use tree_sitter::Node;
1use tree_sitter::Node;
5
2
6−use crate::movement::Direction::{self, Backward, Forward};
3+use crate::{Rope, Syntax};
7−use crate::Syntax;
8−
9−const MAX_PLAINTEXT_SCAN: usize = 10000;
10−const MATCH_LIMIT: usize = 16;
11
4
12−// Limit matching pairs to only ( ) { } [ ] < > ' ' " "
13const PAIRS: &[(char, char)] = &[
5const PAIRS: &[(char, char)] = &[
14 ('(', ')'),
6 ('(', ')'),
15 ('{', '}'),
7 ('{', '}'),
@@ -19,17 +11,17 @@ const PAIRS: &[(char, char)] = &[
19 ('\"', '\"'),
11 ('\"', '\"'),
20];
12];
21
13
22−/// Returns the position of the matching bracket under cursor.
14+// limit matching pairs to only ( ) { } [ ] < > ' ' " "
23−///
15+
24−/// If the cursor is on the opening bracket, the position of
16+// Returns the position of the matching bracket under cursor.
25−/// the closing bracket is returned. If the cursor on the closing
17+//
26−/// bracket, the position of the opening bracket is returned.
18+// If the cursor is one the opening bracket, the position of
27−///
19+// the closing bracket is returned. If the cursor in the closing
28−/// If the cursor is not on a bracket, `None` is returned.
20+// bracket, the position of the opening bracket is returned.
29−///
21+//
30−/// If no matching bracket is found, `None` is returned.
22+// If the cursor is not on a bracket, `None` is returned.
31#[must_use]
23#[must_use]
32−pub fn find_matching_bracket(syntax: &Syntax, doc: RopeSlice, pos: usize) -> Option<usize> {
24+pub fn find_matching_bracket(syntax: &Syntax, doc: &Rope, pos: usize) -> Option<usize> {
33 if pos >= doc.len_chars() || !is_valid_bracket(doc.char(pos)) {
25 if pos >= doc.len_chars() || !is_valid_bracket(doc.char(pos)) {
34 return None;
26 return None;
35 }
27 }
@@ -47,159 +39,46 @@ pub fn find_matching_bracket(syntax: &Syntax, doc: RopeSlice, pos: usize) -> Opt
47//
39//
48// If no surrounding scope is found, the function returns `None`.
40// If no surrounding scope is found, the function returns `None`.
49#[must_use]
41#[must_use]
50−pub fn find_matching_bracket_fuzzy(syntax: &Syntax, doc: RopeSlice, pos: usize) -> Option<usize> {
42+pub fn find_matching_bracket_fuzzy(syntax: &Syntax, doc: &Rope, pos: usize) -> Option<usize> {
51 find_pair(syntax, doc, pos, true)
43 find_pair(syntax, doc, pos, true)
52}
44}
53
45
54−fn find_pair(
46+fn find_pair(syntax: &Syntax, doc: &Rope, pos: usize, traverse_parents: bool) -> Option<usize> {
55− syntax: &Syntax,
56− doc: RopeSlice,
57− pos_: usize,
58− traverse_parents: bool,
59−) -> Option<usize> {
60 let tree = syntax.tree();
47 let tree = syntax.tree();
61− let pos = doc.char_to_byte(pos_);
48+ let pos = doc.char_to_byte(pos);
62
49
63− let mut node = tree.root_node().descendant_for_byte_range(pos, pos)?;
50+ let mut node = tree.root_node().named_descendant_for_byte_range(pos, pos)?;
64
51
65 loop {
52 loop {
66− if node.is_named() {
53+ let (start_byte, end_byte) = surrounding_bytes(doc, &node)?;
67− let (start_byte, end_byte) = surrounding_bytes(doc, &node)?;
54+ let (start_char, end_char) = (doc.byte_to_char(start_byte), doc.byte_to_char(end_byte));
68− let (start_char, end_char) = (doc.byte_to_char(start_byte), doc.byte_to_char(end_byte));
69−
70− if is_valid_pair(doc, start_char, end_char) {
71− if end_byte == pos {
72− return Some(start_char);
73− }
74
55
75− // We return the end char if the cursor is either on the start char
56+ if is_valid_pair(doc, start_char, end_char) {
76− // or at some arbitrary position between start and end char.
57+ if end_byte == pos {
77− if traverse_parents || start_byte == pos {
58+ return Some(start_char);
78− return Some(end_char);
79− }
80 }
59 }
60+ // We return the end char if the cursor is either on the start char
61+ // or at some arbitrary position between start and end char.
62+ return Some(end_char);
81 }
63 }
82− // this node itselt wasn't a pair but maybe its siblings are
83
64
84− // check if we are *on* the pair (special cased so we don't look
65+ if traverse_parents {
85− // at the current node twice and to jump to the start on that case)
66+ node = node.parent()?;
86− if let Some(open) = as_close_pair(doc, &node) {
67+ } else {
87− if let Some(pair_start) = find_pair_end(doc, node.prev_sibling(), open, Backward) {
68+ return None;
88− return Some(pair_start);
89− }
90 }
69 }
91−
92− if !traverse_parents {
93− // check if we are *on* the opening pair (special cased here as
94− // an opptimization since we only care about bracket on the cursor
95− // here)
96− if let Some(close) = as_open_pair(doc, &node) {
97− if let Some(pair_end) = find_pair_end(doc, node.next_sibling(), close, Forward) {
98− return Some(pair_end);
99− }
100− }
101− if node.is_named() {
102− break;
103− }
104− }
105−
106− for close in
107− iter::successors(node.next_sibling(), |node| node.next_sibling()).take(MATCH_LIMIT)
108− {
109− let Some(open) = as_close_pair(doc, &close) else {
110− continue;
111− };
112− if find_pair_end(doc, Some(node), open, Backward).is_some() {
113− return doc.try_byte_to_char(close.start_byte()).ok();
114− }
115− }
116− let Some(parent) = node.parent() else {
117− break;
118− };
119− node = parent;
120− }
121− let node = tree.root_node().named_descendant_for_byte_range(pos, pos)?;
122− if node.child_count() != 0 {
123− return None;
124 }
70 }
125− let node_start = doc.byte_to_char(node.start_byte());
126− find_matching_bracket_plaintext(doc.byte_slice(node.byte_range()), pos_ - node_start)
127− .map(|pos| pos + node_start)
128−}
129−
130−/// Returns the position of the matching bracket under cursor.
131−/// This function works on plain text and ignores tree-sitter grammar.
132−/// The search is limited to `MAX_PLAINTEXT_SCAN` characters
133−///
134−/// If the cursor is on the opening bracket, the position of
135−/// the closing bracket is returned. If the cursor on the closing
136−/// bracket, the position of the opening bracket is returned.
137−///
138−/// If the cursor is not on a bracket, `None` is returned.
139−///
140−/// If no matching bracket is found, `None` is returned.
141−#[must_use]
142−pub fn find_matching_bracket_plaintext(doc: RopeSlice, cursor_pos: usize) -> Option<usize> {
143− // Don't do anything when the cursor is not on top of a bracket.
144− let bracket = doc.char(cursor_pos);
145− if !is_valid_bracket(bracket) {
146− return None;
147− }
148−
149− // Determine the direction of the matching.
150− let is_fwd = is_forward_bracket(bracket);
151− let chars_iter = if is_fwd {
152− doc.chars_at(cursor_pos + 1)
153− } else {
154− doc.chars_at(cursor_pos).reversed()
155− };
156−
157− let mut open_cnt = 1;
158−
159− for (i, candidate) in chars_iter.take(MAX_PLAINTEXT_SCAN).enumerate() {
160− if candidate == bracket {
161− open_cnt += 1;
162− } else if is_valid_pair(
163− doc,
164− if is_fwd {
165− cursor_pos
166− } else {
167− cursor_pos - i - 1
168− },
169− if is_fwd {
170− cursor_pos + i + 1
171− } else {
172− cursor_pos
173− },
174− ) {
175− // Return when all pending brackets have been closed.
176− if open_cnt == 1 {
177− return Some(if is_fwd {
178− cursor_pos + i + 1
179− } else {
180− cursor_pos - i - 1
181− });
182− }
183− open_cnt -= 1;
184− }
185− }
186−
187− None
188}
71}
189
72
190fn is_valid_bracket(c: char) -> bool {
73fn is_valid_bracket(c: char) -> bool {
191 PAIRS.iter().any(|(l, r)| *l == c || *r == c)
74 PAIRS.iter().any(|(l, r)| *l == c || *r == c)
192}
75}
193
76
194−fn is_forward_bracket(c: char) -> bool {
77+fn is_valid_pair(doc: &Rope, start_char: usize, end_char: usize) -> bool {
195− PAIRS.iter().any(|(l, _)| *l == c)
196−}
197−
198−fn is_valid_pair(doc: RopeSlice, start_char: usize, end_char: usize) -> bool {
199 PAIRS.contains(&(doc.char(start_char), doc.char(end_char)))
78 PAIRS.contains(&(doc.char(start_char), doc.char(end_char)))
200}
79}
201
80
202−fn surrounding_bytes(doc: RopeSlice, node: &Node) -> Option<(usize, usize)> {
81+fn surrounding_bytes(doc: &Rope, node: &Node) -> Option<(usize, usize)> {
203 let len = doc.len_bytes();
82 let len = doc.len_bytes();
204
83
205 let start_byte = node.start_byte();
84 let start_byte = node.start_byte();
@@ -211,85 +90,3 @@ fn surrounding_bytes(doc: RopeSlice, node: &Node) -> Option<(usize, usize)> {
211
90
212 Some((start_byte, end_byte))
91 Some((start_byte, end_byte))
213}
92}
214−
215−/// Tests if this node is a pair close char and returns the expected open char
216−fn as_close_pair(doc: RopeSlice, node: &Node) -> Option<char> {
217− let close = as_char(doc, node)?.1;
218− PAIRS
219− .iter()
220− .find_map(|&(open, close_)| (close_ == close).then_some(open))
221−}
222−
223−/// Checks if `node` or its siblings (at most MATCH_LIMIT nodes) is the specified closing char
224−///
225−/// # Returns
226−///
227−/// The position of the found node or `None` otherwise
228−fn find_pair_end(
229− doc: RopeSlice,
230− node: Option<Node>,
231− end_char: char,
232− direction: Direction,
233−) -> Option<usize> {
234− let advance = match direction {
235− Forward => Node::next_sibling,
236− Backward => Node::prev_sibling,
237− };
238− iter::successors(node, advance)
239− .take(MATCH_LIMIT)
240− .find_map(|node| {
241− let (pos, c) = as_char(doc, &node)?;
242− (end_char == c).then_some(pos)
243− })
244−}
245−
246−/// Tests if this node is a pair close char and returns the expected open char
247−fn as_open_pair(doc: RopeSlice, node: &Node) -> Option<char> {
248− let open = as_char(doc, node)?.1;
249− PAIRS
250− .iter()
251− .find_map(|&(open_, close)| (open_ == open).then_some(close))
252−}
253−
254−/// If node is a single char return it (and its char position)
255−fn as_char(doc: RopeSlice, node: &Node) -> Option<(usize, char)> {
256− // TODO: multi char/non ASCII pairs
257− if node.byte_range().len() != 1 {
258− return None;
259− }
260− let pos = doc.try_byte_to_char(node.start_byte()).ok()?;
261− Some((pos, doc.char(pos)))
262−}
263−
264−#[cfg(test)]
265−mod tests {
266− use super::*;
267−
268− #[test]
269− fn test_find_matching_bracket_current_line_plaintext() {
270− let assert = |input: &str, pos, expected| {
271− let input = RopeSlice::from(input);
272− let actual = find_matching_bracket_plaintext(input, pos);
273− assert_eq!(expected, actual.unwrap());
274−
275− let actual = find_matching_bracket_plaintext(input, expected);
276− assert_eq!(pos, actual.unwrap(), "expected symmetrical behaviour");
277− };
278−
279− assert("(hello)", 0, 6);
280− assert("((hello))", 0, 8);
281− assert("((hello))", 1, 7);
282− assert("(((hello)))", 2, 8);
283−
284− assert("key: ${value}", 6, 12);
285− assert("key: ${value} # (some comment)", 16, 29);
286−
287− assert("(paren (paren {bracket}))", 0, 24);
288− assert("(paren (paren {bracket}))", 7, 23);
289− assert("(paren (paren {bracket}))", 14, 22);
290−
291− assert("(prev line\n ) (middle) ( \n next line)", 0, 12);
292− assert("(prev line\n ) (middle) ( \n next line)", 14, 21);
293− assert("(prev line\n ) (middle) ( \n next line)", 23, 36);
294− }
295−}
helix-core/src/movement.rs+36−703
@@ -1,22 +1,15 @@
1−use std::{cmp::Reverse, iter};
1+use std::iter;
2
2
3use ropey::iter::Chars;
3use ropey::iter::Chars;
4−use tree_sitter::{Node, QueryCursor};
5
4
6use crate::{
5use crate::{
7− char_idx_at_visual_offset,
8 chars::{categorize_char, char_is_line_ending, CharCategory},
6 chars::{categorize_char, char_is_line_ending, CharCategory},
9− doc_formatter::TextFormat,
7+ coords_at_pos,
10 graphemes::{
8 graphemes::{
11 next_grapheme_boundary, nth_next_grapheme_boundary, nth_prev_grapheme_boundary,
9 next_grapheme_boundary, nth_next_grapheme_boundary, nth_prev_grapheme_boundary,
12 prev_grapheme_boundary,
10 prev_grapheme_boundary,
13 },
11 },
14− line_ending::rope_is_line_ending,
12+ pos_at_coords, Position, Range, RopeSlice,
15− position::char_idx_at_visual_block_offset,
16− syntax::LanguageConfiguration,
17− text_annotations::TextAnnotations,
18− textobject::TextObject,
19− visual_offset_from_block, Range, RopeSlice, Selection, Syntax,
20};
13};
21
14
22#[derive(Debug, Copy, Clone, PartialEq, Eq)]
15#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -37,8 +30,6 @@ pub fn move_horizontally(
37 dir: Direction,
30 dir: Direction,
38 count: usize,
31 count: usize,
39 behaviour: Movement,
32 behaviour: Movement,
40− _: &TextFormat,
41− _: &mut TextAnnotations,
42) -> Range {
33) -> Range {
43 let pos = range.cursor(slice);
34 let pos = range.cursor(slice);
44
35
@@ -52,116 +43,38 @@ pub fn move_horizontally(
52 range.put_cursor(slice, new_pos, behaviour == Movement::Extend)
43 range.put_cursor(slice, new_pos, behaviour == Movement::Extend)
53}
44}
54
45
55−pub fn move_vertically_visual(
56− slice: RopeSlice,
57− range: Range,
58− dir: Direction,
59− count: usize,
60− behaviour: Movement,
61− text_fmt: &TextFormat,
62− annotations: &mut TextAnnotations,
63−) -> Range {
64− if !text_fmt.soft_wrap {
65− return move_vertically(slice, range, dir, count, behaviour, text_fmt, annotations);
66− }
67− annotations.clear_line_annotations();
68− let pos = range.cursor(slice);
69−
70− // Compute the current position's 2d coordinates.
71− let (visual_pos, block_off) = visual_offset_from_block(slice, pos, pos, text_fmt, annotations);
72− let new_col = range
73− .old_visual_position
74− .map_or(visual_pos.col as u32, |(_, col)| col);
75−
76− // Compute the new position.
77− let mut row_off = match dir {
78− Direction::Forward => count as isize,
79− Direction::Backward => -(count as isize),
80− };
81−
82− // TODO how to handle inline annotations that span an entire visual line (very unlikely).
83−
84− // Compute visual offset relative to block start to avoid trasversing the block twice
85− row_off += visual_pos.row as isize;
86− let new_pos = char_idx_at_visual_offset(
87− slice,
88− block_off,
89− row_off,
90− new_col as usize,
91− text_fmt,
92− annotations,
93− )
94− .0;
95−
96− // Special-case to avoid moving to the end of the last non-empty line.
97− if behaviour == Movement::Extend && slice.line(slice.char_to_line(new_pos)).len_chars() == 0 {
98− return range;
99− }
100−
101− let mut new_range = range.put_cursor(slice, new_pos, behaviour == Movement::Extend);
102− new_range.old_visual_position = Some((0, new_col));
103− new_range
104−}
105−
106pub fn move_vertically(
46pub fn move_vertically(
107 slice: RopeSlice,
47 slice: RopeSlice,
108 range: Range,
48 range: Range,
109 dir: Direction,
49 dir: Direction,
110 count: usize,
50 count: usize,
111 behaviour: Movement,
51 behaviour: Movement,
112− text_fmt: &TextFormat,
113− annotations: &mut TextAnnotations,
114) -> Range {
52) -> Range {
115− annotations.clear_line_annotations();
116 let pos = range.cursor(slice);
53 let pos = range.cursor(slice);
117− let line_idx = slice.char_to_line(pos);
118− let line_start = slice.line_to_char(line_idx);
119
54
120 // Compute the current position's 2d coordinates.
55 // Compute the current position's 2d coordinates.
121− let visual_pos = visual_offset_from_block(slice, line_start, pos, text_fmt, annotations).0;
56+ // TODO: switch this to use `visual_coords_at_pos` rather than
122− let (mut new_row, new_col) = range
57+ // `coords_at_pos` as this will cause a jerky movement when the visual
123− .old_visual_position
58+ // position does not match, like moving from a line with tabs/CJK to
124− .map_or((visual_pos.row as u32, visual_pos.col as u32), |pos| pos);
59+ // a line without
125− new_row = new_row.max(visual_pos.row as u32);
60+ let Position { row, col } = coords_at_pos(slice, pos);
126− let line_idx = slice.char_to_line(pos);
61+ let horiz = range.horiz.unwrap_or(col as u32);
127
62
128 // Compute the new position.
63 // Compute the new position.
129− let mut new_line_idx = match dir {
64+ let new_row = match dir {
130− Direction::Forward => line_idx.saturating_add(count),
65+ Direction::Forward => (row + count).min(slice.len_lines().saturating_sub(1)),
131− Direction::Backward => line_idx.saturating_sub(count),
66+ Direction::Backward => row.saturating_sub(count),
132− };
133−
134− let line = if new_line_idx >= slice.len_lines() - 1 {
135− // there is no line terminator for the last line
136− // so the logic below is not necessary here
137− new_line_idx = slice.len_lines() - 1;
138− slice
139− } else {
140− // char_idx_at_visual_block_offset returns a one-past-the-end index
141− // in case it reaches the end of the slice
142− // to avoid moving to the nextline in that case the line terminator is removed from the line
143− let new_line_end = prev_grapheme_boundary(slice, slice.line_to_char(new_line_idx + 1));
144− slice.slice(..new_line_end)
145 };
67 };
146−
68+ let new_col = col.max(horiz as usize);
147− let new_line_start = line.line_to_char(new_line_idx);
69+ let new_pos = pos_at_coords(slice, Position::new(new_row, new_col), true);
148−
149− let (new_pos, _) = char_idx_at_visual_block_offset(
150− line,
151− new_line_start,
152− new_row as usize,
153− new_col as usize,
154− text_fmt,
155− annotations,
156− );
157
70
158 // Special-case to avoid moving to the end of the last non-empty line.
71 // Special-case to avoid moving to the end of the last non-empty line.
159− if behaviour == Movement::Extend && slice.line(new_line_idx).len_chars() == 0 {
72+ if behaviour == Movement::Extend && slice.line(new_row).len_chars() == 0 {
160 return range;
73 return range;
161 }
74 }
162
75
163 let mut new_range = range.put_cursor(slice, new_pos, behaviour == Movement::Extend);
76 let mut new_range = range.put_cursor(slice, new_pos, behaviour == Movement::Extend);
164− new_range.old_visual_position = Some((new_row, new_col));
77+ new_range.horiz = Some(horiz);
165 new_range
78 new_range
166}
79}
167
80
@@ -177,10 +90,6 @@ pub fn move_prev_word_start(slice: RopeSlice, range: Range, count: usize) -> Ran
177 word_move(slice, range, count, WordMotionTarget::PrevWordStart)
90 word_move(slice, range, count, WordMotionTarget::PrevWordStart)
178}
91}
179
92
180−pub fn move_prev_word_end(slice: RopeSlice, range: Range, count: usize) -> Range {
181− word_move(slice, range, count, WordMotionTarget::PrevWordEnd)
182−}
183−
184pub fn move_next_long_word_start(slice: RopeSlice, range: Range, count: usize) -> Range {
93pub fn move_next_long_word_start(slice: RopeSlice, range: Range, count: usize) -> Range {
185 word_move(slice, range, count, WordMotionTarget::NextLongWordStart)
94 word_move(slice, range, count, WordMotionTarget::NextLongWordStart)
186}
95}
@@ -193,8 +102,8 @@ pub fn move_prev_long_word_start(slice: RopeSlice, range: Range, count: usize) -
193 word_move(slice, range, count, WordMotionTarget::PrevLongWordStart)
102 word_move(slice, range, count, WordMotionTarget::PrevLongWordStart)
194}
103}
195
104
196−pub fn move_prev_long_word_end(slice: RopeSlice, range: Range, count: usize) -> Range {
105+pub fn move_prev_word_end(slice: RopeSlice, range: Range, count: usize) -> Range {
197− word_move(slice, range, count, WordMotionTarget::PrevLongWordEnd)
106+ word_move(slice, range, count, WordMotionTarget::PrevWordEnd)
198}
107}
199
108
200fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTarget) -> Range {
109fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTarget) -> Range {
@@ -203,7 +112,6 @@ fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTar
203 WordMotionTarget::PrevWordStart
112 WordMotionTarget::PrevWordStart
204 | WordMotionTarget::PrevLongWordStart
113 | WordMotionTarget::PrevLongWordStart
205 | WordMotionTarget::PrevWordEnd
114 | WordMotionTarget::PrevWordEnd
206− | WordMotionTarget::PrevLongWordEnd
207 );
115 );
208
116
209 // Special-case early-out.
117 // Special-case early-out.
@@ -232,107 +140,9 @@ fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTar
232 };
140 };
233
141
234 // Do the main work.
142 // Do the main work.
235− let mut range = start_range;
143+ (0..count).fold(start_range, |r, _| {
236− for _ in 0..count {
144+ slice.chars_at(r.head).range_to_target(target, r)
237− let next_range = slice.chars_at(range.head).range_to_target(target, range);
145+ })
238− if range == next_range {
239− break;
240− }
241− range = next_range;
242− }
243− range
244−}
245−
246−pub fn move_prev_paragraph(
247− slice: RopeSlice,
248− range: Range,
249− count: usize,
250− behavior: Movement,
251−) -> Range {
252− let mut line = range.cursor_line(slice);
253− let first_char = slice.line_to_char(line) == range.cursor(slice);
254− let prev_line_empty = rope_is_line_ending(slice.line(line.saturating_sub(1)));
255− let curr_line_empty = rope_is_line_ending(slice.line(line));
256− let prev_empty_to_line = prev_line_empty && !curr_line_empty;
257−
258− // skip character before paragraph boundary
259− if prev_empty_to_line && !first_char {
260− line += 1;
261− }
262− let mut lines = slice.lines_at(line);
263− lines.reverse();
264− let mut lines = lines.map(rope_is_line_ending).peekable();
265− let mut last_line = line;
266− for _ in 0..count {
267− while lines.next_if(|&e| e).is_some() {
268− line -= 1;
269− }
270− while lines.next_if(|&e| !e).is_some() {
271− line -= 1;
272− }
273− if line == last_line {
274− break;
275− }
276− last_line = line;
277− }
278−
279− let head = slice.line_to_char(line);
280− let anchor = if behavior == Movement::Move {
281− // exclude first character after paragraph boundary
282− if prev_empty_to_line && first_char {
283− range.cursor(slice)
284− } else {
285− range.head
286− }
287− } else {
288− range.put_cursor(slice, head, true).anchor
289− };
290− Range::new(anchor, head)
291−}
292−
293−pub fn move_next_paragraph(
294− slice: RopeSlice,
295− range: Range,
296− count: usize,
297− behavior: Movement,
298−) -> Range {
299− let mut line = range.cursor_line(slice);
300− let last_char =
301− prev_grapheme_boundary(slice, slice.line_to_char(line + 1)) == range.cursor(slice);
302− let curr_line_empty = rope_is_line_ending(slice.line(line));
303− let next_line_empty =
304− rope_is_line_ending(slice.line(slice.len_lines().saturating_sub(1).min(line + 1)));
305− let curr_empty_to_line = curr_line_empty && !next_line_empty;
306−
307− // skip character after paragraph boundary
308− if curr_empty_to_line && last_char {
309− line += 1;
310− }
311− let mut lines = slice.lines_at(line).map(rope_is_line_ending).peekable();
312− let mut last_line = line;
313− for _ in 0..count {
314− while lines.next_if(|&e| !e).is_some() {
315− line += 1;
316− }
317− while lines.next_if(|&e| e).is_some() {
318− line += 1;
319− }
320− if line == last_line {
321− break;
322− }
323− last_line = line;
324− }
325− let head = slice.line_to_char(line);
326− let anchor = if behavior == Movement::Move {
327− if curr_empty_to_line && last_char {
328− range.head
329− } else {
330− range.cursor(slice)
331− }
332− } else {
333− range.put_cursor(slice, head, true).anchor
334− };
335− Range::new(anchor, head)
336}
146}
337
147
338// ---- util ------------
148// ---- util ------------
@@ -376,13 +186,12 @@ pub enum WordMotionTarget {
376 NextWordEnd,
186 NextWordEnd,
377 PrevWordStart,
187 PrevWordStart,
378 PrevWordEnd,
188 PrevWordEnd,
379− // A "Long word" (also known as a WORD in Vim/Kakoune) is strictly
189+ // A "Long word" (also known as a WORD in vim/kakoune) is strictly
380 // delimited by whitespace, and can consist of punctuation as well
190 // delimited by whitespace, and can consist of punctuation as well
381 // as alphanumerics.
191 // as alphanumerics.
382 NextLongWordStart,
192 NextLongWordStart,
383 NextLongWordEnd,
193 NextLongWordEnd,
384 PrevLongWordStart,
194 PrevLongWordStart,
385− PrevLongWordEnd,
386}
195}
387
196
388pub trait CharHelpers {
197pub trait CharHelpers {
@@ -399,7 +208,6 @@ impl CharHelpers for Chars<'_> {
399 WordMotionTarget::PrevWordStart
208 WordMotionTarget::PrevWordStart
400 | WordMotionTarget::PrevLongWordStart
209 | WordMotionTarget::PrevLongWordStart
401 | WordMotionTarget::PrevWordEnd
210 | WordMotionTarget::PrevWordEnd
402− | WordMotionTarget::PrevLongWordEnd
403 );
211 );
404
212
405 // Reverse the iterator if needed for the motion direction.
213 // Reverse the iterator if needed for the motion direction.
@@ -486,7 +294,7 @@ fn reached_target(target: WordMotionTarget, prev_ch: char, next_ch: char) -> boo
486 is_word_boundary(prev_ch, next_ch)
294 is_word_boundary(prev_ch, next_ch)
487 && (!prev_ch.is_whitespace() || char_is_line_ending(next_ch))
295 && (!prev_ch.is_whitespace() || char_is_line_ending(next_ch))
488 }
296 }
489− WordMotionTarget::NextLongWordStart | WordMotionTarget::PrevLongWordEnd => {
297+ WordMotionTarget::NextLongWordStart => {
490 is_long_word_boundary(prev_ch, next_ch)
298 is_long_word_boundary(prev_ch, next_ch)
491 && (char_is_line_ending(next_ch) || !next_ch.is_whitespace())
299 && (char_is_line_ending(next_ch) || !next_ch.is_whitespace())
492 }
300 }
@@ -497,150 +305,10 @@ fn reached_target(target: WordMotionTarget, prev_ch: char, next_ch: char) -> boo
497 }
305 }
498}
306}
499
307
500−/// Finds the range of the next or previous textobject in the syntax sub-tree of `node`.
501−/// Returns the range in the forwards direction.
502−pub fn goto_treesitter_object(
503− slice: RopeSlice,
504− range: Range,
505− object_name: &str,
506− dir: Direction,
507− slice_tree: Node,
508− lang_config: &LanguageConfiguration,
509− count: usize,
510−) -> Range {
511− let get_range = move |range: Range| -> Option<Range> {
512− let byte_pos = slice.char_to_byte(range.cursor(slice));
513−
514− let cap_name = |t: TextObject| format!("{}.{}", object_name, t);
515− let mut cursor = QueryCursor::new();
516− let nodes = lang_config.textobject_query()?.capture_nodes_any(
517− &[
518− &cap_name(TextObject::Movement),
519− &cap_name(TextObject::Around),
520− &cap_name(TextObject::Inside),
521− ],
522− slice_tree,
523− slice,
524− &mut cursor,
525− )?;
526−
527− let node = match dir {
528− Direction::Forward => nodes
529− .filter(|n| n.start_byte() > byte_pos)
530− .min_by_key(|n| (n.start_byte(), Reverse(n.end_byte())))?,
531− Direction::Backward => nodes
532− .filter(|n| n.end_byte() < byte_pos)
533− .max_by_key(|n| (n.end_byte(), Reverse(n.start_byte())))?,
534− };
535−
536− let len = slice.len_bytes();
537− let start_byte = node.start_byte();
538− let end_byte = node.end_byte();
539− if start_byte >= len || end_byte >= len {
540− return None;
541− }
542−
543− let start_char = slice.byte_to_char(start_byte);
544− let end_char = slice.byte_to_char(end_byte);
545−
546− // head of range should be at beginning
547− Some(Range::new(start_char, end_char))
548− };
549− let mut last_range = range;
550− for _ in 0..count {
551− match get_range(last_range) {
552− Some(r) if r != last_range => last_range = r,
553− _ => break,
554− }
555− }
556− last_range
557−}
558−
559−fn find_parent_start(mut node: Node) -> Option<Node> {
560− let start = node.start_byte();
561−
562− while node.start_byte() >= start || !node.is_named() {
563− node = node.parent()?;
564− }
565−
566− Some(node)
567−}
568−
569−pub fn move_parent_node_end(
570− syntax: &Syntax,
571− text: RopeSlice,
572− selection: Selection,
573− dir: Direction,
574− movement: Movement,
575−) -> Selection {
576− let tree = syntax.tree();
577−
578− selection.transform(|range| {
579− let start_from = text.char_to_byte(range.from());
580− let start_to = text.char_to_byte(range.to());
581−
582− let mut node = match tree
583− .root_node()
584− .named_descendant_for_byte_range(start_from, start_to)
585− {
586− Some(node) => node,
587− None => {
588− log::debug!(
589− "no descendant found for byte range: {} - {}",
590− start_from,
591− start_to
592− );
593− return range;
594− }
595− };
596−
597− let mut end_head = match dir {
598− // moving forward, we always want to move one past the end of the
599− // current node, so use the end byte of the current node, which is an exclusive
600− // end of the range
601− Direction::Forward => text.byte_to_char(node.end_byte()),
602−
603− // moving backward, we want the cursor to land on the start char of
604− // the current node, or if it is already at the start of a node, to traverse up to
605− // the parent
606− Direction::Backward => {
607− let end_head = text.byte_to_char(node.start_byte());
608−
609− // if we're already on the beginning, look up to the parent
610− if end_head == range.cursor(text) {
611− node = find_parent_start(node).unwrap_or(node);
612− text.byte_to_char(node.start_byte())
613− } else {
614− end_head
615− }
616− }
617− };
618−
619− if movement == Movement::Move {
620− // preserve direction of original range
621− if range.direction() == Direction::Forward {
622− Range::new(end_head, end_head + 1)
623− } else {
624− Range::new(end_head + 1, end_head)
625− }
626− } else {
627− // if we end up with a forward range, then adjust it to be one past
628− // where we want
629− if end_head >= range.anchor {
630− end_head += 1;
631− }
632−
633− Range::new(range.anchor, end_head)
634− }
635− })
636−}
637−
638#[cfg(test)]
308#[cfg(test)]
639mod test {
309mod test {
640 use ropey::Rope;
310 use ropey::Rope;
641
311
642− use crate::{coords_at_pos, pos_at_coords};
643−
644 use super::*;
312 use super::*;
645
313
646 const SINGLE_LINE_SAMPLE: &str = "This is a simple alphabetic line";
314 const SINGLE_LINE_SAMPLE: &str = "This is a simple alphabetic line";
@@ -667,16 +335,7 @@ mod test {
667 assert_eq!(
335 assert_eq!(
668 coords_at_pos(
336 coords_at_pos(
669 slice,
337 slice,
670− move_vertically_visual(
338+ move_vertically(slice, range, Direction::Forward, 1, Movement::Move).head
671− slice,
672− range,
673− Direction::Forward,
674− 1,
675− Movement::Move,
676− &TextFormat::default(),
677− &mut TextAnnotations::default(),
678− )
679− .head
680 ),
339 ),
681 (1, 3).into()
340 (1, 3).into()
682 );
341 );
@@ -700,15 +359,7 @@ mod test {
700 ];
359 ];
701
360
702 for ((direction, amount), coordinates) in moves_and_expected_coordinates {
361 for ((direction, amount), coordinates) in moves_and_expected_coordinates {
703− range = move_horizontally(
362+ range = move_horizontally(slice, range, direction, amount, Movement::Move);
704− slice,
705− range,
706− direction,
707− amount,
708− Movement::Move,
709− &TextFormat::default(),
710− &mut TextAnnotations::default(),
711− );
712 assert_eq!(coords_at_pos(slice, range.head), coordinates.into())
363 assert_eq!(coords_at_pos(slice, range.head), coordinates.into())
713 }
364 }
714 }
365 }
@@ -734,15 +385,7 @@ mod test {
734 ];
385 ];
735
386
736 for ((direction, amount), coordinates) in moves_and_expected_coordinates {
387 for ((direction, amount), coordinates) in moves_and_expected_coordinates {
737− range = move_horizontally(
388+ range = move_horizontally(slice, range, direction, amount, Movement::Move);
738− slice,
739− range,
740− direction,
741− amount,
742− Movement::Move,
743− &TextFormat::default(),
744− &mut TextAnnotations::default(),
745− );
746 assert_eq!(coords_at_pos(slice, range.head), coordinates.into());
389 assert_eq!(coords_at_pos(slice, range.head), coordinates.into());
747 assert_eq!(range.head, range.anchor);
390 assert_eq!(range.head, range.anchor);
748 }
391 }
@@ -764,15 +407,7 @@ mod test {
764 ];
407 ];
765
408
766 for (direction, amount) in moves {
409 for (direction, amount) in moves {
767− range = move_horizontally(
410+ range = move_horizontally(slice, range, direction, amount, Movement::Extend);
768− slice,
769− range,
770− direction,
771− amount,
772− Movement::Extend,
773− &TextFormat::default(),
774− &mut TextAnnotations::default(),
775− );
776 assert_eq!(range.anchor, original_anchor);
411 assert_eq!(range.anchor, original_anchor);
777 }
412 }
778 }
413 }
@@ -796,15 +431,7 @@ mod test {
796 ];
431 ];
797
432
798 for ((direction, amount), coordinates) in moves_and_expected_coordinates {
433 for ((direction, amount), coordinates) in moves_and_expected_coordinates {
799− range = move_vertically_visual(
434+ range = move_vertically(slice, range, direction, amount, Movement::Move);
800− slice,
801− range,
802− direction,
803− amount,
804− Movement::Move,
805− &TextFormat::default(),
806− &mut TextAnnotations::default(),
807− );
808 assert_eq!(coords_at_pos(slice, range.head), coordinates.into());
435 assert_eq!(coords_at_pos(slice, range.head), coordinates.into());
809 assert_eq!(range.head, range.anchor);
436 assert_eq!(range.head, range.anchor);
810 }
437 }
@@ -838,24 +465,8 @@ mod test {
838
465
839 for ((axis, direction, amount), coordinates) in moves_and_expected_coordinates {
466 for ((axis, direction, amount), coordinates) in moves_and_expected_coordinates {
840 range = match axis {
467 range = match axis {
841− Axis::H => move_horizontally(
468+ Axis::H => move_horizontally(slice, range, direction, amount, Movement::Move),
842− slice,
469+ Axis::V => move_vertically(slice, range, direction, amount, Movement::Move),
843− range,
844− direction,
845− amount,
846− Movement::Move,
847− &TextFormat::default(),
848− &mut TextAnnotations::default(),
849− ),
850− Axis::V => move_vertically_visual(
851− slice,
852− range,
853− direction,
854− amount,
855− Movement::Move,
856− &TextFormat::default(),
857− &mut TextAnnotations::default(),
858− ),
859 };
470 };
860 assert_eq!(coords_at_pos(slice, range.head), coordinates.into());
471 assert_eq!(coords_at_pos(slice, range.head), coordinates.into());
861 assert_eq!(range.head, range.anchor);
472 assert_eq!(range.head, range.anchor);
@@ -879,34 +490,18 @@ mod test {
879 let moves_and_expected_coordinates = [
490 let moves_and_expected_coordinates = [
880 // Places cursor at the fourth kana.
491 // Places cursor at the fourth kana.
881 ((Axis::H, Direction::Forward, 4), (0, 4)),
492 ((Axis::H, Direction::Forward, 4), (0, 4)),
882− // Descent places cursor at the 8th character.
493+ // Descent places cursor at the 4th character.
883− ((Axis::V, Direction::Forward, 1usize), (1, 8)),
494+ ((Axis::V, Direction::Forward, 1usize), (1, 4)),
884− // Moving back 2 characters.
495+ // Moving back 1 character.
885− ((Axis::H, Direction::Backward, 2usize), (1, 6)),
496+ ((Axis::H, Direction::Backward, 1usize), (1, 3)),
886 // Jumping back up 1 line.
497 // Jumping back up 1 line.
887 ((Axis::V, Direction::Backward, 1usize), (0, 3)),
498 ((Axis::V, Direction::Backward, 1usize), (0, 3)),
888 ];
499 ];
889
500
890 for ((axis, direction, amount), coordinates) in moves_and_expected_coordinates {
501 for ((axis, direction, amount), coordinates) in moves_and_expected_coordinates {
891 range = match axis {
502 range = match axis {
892− Axis::H => move_horizontally(
503+ Axis::H => move_horizontally(slice, range, direction, amount, Movement::Move),
893− slice,
504+ Axis::V => move_vertically(slice, range, direction, amount, Movement::Move),
894− range,
895− direction,
896− amount,
897− Movement::Move,
898− &TextFormat::default(),
899− &mut TextAnnotations::default(),
900− ),
901− Axis::V => move_vertically_visual(
902− slice,
903− range,
904− direction,
905− amount,
906− Movement::Move,
907− &TextFormat::default(),
908− &mut TextAnnotations::default(),
909− ),
910 };
505 };
911 assert_eq!(coords_at_pos(slice, range.head), coordinates.into());
506 assert_eq!(coords_at_pos(slice, range.head), coordinates.into());
912 assert_eq!(range.head, range.anchor);
507 assert_eq!(range.head, range.anchor);
@@ -1530,266 +1125,4 @@ mod test {
1530 }
1125 }
1531 }
1126 }
1532 }
1127 }
1533−
1534− #[test]
1535− fn test_behaviour_when_moving_to_end_of_prev_long_words() {
1536− let tests = [
1537− (
1538− "Basic backward motion from the middle of a word",
1539− vec![(1, Range::new(3, 3), Range::new(4, 0))],
1540− ),
1541− ("Starting from after boundary retreats the anchor",
1542− vec![(1, Range::new(0, 9), Range::new(8, 0))],
1543− ),
1544− (
1545− "Jump to end of a word succeeded by whitespace",
1546− vec![(1, Range::new(10, 10), Range::new(10, 4))],
1547− ),
1548− (
1549− " Jump to start of line from end of word preceded by whitespace",
1550− vec![(1, Range::new(3, 4), Range::new(4, 0))],
1551− ),
1552− ("Previous anchor is irrelevant for backward motions",
1553− vec![(1, Range::new(12, 5), Range::new(6, 0))]),
1554− (
1555− " Starting from whitespace moves to first space in sequence",
1556− vec![(1, Range::new(0, 4), Range::new(4, 0))],
1557− ),
1558− ("Identifiers_with_underscores are considered a single word",
1559− vec![(1, Range::new(0, 20), Range::new(20, 0))]),
1560− (
1561− "Jumping\n \nback through a newline selects whitespace",
1562− vec![(1, Range::new(0, 13), Range::new(12, 8))],
1563− ),
1564− (
1565− "Jumping to start of word from the end selects the word",
1566− vec![(1, Range::new(6, 7), Range::new(7, 0))],
1567− ),
1568− (
1569− "alphanumeric.!,and.?=punctuation are treated exactly the same",
1570− vec![(1, Range::new(29, 30), Range::new(30, 0))],
1571− ),
1572− (
1573− "... ... punctuation and spaces behave as expected",
1574− vec![
1575− (1, Range::new(0, 10), Range::new(9, 3)),
1576− (1, Range::new(10, 6), Range::new(7, 3)),
1577− ],
1578− ),
1579− (".._.._ punctuation is joined by underscores into a single block",
1580− vec![(1, Range::new(0, 6), Range::new(6, 0))]),
1581− (
1582− "Newlines\n\nare bridged seamlessly.",
1583− vec![(1, Range::new(0, 10), Range::new(8, 0))],
1584− ),
1585− (
1586− "Jumping \n\n\n\n\nback from within a newline group selects previous block",
1587− vec![(1, Range::new(0, 13), Range::new(11, 7))],
1588− ),
1589− (
1590− "Failed motions do not modify the range",
1591− vec![(0, Range::new(3, 0), Range::new(3, 0))],
1592− ),
1593− (
1594− "Multiple motions at once resolve correctly",
1595− vec![(3, Range::new(19, 19), Range::new(8, 0))],
1596− ),
1597− (
1598− "Excessive motions are performed partially",
1599− vec![(999, Range::new(40, 40), Range::new(9, 0))],
1600− ),
1601− (
1602− "", // Edge case of moving backwards in empty string
1603− vec![(1, Range::new(0, 0), Range::new(0, 0))],
1604− ),
1605− (
1606− "\n\n\n\n\n", // Edge case of moving backwards in all newlines
1607− vec![(1, Range::new(5, 5), Range::new(0, 0))],
1608− ),
1609− (" \n \nJumping back through alternated space blocks and newlines selects the space blocks",
1610− vec![
1611− (1, Range::new(0, 8), Range::new(7, 4)),
1612− (1, Range::new(7, 4), Range::new(3, 0)),
1613− ]),
1614− ("ヒーリ..クス multibyte characters behave as normal characters, including when interacting with punctuation",
1615− vec![
1616− (1, Range::new(0, 8), Range::new(7, 0)),
1617− ]),
1618− ];
1619−
1620− for (sample, scenario) in tests {
1621− for (count, begin, expected_end) in scenario.into_iter() {
1622− let range = move_prev_long_word_end(Rope::from(sample).slice(..), begin, count);
1623− assert_eq!(range, expected_end, "Case failed: [{}]", sample);
1624− }
1625− }
1626− }
1627−
1628− #[test]
1629− fn test_behaviour_when_moving_to_prev_paragraph_single() {
1630− let tests = [
1631− ("#[|]#", "#[|]#"),
1632− ("#[s|]#tart at\nfirst char\n", "#[|s]#tart at\nfirst char\n"),
1633− ("start at\nlast char#[\n|]#", "#[|start at\nlast char\n]#"),
1634− (
1635− "goto\nfirst\n\n#[p|]#aragraph",
1636− "#[|goto\nfirst\n\n]#paragraph",
1637− ),
1638− (
1639− "goto\nfirst\n#[\n|]#paragraph",
1640− "#[|goto\nfirst\n\n]#paragraph",
1641− ),
1642− (
1643− "goto\nsecond\n\np#[a|]#ragraph",
1644− "goto\nsecond\n\n#[|pa]#ragraph",
1645− ),
1646− (
1647− "here\n\nhave\nmultiple\nparagraph\n\n\n\n\n#[|]#",
1648− "here\n\n#[|have\nmultiple\nparagraph\n\n\n\n\n]#",
1649− ),
1650− ];
1651−
1652− for (before, expected) in tests {
1653− let (s, selection) = crate::test::print(before);
1654− let text = Rope::from(s.as_str());
1655− let selection =
1656− selection.transform(|r| move_prev_paragraph(text.slice(..), r, 1, Movement::Move));
1657− let actual = crate::test::plain(s.as_ref(), &selection);
1658− assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
1659− }
1660− }
1661−
1662− #[test]
1663− fn test_behaviour_when_moving_to_prev_paragraph_double() {
1664− let tests = [
1665− (
1666− "on#[e|]#\n\ntwo\n\nthree\n\n",
1667− "#[|one]#\n\ntwo\n\nthree\n\n",
1668− ),
1669− (
1670− "one\n\ntwo\n\nth#[r|]#ee\n\n",
1671− "one\n\n#[|two\n\nthr]#ee\n\n",
1672− ),
1673− ];
1674−
1675− for (before, expected) in tests {
1676− let (s, selection) = crate::test::print(before);
1677− let text = Rope::from(s.as_str());
1678− let selection =
1679− selection.transform(|r| move_prev_paragraph(text.slice(..), r, 2, Movement::Move));
1680− let actual = crate::test::plain(s.as_ref(), &selection);
1681− assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
1682− }
1683− }
1684−
1685− #[test]
1686− fn test_behaviour_when_moving_to_prev_paragraph_extend() {
1687− let tests = [
1688− (
1689− "one\n\n#[|two\n\n]#three\n\n",
1690− "#[|one\n\ntwo\n\n]#three\n\n",
1691− ),
1692− (
1693− "#[|one\n\ntwo\n\n]#three\n\n",
1694− "#[|one\n\ntwo\n\n]#three\n\n",
1695− ),
1696− ];
1697−
1698− for (before, expected) in tests {
1699− let (s, selection) = crate::test::print(before);
1700− let text = Rope::from(s.as_str());
1701− let selection = selection
1702− .transform(|r| move_prev_paragraph(text.slice(..), r, 1, Movement::Extend));
1703− let actual = crate::test::plain(s.as_ref(), &selection);
1704− assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
1705− }
1706− }
1707−
1708− #[test]
1709− fn test_behaviour_when_moving_to_next_paragraph_single() {
1710− let tests = [
1711− ("#[|]#", "#[|]#"),
1712− ("#[s|]#tart at\nfirst char\n", "#[start at\nfirst char\n|]#"),
1713− ("start at\nlast char#[\n|]#", "start at\nlast char#[\n|]#"),
1714− (
1715− "a\nb\n\n#[g|]#oto\nthird\n\nparagraph",
1716− "a\nb\n\n#[goto\nthird\n\n|]#paragraph",
1717− ),
1718− (
1719− "a\nb\n#[\n|]#goto\nthird\n\nparagraph",
1720− "a\nb\n\n#[goto\nthird\n\n|]#paragraph",
1721− ),
1722− (
1723− "a\nb#[\n|]#\n\ngoto\nsecond\n\nparagraph",
1724− "a\nb#[\n\n|]#goto\nsecond\n\nparagraph",
1725− ),
1726− (
1727− "here\n\nhave\n#[m|]#ultiple\nparagraph\n\n\n\n\n",
1728− "here\n\nhave\n#[multiple\nparagraph\n\n\n\n\n|]#",
1729− ),
1730− (
1731− "#[t|]#ext\n\n\nafter two blank lines\n\nmore text\n",
1732− "#[text\n\n\n|]#after two blank lines\n\nmore text\n",
1733− ),
1734− (
1735− "#[text\n\n\n|]#after two blank lines\n\nmore text\n",
1736− "text\n\n\n#[after two blank lines\n\n|]#more text\n",
1737− ),
1738− ];
1739−
1740− for (before, expected) in tests {
1741− let (s, selection) = crate::test::print(before);
1742− let text = Rope::from(s.as_str());
1743− let selection =
1744− selection.transform(|r| move_next_paragraph(text.slice(..), r, 1, Movement::Move));
1745− let actual = crate::test::plain(s.as_ref(), &selection);
1746− assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
1747− }
1748− }
1749−
1750− #[test]
1751− fn test_behaviour_when_moving_to_next_paragraph_double() {
1752− let tests = [
1753− (
1754− "one\n\ntwo\n\nth#[r|]#ee\n\n",
1755− "one\n\ntwo\n\nth#[ree\n\n|]#",
1756− ),
1757− (
1758− "on#[e|]#\n\ntwo\n\nthree\n\n",
1759− "on#[e\n\ntwo\n\n|]#three\n\n",
1760− ),
1761− ];
1762−
1763− for (before, expected) in tests {
1764− let (s, selection) = crate::test::print(before);
1765− let text = Rope::from(s.as_str());
1766− let selection =
1767− selection.transform(|r| move_next_paragraph(text.slice(..), r, 2, Movement::Move));
1768− let actual = crate::test::plain(s.as_ref(), &selection);
1769− assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
1770− }
1771− }
1772−
1773− #[test]
1774− fn test_behaviour_when_moving_to_next_paragraph_extend() {
1775− let tests = [
1776− (
1777− "one\n\n#[two\n\n|]#three\n\n",
1778− "one\n\n#[two\n\nthree\n\n|]#",
1779− ),
1780− (
1781− "one\n\n#[two\n\nthree\n\n|]#",
1782− "one\n\n#[two\n\nthree\n\n|]#",
1783− ),
1784− ];
1785−
1786− for (before, expected) in tests {
1787− let (s, selection) = crate::test::print(before);
1788− let text = Rope::from(s.as_str());
1789− let selection = selection
1790− .transform(|r| move_next_paragraph(text.slice(..), r, 1, Movement::Extend));
1791− let actual = crate::test::plain(s.as_ref(), &selection);
1792− assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
1793− }
1794− }
1795}
1128}
helix-core/src/object.rs+16−56
@@ -1,71 +1,31 @@
1use crate::{Range, RopeSlice, Selection, Syntax};
1use crate::{Range, RopeSlice, Selection, Syntax};
2−use tree_sitter::Node;
3
2
4−pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
3+// TODO: to contract_selection we'd need to store the previous ranges before expand.
5− select_node_impl(syntax, text, selection, |mut node, from, to| {
4+// Maybe just contract to the first child node?
6− while node.start_byte() == from && node.end_byte() == to {
5+pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: &Selection) -> Selection {
7− node = node.parent()?;
8− }
9− Some(node)
10− })
11−}
12−
13−pub fn shrink_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
14− select_node_impl(syntax, text, selection, |descendant, _from, _to| {
15− descendant.child(0).or(Some(descendant))
16− })
17−}
18−
19−pub fn select_sibling<F>(
20− syntax: &Syntax,
21− text: RopeSlice,
22− selection: Selection,
23− sibling_fn: &F,
24−) -> Selection
25−where
26− F: Fn(Node) -> Option<Node>,
27−{
28− select_node_impl(syntax, text, selection, |descendant, _from, _to| {
29− find_sibling_recursive(descendant, sibling_fn)
30− })
31−}
32−
33−fn find_sibling_recursive<F>(node: Node, sibling_fn: F) -> Option<Node>
34−where
35− F: Fn(Node) -> Option<Node>,
36−{
37− sibling_fn(node).or_else(|| {
38− node.parent()
39− .and_then(|node| find_sibling_recursive(node, sibling_fn))
40− })
41−}
42−
43−fn select_node_impl<F>(
44− syntax: &Syntax,
45− text: RopeSlice,
46− selection: Selection,
47− select_fn: F,
48−) -> Selection
49−where
50− F: Fn(Node, usize, usize) -> Option<Node>,
51−{
52 let tree = syntax.tree();
6 let tree = syntax.tree();
53
7
54− selection.transform(|range| {
8+ selection.clone().transform(|range| {
55 let from = text.char_to_byte(range.from());
9 let from = text.char_to_byte(range.from());
56 let to = text.char_to_byte(range.to());
10 let to = text.char_to_byte(range.to());
57
11
58− let node = match tree
12+ // find parent of a descendant that matches the range
13+ let parent = match tree
59 .root_node()
14 .root_node()
60 .descendant_for_byte_range(from, to)
15 .descendant_for_byte_range(from, to)
61− .and_then(|node| select_fn(node, from, to))
16+ .and_then(|node| {
62− {
17+ if node.child_count() == 0 || (node.start_byte() == from && node.end_byte() == to) {
63− Some(node) => node,
18+ node.parent()
19+ } else {
20+ Some(node)
21+ }
22+ }) {
23+ Some(parent) => parent,
64 None => return range,
24 None => return range,
65 };
25 };
66
26
67− let from = text.byte_to_char(node.start_byte());
27+ let from = text.byte_to_char(parent.start_byte());
68− let to = text.byte_to_char(node.end_byte());
28+ let to = text.byte_to_char(parent.end_byte());
69
29
70 if range.head < range.anchor {
30 if range.head < range.anchor {
71 Range::new(to, from)
31 Range::new(to, from)
helix-core/src/path.rs+13−83
@@ -1,26 +1,26 @@
1−use etcetera::home_dir;
2use std::path::{Component, Path, PathBuf};
1use std::path::{Component, Path, PathBuf};
3
2
4/// Replaces users home directory from `path` with tilde `~` if the directory
3/// Replaces users home directory from `path` with tilde `~` if the directory
5/// is available, otherwise returns the path unchanged.
4/// is available, otherwise returns the path unchanged.
6pub fn fold_home_dir(path: &Path) -> PathBuf {
5pub fn fold_home_dir(path: &Path) -> PathBuf {
7− if let Ok(home) = home_dir() {
6+ if let Ok(home) = super::home_dir() {
8− if let Ok(stripped) = path.strip_prefix(&home) {
7+ if path.starts_with(&home) {
9− return PathBuf::from("~").join(stripped);
8+ // it's ok to unwrap, the path starts with home dir
9+ return PathBuf::from("~").join(path.strip_prefix(&home).unwrap());
10 }
10 }
11 }
11 }
12
12
13 path.to_path_buf()
13 path.to_path_buf()
14}
14}
15
15
16−/// Expands tilde `~` into users home directory if available, otherwise returns the path
16+/// Expands tilde `~` into users home directory if avilable, otherwise returns the path
17/// unchanged. The tilde will only be expanded when present as the first component of the path
17/// unchanged. The tilde will only be expanded when present as the first component of the path
18/// and only slash follows it.
18/// and only slash follows it.
19pub fn expand_tilde(path: &Path) -> PathBuf {
19pub fn expand_tilde(path: &Path) -> PathBuf {
20 let mut components = path.components().peekable();
20 let mut components = path.components().peekable();
21 if let Some(Component::Normal(c)) = components.peek() {
21 if let Some(Component::Normal(c)) = components.peek() {
22 if c == &"~" {
22 if c == &"~" {
23− if let Ok(home) = home_dir() {
23+ if let Ok(home) = super::home_dir() {
24 // it's ok to unwrap, the path starts with `~`
24 // it's ok to unwrap, the path starts with `~`
25 return home.join(path.strip_prefix("~").unwrap());
25 return home.join(path.strip_prefix("~").unwrap());
26 }
26 }
@@ -40,21 +40,6 @@ pub fn expand_tilde(path: &Path) -> PathBuf {
40/// needs to improve on.
40/// needs to improve on.
41/// Copied from cargo: <https://github.com/rust-lang/cargo/blob/070e459c2d8b79c5b2ac5218064e7603329c92ae/crates/cargo-util/src/paths.rs#L81>
41/// Copied from cargo: <https://github.com/rust-lang/cargo/blob/070e459c2d8b79c5b2ac5218064e7603329c92ae/crates/cargo-util/src/paths.rs#L81>
42pub fn get_normalized_path(path: &Path) -> PathBuf {
42pub fn get_normalized_path(path: &Path) -> PathBuf {
43− // normalization strategy is to canonicalize first ancestor path that exists (i.e., canonicalize as much as possible),
44− // then run handrolled normalization on the non-existent remainder
45− let (base, path) = path
46− .ancestors()
47− .find_map(|base| {
48− let canonicalized_base = dunce::canonicalize(base).ok()?;
49− let remainder = path.strip_prefix(base).ok()?.into();
50− Some((canonicalized_base, remainder))
51− })
52− .unwrap_or_else(|| (PathBuf::new(), PathBuf::from(path)));
53−
54− if path.as_os_str().is_empty() {
55− return base;
56− }
57−
58 let mut components = path.components().peekable();
43 let mut components = path.components().peekable();
59 let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
44 let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
60 components.next();
45 components.next();
@@ -78,85 +63,30 @@ pub fn get_normalized_path(path: &Path) -> PathBuf {
78 }
63 }
79 }
64 }
80 }
65 }
81− base.join(ret)
66+ ret
82}
67}
83
68
84/// Returns the canonical, absolute form of a path with all intermediate components normalized.
69/// Returns the canonical, absolute form of a path with all intermediate components normalized.
85///
70///
86/// This function is used instead of `std::fs::canonicalize` because we don't want to verify
71/// This function is used instead of `std::fs::canonicalize` because we don't want to verify
87/// here if the path exists, just normalize it's components.
72/// here if the path exists, just normalize it's components.
88−pub fn get_canonicalized_path(path: &Path) -> PathBuf {
73+pub fn get_canonicalized_path(path: &Path) -> std::io::Result<PathBuf> {
89 let path = expand_tilde(path);
74 let path = expand_tilde(path);
90 let path = if path.is_relative() {
75 let path = if path.is_relative() {
91− helix_loader::current_working_dir().join(path)
76+ std::env::current_dir().map(|current_dir| current_dir.join(path))?
92 } else {
77 } else {
93 path
78 path
94 };
79 };
95
80
96− get_normalized_path(path.as_path())
81+ Ok(get_normalized_path(path.as_path()))
97}
82}
98
83
99pub fn get_relative_path(path: &Path) -> PathBuf {
84pub fn get_relative_path(path: &Path) -> PathBuf {
100− let path = PathBuf::from(path);
101 let path = if path.is_absolute() {
85 let path = if path.is_absolute() {
102− let cwdir = get_normalized_path(&helix_loader::current_working_dir());
86+ let cwdir = std::env::current_dir().expect("couldn't determine current directory");
103− get_normalized_path(&path)
87+ path.strip_prefix(cwdir).unwrap_or(path)
104− .strip_prefix(cwdir)
105− .map(PathBuf::from)
106− .unwrap_or(path)
107 } else {
88 } else {
108 path
89 path
109 };
90 };
110− fold_home_dir(&path)
91+ fold_home_dir(path)
111−}
112−
113−/// Returns a truncated filepath where the basepart of the path is reduced to the first
114−/// char of the folder and the whole filename appended.
115−///
116−/// Also strip the current working directory from the beginning of the path.
117−/// Note that this function does not check if the truncated path is unambiguous.
118−///
119−/// ```
120−/// use helix_core::path::get_truncated_path;
121−/// use std::path::Path;
122−///
123−/// assert_eq!(
124−/// get_truncated_path("/home/cnorris/documents/jokes.txt").as_path(),
125−/// Path::new("/h/c/d/jokes.txt")
126−/// );
127−/// assert_eq!(
128−/// get_truncated_path("jokes.txt").as_path(),
129−/// Path::new("jokes.txt")
130−/// );
131−/// assert_eq!(
132−/// get_truncated_path("/jokes.txt").as_path(),
133−/// Path::new("/jokes.txt")
134−/// );
135−/// assert_eq!(
136−/// get_truncated_path("/h/c/d/jokes.txt").as_path(),
137−/// Path::new("/h/c/d/jokes.txt")
138−/// );
139−/// assert_eq!(get_truncated_path("").as_path(), Path::new(""));
140−/// ```
141−///
142−pub fn get_truncated_path<P: AsRef<Path>>(path: P) -> PathBuf {
143− let cwd = helix_loader::current_working_dir();
144− let path = path
145− .as_ref()
146− .strip_prefix(cwd)
147− .unwrap_or_else(|_| path.as_ref());
148− let file = path.file_name().unwrap_or_default();
149− let base = path.parent().unwrap_or_else(|| Path::new(""));
150− let mut ret = PathBuf::new();
151− for d in base {
152− ret.push(
153− d.to_string_lossy()
154− .chars()
155− .next()
156− .unwrap_or_default()
157− .to_string(),
158− );
159− }
160− ret.push(file);
161− ret
162}
92}
helix-core/src/position.rs+14−579

This diff is too big to show here.

helix-core/src/register.rsnew file+71

This diff is too big to show here.

helix-core/src/rope_reader.rsdeleted−37

This diff is too big to show here.

helix-core/src/search.rs+2−24

This diff is too big to show here.

helix-core/src/selection.rs+86−388

This diff is too big to show here.

helix-core/src/shellwords.rs+89−275

This diff is too big to show here.

helix-core/src/state.rsnew file+17

This diff is too big to show here.

helix-core/src/surround.rs+119−222

This diff is too big to show here.

helix-core/src/syntax.rs+847−1661

This diff is too big to show here.

helix-core/src/test.rsdeleted−386

This diff is too big to show here.

helix-core/src/text_annotations.rsdeleted−271

This diff is too big to show here.

helix-core/src/textobject.rs+6−219

This diff is too big to show here.

helix-core/src/transaction.rs+84−345

This diff is too big to show here.

helix-core/src/wrap.rsdeleted−9

This diff is too big to show here.

helix-core/tests/data/indent/cpp.cppdeleted−48

This diff is too big to show here.

helix-core/tests/data/indent/languages.tomldeleted−26

This diff is too big to show here.

helix-core/tests/data/indent/rust.rsdeleted−105

This diff is too big to show here.

helix-core/tests/indent.rsdeleted−232

This diff is too big to show here.

helix-dap/Cargo.tomldeleted−27

This diff is too big to show here.

helix-dap/src/client.rsdeleted−519

This diff is too big to show here.

helix-dap/src/lib.rsdeleted−24

This diff is too big to show here.

helix-dap/src/transport.rsdeleted−290

This diff is too big to show here.

helix-dap/src/types.rsdeleted−890

This diff is too big to show here.

helix-event/Cargo.tomldeleted−16

This diff is too big to show here.

helix-event/src/lib.rsdeleted−8

This diff is too big to show here.

helix-event/src/redraw.rsdeleted−49

This diff is too big to show here.

helix-loader/Cargo.tomldeleted−36

This diff is too big to show here.

helix-loader/build.rsdeleted−77

This diff is too big to show here.

helix-loader/src/config.rsdeleted−46

This diff is too big to show here.

helix-loader/src/grammar.rsdeleted−599

This diff is too big to show here.

helix-loader/src/lib.rsdeleted−362

This diff is too big to show here.

helix-loader/src/main.rsdeleted−9

This diff is too big to show here.

helix-lsp/Cargo.toml+12−17

This diff is too big to show here.

helix-lsp/src/client.rs+100−816

This diff is too big to show here.

helix-lsp/src/file_event.rsdeleted−193

This diff is too big to show here.

helix-lsp/src/jsonrpc.rsdeleted−411

This diff is too big to show here.

helix-lsp/src/lib.rs+143−732

This diff is too big to show here.

helix-lsp/src/snippet.rsdeleted−1010

This diff is too big to show here.

helix-lsp/src/transport.rs+36−97

This diff is too big to show here.

helix-parsec/Cargo.tomldeleted−14

This diff is too big to show here.

helix-parsec/src/lib.rsdeleted−574

This diff is too big to show here.

helix-syntax/Cargo.tomlnew file+21

This diff is too big to show here.

helix-syntax/README.mdnew file+13

This diff is too big to show here.

helix-syntax/build.rsnew file+207

This diff is too big to show here.

helix-syntax/languages/tree-sitter-agdanew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-bashnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-cnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-c-sharpnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-cmakenew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-commentnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-cppnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-cssnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-dartnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-dockerfilenew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-elixirnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-fishnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-git-commitnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-git-diffnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-git-rebasenew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-glslnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-gonew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-haskellnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-htmlnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-javanew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-javascriptnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-jsonnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-julianew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-latexnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-ledgernew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-llvmnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-llvm-mirnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-luanew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-markdownnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-nixnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-ocamlnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-perlnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-phpnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-protobufnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-pythonnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-rubynew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-rustnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-scalanew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-sveltenew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-swiftnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-tablegennew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-tomlnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-tsqnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-typescriptnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-vuenew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-wgslnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-yamlnew file+1

This diff is too big to show here.

helix-syntax/languages/tree-sitter-zignew file+1

This diff is too big to show here.

helix-syntax/src/lib.rsnew file+31

This diff is too big to show here.

helix-term/Cargo.toml+24−46

This diff is too big to show here.

helix-term/build.rs+9−6

This diff is too big to show here.

helix-term/src/application.rs+296−889

This diff is too big to show here.

helix-term/src/args.rs+15−110

This diff is too big to show here.

helix-term/src/commands.rs+3412−3084

This diff is too big to show here.

helix-term/src/commands/dap.rsdeleted−769

This diff is too big to show here.

helix-term/src/commands/lsp.rsdeleted−1665

This diff is too big to show here.

helix-term/src/commands/typed.rsdeleted−3226

This diff is too big to show here.

helix-term/src/compositor.rs+71−81

This diff is too big to show here.

helix-term/src/config.rs+32−165

This diff is too big to show here.

helix-term/src/health.rsdeleted−372

This diff is too big to show here.

helix-term/src/job.rs+15−55

This diff is too big to show here.

helix-term/src/keymap.rs+638−306

This diff is too big to show here.

helix-term/src/keymap/default.rsdeleted−393

This diff is too big to show here.

helix-term/src/keymap/macros.rsdeleted−126

This diff is too big to show here.

helix-term/src/lib.rs−27

This diff is too big to show here.

helix-term/src/main.rs+40−88

This diff is too big to show here.

helix-term/src/ui/completion.rs+202−399

This diff is too big to show here.

helix-term/src/ui/document.rsdeleted−520

This diff is too big to show here.

helix-term/src/ui/editor.rs+596−970

This diff is too big to show here.

helix-term/src/ui/info.rs+10−3

This diff is too big to show here.

helix-term/src/ui/lsp.rsdeleted−139

This diff is too big to show here.

helix-term/src/ui/markdown.rs+178−292

This diff is too big to show here.

helix-term/src/ui/menu.rs+71−181

This diff is too big to show here.

helix-term/src/ui/mod.rs+175−297

This diff is too big to show here.

helix-term/src/ui/overlay.rsdeleted−76

This diff is too big to show here.

helix-term/src/ui/picker.rs+364−827

This diff is too big to show here.

helix-term/src/ui/popup.rs+37−188

This diff is too big to show here.

helix-term/src/ui/prompt.rs+102−232

This diff is too big to show here.

helix-term/src/ui/spinner.rs+5−4

This diff is too big to show here.

helix-term/src/ui/statusline.rsdeleted−515

This diff is too big to show here.

helix-term/src/ui/text.rs+6−31

This diff is too big to show here.

helix-term/tests/integration.rsdeleted−25

This diff is too big to show here.

helix-term/tests/test/auto_indent.rsdeleted−21

This diff is too big to show here.

helix-term/tests/test/auto_pairs.rsdeleted−541

This diff is too big to show here.

helix-term/tests/test/commands.rsdeleted−528

This diff is too big to show here.

helix-term/tests/test/commands/movement.rsdeleted−452

This diff is too big to show here.

helix-term/tests/test/commands/write.rsdeleted−566

This diff is too big to show here.

helix-term/tests/test/helpers.rsdeleted−370

This diff is too big to show here.

helix-term/tests/test/languages/go.rsdeleted−41

This diff is too big to show here.

helix-term/tests/test/languages/mod.rsdeleted−4

This diff is too big to show here.

helix-term/tests/test/languages/yaml.rsdeleted−819

This diff is too big to show here.

helix-term/tests/test/movement.rsdeleted−554

This diff is too big to show here.

helix-term/tests/test/prompt.rsdeleted−16

This diff is too big to show here.

helix-term/tests/test/splits.rsdeleted−192

This diff is too big to show here.

helix-tui/Cargo.toml+15−18

This diff is too big to show here.

helix-tui/src/backend/crossterm.rs+43−280

This diff is too big to show here.

helix-tui/src/backend/mod.rs+1−5

This diff is too big to show here.

helix-tui/src/backend/test.rs+2−18

This diff is too big to show here.

helix-tui/src/buffer.rs+60−211

This diff is too big to show here.

helix-tui/src/layout.rs+11−7

This diff is too big to show here.

helix-tui/src/lib.rs+3−9

This diff is too big to show here.

helix-tui/src/terminal.rs+14−26

This diff is too big to show here.

helix-tui/src/text.rs+8−65

This diff is too big to show here.

helix-tui/src/widgets/block.rs+38−20

This diff is too big to show here.

helix-tui/src/widgets/mod.rs+8−7

This diff is too big to show here.

helix-tui/src/widgets/paragraph.rs+2−2

This diff is too big to show here.

helix-tui/src/widgets/reflow.rs+5−5

This diff is too big to show here.

helix-tui/src/widgets/table.rs+74−54

This diff is too big to show here.

helix-tui/tests/terminal.rs+7−7

This diff is too big to show here.

helix-vcs/Cargo.tomldeleted−32

This diff is too big to show here.

helix-vcs/src/diff.rsdeleted−292

This diff is too big to show here.

helix-vcs/src/diff/line_cache.rsdeleted−138

This diff is too big to show here.

helix-vcs/src/diff/worker.rsdeleted−204

This diff is too big to show here.

helix-vcs/src/diff/worker/test.rsdeleted−145

This diff is too big to show here.

helix-vcs/src/git.rsdeleted−139

This diff is too big to show here.

helix-vcs/src/git/test.rsdeleted−121

This diff is too big to show here.

helix-vcs/src/lib.rsdeleted−78

This diff is too big to show here.

helix-view/Cargo.toml+16−32

This diff is too big to show here.

helix-view/src/base64.rsdeleted−163

This diff is too big to show here.

helix-view/src/clipboard.rs+148−251

This diff is too big to show here.

helix-view/src/document.rs+359−1288

This diff is too big to show here.

helix-view/src/editor.rs+169−1410

This diff is too big to show here.

helix-view/src/env.rsdeleted−8

This diff is too big to show here.

helix-view/src/graphics.rs+604−702

This diff is too big to show here.

helix-view/src/gutter.rs+53−392

This diff is too big to show here.

helix-view/src/handlers/dap.rsdeleted−394

This diff is too big to show here.

helix-view/src/handlers/lsp.rsdeleted−1

This diff is too big to show here.

helix-view/src/info.rs+16−36

This diff is too big to show here.

helix-view/src/input.rs+24−411

This diff is too big to show here.

helix-view/src/keyboard.rs+153−346

This diff is too big to show here.

helix-view/src/lib.rs−44

This diff is too big to show here.

helix-view/src/macros.rs+1−13

This diff is too big to show here.

helix-view/src/register.rsdeleted−333

This diff is too big to show here.

helix-view/src/theme.rs+107−336

This diff is too big to show here.

helix-view/src/tree.rs+43−269

This diff is too big to show here.

helix-view/src/view.rs+154−766

This diff is too big to show here.

languages.toml+152−2628

This diff is too big to show here.

logo.svgdeleted−1

This diff is too big to show here.

logo_dark.svgdeleted−115

This diff is too big to show here.

logo_light.svgdeleted−115

This diff is too big to show here.

runtime/queries/_javascript/highlights.scmdeleted−36

This diff is too big to show here.

runtime/queries/_javascript/locals.scmdeleted−14

This diff is too big to show here.

runtime/queries/_javascript/tags.scmdeleted−88

This diff is too big to show here.

runtime/queries/_jsx/highlights.scmdeleted−43

This diff is too big to show here.

runtime/queries/_jsx/indents.scmdeleted−6

This diff is too big to show here.

runtime/queries/_typescript/highlights.scmdeleted−142

This diff is too big to show here.

runtime/queries/_typescript/indents.scmdeleted−5

This diff is too big to show here.

runtime/queries/_typescript/locals.scmdeleted−33

This diff is too big to show here.

runtime/queries/_typescript/tags.scmdeleted−23

This diff is too big to show here.

runtime/queries/_typescript/textobjects.scmdeleted−6

This diff is too big to show here.

runtime/queries/agda/highlights.scmdeleted−124

This diff is too big to show here.

runtime/queries/astro/highlights.scmdeleted−3

This diff is too big to show here.

runtime/queries/astro/injections.scmdeleted−9

This diff is too big to show here.

runtime/queries/awk/highlights.scmdeleted−122

This diff is too big to show here.

runtime/queries/awk/injections.scmdeleted−5

This diff is too big to show here.

runtime/queries/awk/textobjects.scmdeleted−10

This diff is too big to show here.

runtime/queries/bash/highlights.scm−1

This diff is too big to show here.

runtime/queries/bash/indents.scmdeleted−12

This diff is too big to show here.

runtime/queries/bash/injections.scmdeleted−8

This diff is too big to show here.

runtime/queries/bash/textobjects.scmdeleted−9

This diff is too big to show here.

runtime/queries/bass/highlights.scmdeleted−101

This diff is too big to show here.

runtime/queries/beancount/folds.scmdeleted−4

This diff is too big to show here.

runtime/queries/beancount/highlights.scmdeleted−49

This diff is too big to show here.

runtime/queries/bibtex/highlights.scmdeleted−47

This diff is too big to show here.

runtime/queries/bibtex/locals.scmdeleted

No changes to the content.

runtime/queries/bibtex/tags.scmdeleted

No changes to the content.

runtime/queries/bicep/highlights.scmdeleted−73

This diff is too big to show here.

runtime/queries/blueprint/highlights.scmdeleted−61

This diff is too big to show here.

runtime/queries/c-sharp/highlights.scm+62−202

This diff is too big to show here.

runtime/queries/c-sharp/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/c-sharp/textobjects.scmdeleted−21

This diff is too big to show here.

runtime/queries/c/highlights.scm+57−112

This diff is too big to show here.

runtime/queries/c/indents.scmdeleted−51

This diff is too big to show here.

runtime/queries/c/indents.tomlnew file+16

This diff is too big to show here.

runtime/queries/c/textobjects.scm+1−9

This diff is too big to show here.

runtime/queries/cairo/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/cairo/indents.scmdeleted−1

This diff is too big to show here.

runtime/queries/cairo/injections.scmdeleted−3

This diff is too big to show here.

runtime/queries/cairo/locals.scmdeleted−1

This diff is too big to show here.

runtime/queries/cairo/textobjects.scmdeleted−1

This diff is too big to show here.

runtime/queries/capnp/folds.scmdeleted−14

This diff is too big to show here.

runtime/queries/capnp/highlights.scmdeleted−141

This diff is too big to show here.

runtime/queries/capnp/indents.scmdeleted−19

This diff is too big to show here.

runtime/queries/capnp/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/capnp/locals.scmdeleted−96

This diff is too big to show here.

runtime/queries/clojure/highlights.scmdeleted−84

This diff is too big to show here.

runtime/queries/clojure/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/cmake/indents.scmdeleted−10

This diff is too big to show here.

runtime/queries/cmake/indents.tomlnew file+12

This diff is too big to show here.

runtime/queries/cmake/textobjects.scm+1−13

This diff is too big to show here.

runtime/queries/comment/highlights.scm+4−20

This diff is too big to show here.

runtime/queries/common-lisp/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/common-lisp/indents.scmdeleted−1

This diff is too big to show here.

runtime/queries/common-lisp/injections.scmdeleted−1

This diff is too big to show here.

runtime/queries/cpon/highlights.scmdeleted−26

This diff is too big to show here.

runtime/queries/cpon/indents.scmdeleted−12

This diff is too big to show here.

runtime/queries/cpp/highlights.scm+30−92

This diff is too big to show here.

runtime/queries/cpp/indents.scmdeleted−3

This diff is too big to show here.

runtime/queries/cpp/indents.tomlnew file+17

This diff is too big to show here.

runtime/queries/cpp/injections.scm−3

This diff is too big to show here.

runtime/queries/crystal/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/crystal/injections.scmdeleted−1

This diff is too big to show here.

runtime/queries/crystal/locals.scmdeleted−1

This diff is too big to show here.

runtime/queries/crystal/textobjects.scmdeleted−1

This diff is too big to show here.

runtime/queries/css/highlights.scm+47−68

This diff is too big to show here.

runtime/queries/css/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/cue/highlights.scmdeleted−110

This diff is too big to show here.

runtime/queries/d/highlights.scmdeleted−231

This diff is too big to show here.

runtime/queries/d/indents.scmdeleted−17

This diff is too big to show here.

runtime/queries/d/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/d/textobjects.scmdeleted−9

This diff is too big to show here.

runtime/queries/dart/highlights.scm+1−3

This diff is too big to show here.

runtime/queries/dart/indents.scmdeleted−100

This diff is too big to show here.

runtime/queries/dart/indents.tomlnew file+20

This diff is too big to show here.

runtime/queries/dart/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/dbml/highlights.scmdeleted−44

This diff is too big to show here.

runtime/queries/devicetree/highlights.scmdeleted−66

This diff is too big to show here.

runtime/queries/dhall/highlights.scmdeleted−110

This diff is too big to show here.

runtime/queries/dhall/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/dhall/textobjects.scmdeleted−23

This diff is too big to show here.

runtime/queries/dockerfile/highlights.scm+1−4

This diff is too big to show here.

runtime/queries/dot/highlights.scmdeleted−43

This diff is too big to show here.

runtime/queries/dot/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/dtd/highlights.scmdeleted−39

This diff is too big to show here.

runtime/queries/dtd/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/ecma/README.mddeleted−14

This diff is too big to show here.

runtime/queries/ecma/highlights.scmdeleted−249

This diff is too big to show here.

runtime/queries/ecma/indents.scmdeleted−28

This diff is too big to show here.

runtime/queries/ecma/injections.scmdeleted−36

This diff is too big to show here.

runtime/queries/ecma/locals.scmdeleted−43

This diff is too big to show here.

runtime/queries/ecma/textobjects.scmdeleted−36

This diff is too big to show here.

runtime/queries/edoc/highlights.scmdeleted−52

This diff is too big to show here.

runtime/queries/edoc/injections.scmdeleted−20

This diff is too big to show here.

runtime/queries/eex/highlights.scmdeleted−6

This diff is too big to show here.

runtime/queries/eex/injections.scmdeleted−9

This diff is too big to show here.

runtime/queries/ejs/highlights.scmdeleted−12

This diff is too big to show here.

runtime/queries/ejs/injections.scmdeleted−7

This diff is too big to show here.

runtime/queries/elixir/highlights.scm+4−2

This diff is too big to show here.

runtime/queries/elixir/indents.scmdeleted−13

This diff is too big to show here.

runtime/queries/elixir/injections.scm−57

This diff is too big to show here.

runtime/queries/elixir/textobjects.scmdeleted−35

This diff is too big to show here.

runtime/queries/elm/highlights.scmdeleted−83

This diff is too big to show here.

runtime/queries/elm/injections.scmdeleted−4

This diff is too big to show here.

runtime/queries/elm/locals.scmdeleted−14

This diff is too big to show here.

runtime/queries/elm/tags.scmdeleted−19

This diff is too big to show here.

runtime/queries/elm/textobjects.scmdeleted−63

This diff is too big to show here.

runtime/queries/elvish/highlights.scmdeleted−76

This diff is too big to show here.

runtime/queries/elvish/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/env/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/erb/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/erb/injections.scmdeleted−7

This diff is too big to show here.

runtime/queries/erlang/highlights.scmdeleted−158

This diff is too big to show here.

runtime/queries/erlang/injections.scmdeleted−7

This diff is too big to show here.

runtime/queries/erlang/locals.scmdeleted−30

This diff is too big to show here.

runtime/queries/erlang/textobjects.scmdeleted−16

This diff is too big to show here.

runtime/queries/esdl/highlights.scmdeleted−74

This diff is too big to show here.

runtime/queries/fish/highlights.scm+1−1

This diff is too big to show here.

runtime/queries/fish/indents.scmdeleted−12

This diff is too big to show here.

runtime/queries/fish/indents.tomlnew file+12

This diff is too big to show here.

runtime/queries/fish/textobjects.scm−4

This diff is too big to show here.

runtime/queries/forth/highlights.scmdeleted−7

This diff is too big to show here.

runtime/queries/fortran/folds.scmdeleted−11

This diff is too big to show here.

runtime/queries/fortran/highlights.scmdeleted−171

This diff is too big to show here.

runtime/queries/fortran/indents.scmdeleted−27

This diff is too big to show here.

runtime/queries/fortran/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/fsharp/highlights.scmdeleted−196

This diff is too big to show here.

runtime/queries/fsharp/locals.scmdeleted−25

This diff is too big to show here.

runtime/queries/gas/highlights.scmdeleted−21

This diff is too big to show here.

runtime/queries/gas/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/gas/textobjects.scmdeleted−2

This diff is too big to show here.

runtime/queries/gdscript/highlights.scmdeleted−155

This diff is too big to show here.

runtime/queries/gdscript/indents.scmdeleted−35

This diff is too big to show here.

runtime/queries/gdscript/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/gdscript/tags.scmdeleted−5

This diff is too big to show here.

runtime/queries/gdscript/textobjects.scmdeleted−17

This diff is too big to show here.

runtime/queries/gemini/highlights.scmdeleted−26

This diff is too big to show here.

runtime/queries/git-attributes/highlights.scmdeleted−9

This diff is too big to show here.

runtime/queries/git-commit/highlights.scm+1−5

This diff is too big to show here.

runtime/queries/git-commit/injections.scm+2−2

This diff is too big to show here.

runtime/queries/git-commit/textobjects.scmdeleted−2

This diff is too big to show here.

runtime/queries/git-config/highlights.scmdeleted−27

This diff is too big to show here.

runtime/queries/diff/highlights.scm → runtime/queries/git-diff/highlights.scmrenamed

The content is the same.

runtime/queries/git-ignore/highlights.scmdeleted−25

This diff is too big to show here.

runtime/queries/git-rebase/highlights.scm+8−33

This diff is too big to show here.

runtime/queries/git-rebase/injections.scm+4−5

This diff is too big to show here.

runtime/queries/gleam/highlights.scmdeleted−120

This diff is too big to show here.

runtime/queries/gleam/locals.scmdeleted−15

This diff is too big to show here.

runtime/queries/gleam/textobjects.scmdeleted−11

This diff is too big to show here.

runtime/queries/glsl/indents.scmdeleted−19

This diff is too big to show here.

runtime/queries/glsl/indents.tomlnew file+19

This diff is too big to show here.

runtime/queries/glsl/textobjects.scmdeleted−1

This diff is too big to show here.

runtime/queries/gn/highlights.scmdeleted−42

This diff is too big to show here.

runtime/queries/gn/injections.scmdeleted−15

This diff is too big to show here.

runtime/queries/gn/locals.scmdeleted−16

This diff is too big to show here.

runtime/queries/go/highlights.scm+24−76

This diff is too big to show here.

runtime/queries/go/indents.scmdeleted−40

This diff is too big to show here.

runtime/queries/go/indents.tomlnew file+30

This diff is too big to show here.

runtime/queries/go/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/go/locals.scm+3−11

This diff is too big to show here.

runtime/queries/go/textobjects.scm+3−15

This diff is too big to show here.

runtime/queries/godot-resource/highlights.scmdeleted−29

This diff is too big to show here.

runtime/queries/godot-resource/injections.scmdeleted−18

This diff is too big to show here.

runtime/queries/gomod/highlights.scmdeleted−17

This diff is too big to show here.

runtime/queries/gomod/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/gotmpl/highlights.scmdeleted−76

This diff is too big to show here.

runtime/queries/gotmpl/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/gowork/highlights.scmdeleted−14

This diff is too big to show here.

runtime/queries/gowork/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/graphql/highlights.scmdeleted−163

This diff is too big to show here.

runtime/queries/hare/highlights.scmdeleted−161

This diff is too big to show here.

runtime/queries/hare/locals.scmdeleted−20

This diff is too big to show here.

runtime/queries/haskell-persistent/folds.scmdeleted−3

This diff is too big to show here.

runtime/queries/haskell-persistent/highlights.scmdeleted−37

This diff is too big to show here.

runtime/queries/haskell-persistent/locals.scmdeleted−1

This diff is too big to show here.

runtime/queries/haskell/highlights.scm+38−131

This diff is too big to show here.

runtime/queries/haskell/injections.scmdeleted−14

This diff is too big to show here.

runtime/queries/haskell/textobjects.scmdeleted−13

This diff is too big to show here.

runtime/queries/hcl/folds.scmdeleted−6

This diff is too big to show here.

runtime/queries/hcl/highlights.scmdeleted−100

This diff is too big to show here.

runtime/queries/hcl/indents.scmdeleted−13

This diff is too big to show here.

runtime/queries/hcl/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/heex/highlights.scmdeleted−63

This diff is too big to show here.

runtime/queries/heex/injections.scmdeleted−28

This diff is too big to show here.

runtime/queries/heex/textobjects.scmdeleted−1

This diff is too big to show here.

runtime/queries/hosts/highlights.scmdeleted−3

This diff is too big to show here.

runtime/queries/html/highlights.scm+1−9

This diff is too big to show here.

runtime/queries/html/injections.scm−3

This diff is too big to show here.

runtime/queries/hurl/highlights.scmdeleted−127

This diff is too big to show here.

runtime/queries/hurl/indents.scmdeleted−11

This diff is too big to show here.

runtime/queries/hurl/injections.scmdeleted−14

This diff is too big to show here.

runtime/queries/iex/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/iex/injections.scmdeleted−6

This diff is too big to show here.

runtime/queries/ini/highlights.scmdeleted−6

This diff is too big to show here.

runtime/queries/janet/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/java/highlights.scm+4−98

This diff is too big to show here.

runtime/queries/java/indents.scmdeleted−35

This diff is too big to show here.

runtime/queries/java/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/java/textobjects.scmdeleted−35

This diff is too big to show here.

runtime/queries/javascript/highlights-jsx.scmnew file+4

This diff is too big to show here.

runtime/queries/javascript/highlights-params.scmnew file+12

This diff is too big to show here.

runtime/queries/javascript/highlights.scm+204−2

This diff is too big to show here.

runtime/queries/javascript/indents.scmdeleted−3

This diff is too big to show here.

runtime/queries/javascript/indents.tomlnew file+28

This diff is too big to show here.

runtime/queries/javascript/injections.scm+19−2

This diff is too big to show here.

runtime/queries/javascript/locals.scm+22−2

This diff is too big to show here.

runtime/queries/javascript/tags.scm+87−2

This diff is too big to show here.

runtime/queries/javascript/textobjects.scmdeleted−3

This diff is too big to show here.

runtime/queries/jinja/highlights.scmdeleted−7

This diff is too big to show here.

runtime/queries/jinja/injections.scmdeleted−4

This diff is too big to show here.

runtime/queries/jsdoc/highlights.scmdeleted−2

This diff is too big to show here.

runtime/queries/jsdoc/injections.scmdeleted−5

This diff is too big to show here.

runtime/queries/json/indents.scmdeleted−9

This diff is too big to show here.

runtime/queries/json/indents.tomlnew file+9

This diff is too big to show here.

runtime/queries/json5/highlights.scmdeleted−11

This diff is too big to show here.

runtime/queries/jsonnet/highlights.scmdeleted−38

This diff is too big to show here.

runtime/queries/jsx/highlights.scmdeleted−3

This diff is too big to show here.

runtime/queries/jsx/indents.scmdeleted−3

This diff is too big to show here.

runtime/queries/jsx/injections.scmdeleted−3

This diff is too big to show here.

runtime/queries/jsx/locals.scmdeleted−3

This diff is too big to show here.

runtime/queries/jsx/tags.scmdeleted−3

This diff is too big to show here.

runtime/queries/jsx/textobjects.scmdeleted−3

This diff is too big to show here.

runtime/queries/julia/highlights.scm+135−245

This diff is too big to show here.

runtime/queries/julia/indents.scmdeleted−16

This diff is too big to show here.

runtime/queries/julia/injections.scm+6−33

This diff is too big to show here.

runtime/queries/julia/locals.scm+50−35

This diff is too big to show here.

runtime/queries/julia/textobjects.scmdeleted−46

This diff is too big to show here.

runtime/queries/just/folds.scmdeleted−4

This diff is too big to show here.

runtime/queries/just/highlights.scmdeleted−33

This diff is too big to show here.

runtime/queries/just/indents.scmdeleted−3

This diff is too big to show here.

runtime/queries/just/injections.scmdeleted−16

This diff is too big to show here.

runtime/queries/just/locals.scmdeleted−10

This diff is too big to show here.

runtime/queries/just/textobjects.scmdeleted−48

This diff is too big to show here.

runtime/queries/kdl/highlights.scmdeleted−22

This diff is too big to show here.

runtime/queries/kdl/indents.scmdeleted−3

This diff is too big to show here.

runtime/queries/kdl/textobjects.scmdeleted−27

This diff is too big to show here.

runtime/queries/kotlin/folds.scmdeleted−17

This diff is too big to show here.

runtime/queries/kotlin/highlights.scmdeleted−298

This diff is too big to show here.

runtime/queries/kotlin/injections.scmdeleted−36

This diff is too big to show here.

runtime/queries/kotlin/locals.scmdeleted−15

This diff is too big to show here.

runtime/queries/latex/highlights.scm+360−191

This diff is too big to show here.

runtime/queries/latex/injections.scmdeleted−6

This diff is too big to show here.

runtime/queries/latex/textobjects.scmdeleted−13

This diff is too big to show here.

runtime/queries/lean/folds.scmdeleted−15

This diff is too big to show here.

runtime/queries/lean/highlights.scmdeleted−217

This diff is too big to show here.

runtime/queries/lean/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/lean/locals.scmdeleted−5

This diff is too big to show here.

runtime/queries/llvm-mir-yaml/indents.scmdeleted−2

This diff is too big to show here.

runtime/queries/llvm-mir-yaml/indents.tomlnew file+3

This diff is too big to show here.

runtime/queries/llvm-mir/indents.scmdeleted−3

This diff is too big to show here.

runtime/queries/llvm-mir/indents.tomlnew file+7

This diff is too big to show here.

runtime/queries/llvm-mir/textobjects.scm−9

This diff is too big to show here.

runtime/queries/llvm/indents.scmdeleted−6

This diff is too big to show here.

runtime/queries/llvm/indents.tomlnew file+8

This diff is too big to show here.

runtime/queries/llvm/textobjects.scm−4

This diff is too big to show here.

runtime/queries/log/highlights.scmdeleted−10

This diff is too big to show here.

runtime/queries/lpf/highlights.scmdeleted−19

This diff is too big to show here.

runtime/queries/lua/folds.scmdeleted−10

This diff is too big to show here.

runtime/queries/lua/highlights.scm+37−40

This diff is too big to show here.

runtime/queries/lua/indents.scmdeleted−20

This diff is too big to show here.

runtime/queries/lua/indents.tomlnew file+24

This diff is too big to show here.

runtime/queries/lua/injections.scmdeleted−3

This diff is too big to show here.

runtime/queries/lua/textobjects.scmdeleted−15

This diff is too big to show here.

runtime/queries/make/highlights.scmdeleted−175

This diff is too big to show here.

runtime/queries/make/injections.scmdeleted−5

This diff is too big to show here.

runtime/queries/markdoc/highlights.scmdeleted−16

This diff is too big to show here.

runtime/queries/markdoc/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/markdown.inline/highlights.scmdeleted−39

This diff is too big to show here.

runtime/queries/markdown.inline/injections.scmdeleted−7

This diff is too big to show here.

runtime/queries/markdown/highlights.scm+14−40

This diff is too big to show here.

runtime/queries/markdown/injections.scm+6−19

This diff is too big to show here.

runtime/queries/matlab/context.scmdeleted−41

This diff is too big to show here.

runtime/queries/matlab/folds.scmdeleted−11

This diff is too big to show here.

runtime/queries/matlab/highlights.scmdeleted−128

This diff is too big to show here.

runtime/queries/matlab/indents.scmdeleted−23

This diff is too big to show here.

runtime/queries/matlab/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/matlab/locals.scmdeleted−19

This diff is too big to show here.

runtime/queries/matlab/textobjects.scmdeleted−9

This diff is too big to show here.

runtime/queries/mermaid/highlights.scmdeleted−187

This diff is too big to show here.

runtime/queries/meson/highlights.scmdeleted−62

This diff is too big to show here.

runtime/queries/meson/indents.scmdeleted−17

This diff is too big to show here.

runtime/queries/msbuild/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/msbuild/indents.scmdeleted−1

This diff is too big to show here.

runtime/queries/msbuild/injections.scmdeleted−1

This diff is too big to show here.

runtime/queries/nasm/highlights.scmdeleted−126

This diff is too big to show here.

runtime/queries/nasm/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/nasm/textobjects.scmdeleted−15

This diff is too big to show here.

runtime/queries/nickel/highlights.scmdeleted−68

This diff is too big to show here.

runtime/queries/nickel/indents.scmdeleted−17

This diff is too big to show here.

runtime/queries/nickel/injections.scmdeleted−3

This diff is too big to show here.

runtime/queries/nim/highlights.scmdeleted−315

This diff is too big to show here.

runtime/queries/nim/indents.scmdeleted−54

This diff is too big to show here.

runtime/queries/nim/textobjects.scmdeleted−19

This diff is too big to show here.

runtime/queries/nix/highlights.scm+29−56

This diff is too big to show here.

runtime/queries/nix/indents.tomlnew file+18

This diff is too big to show here.

runtime/queries/nix/injections.scmdeleted−178

This diff is too big to show here.

runtime/queries/nu/highlights.scmdeleted−287

This diff is too big to show here.

runtime/queries/nu/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/nunjucks/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/nunjucks/injections.scmdeleted−1

This diff is too big to show here.

runtime/queries/ocaml-interface/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/ocaml/highlights.scm−2

This diff is too big to show here.

runtime/queries/ocaml/indents.scmdeleted−12

This diff is too big to show here.

runtime/queries/ocaml/indents.tomlnew file+13

This diff is too big to show here.

runtime/queries/ocaml/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/odin/highlights.scmdeleted−26

This diff is too big to show here.

runtime/queries/odin/indents.scmdeleted−16

This diff is too big to show here.

runtime/queries/odin/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/opencl/highlights.scmdeleted−150

This diff is too big to show here.

runtime/queries/opencl/indents.scmdeleted−1

This diff is too big to show here.

runtime/queries/opencl/injections.scmdeleted−1

This diff is too big to show here.

runtime/queries/opencl/textobjects.scmdeleted−1

This diff is too big to show here.

runtime/queries/openscad/highlights.scmdeleted−63

This diff is too big to show here.

runtime/queries/org/highlights.scmdeleted−24

This diff is too big to show here.

runtime/queries/org/injections.scmdeleted−4

This diff is too big to show here.

runtime/queries/pascal/highlights.scmdeleted−382

This diff is too big to show here.

runtime/queries/pascal/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/pascal/textobjects.scmdeleted−10

This diff is too big to show here.

runtime/queries/passwd/highlights.scmdeleted−7

This diff is too big to show here.

runtime/queries/pem/highlights.scmdeleted−7

This diff is too big to show here.

runtime/queries/perl/fold.scmdeleted−19

This diff is too big to show here.

runtime/queries/perl/highlights.scm+155−72

This diff is too big to show here.

runtime/queries/perl/indents.scmdeleted−29

This diff is too big to show here.

runtime/queries/perl/indents.tomlnew file+17

This diff is too big to show here.

runtime/queries/perl/injections.scmdeleted−4

This diff is too big to show here.

runtime/queries/perl/textobjects.scm+5−11

This diff is too big to show here.

runtime/queries/php/highlights.scm+53−257

This diff is too big to show here.

runtime/queries/php/indents.scmdeleted−17

This diff is too big to show here.

runtime/queries/php/indents.tomlnew file+17

This diff is too big to show here.

runtime/queries/php/injections.scm−22

This diff is too big to show here.

runtime/queries/php/textobjects.scmdeleted−40

This diff is too big to show here.

runtime/queries/po/highlights.scmdeleted−15

This diff is too big to show here.

runtime/queries/po/textobjects.scmdeleted−6

This diff is too big to show here.

runtime/queries/pod/highlights.scmdeleted−61

This diff is too big to show here.

runtime/queries/ponylang/highlights.scmdeleted−176

This diff is too big to show here.

runtime/queries/ponylang/indents.scmdeleted−32

This diff is too big to show here.

runtime/queries/ponylang/locals.scmdeleted−37

This diff is too big to show here.

runtime/queries/ponylang/textobjects.scmdeleted−64

This diff is too big to show here.

runtime/queries/prisma/highlights.scmdeleted−58

This diff is too big to show here.

runtime/queries/protobuf/indents.scmdeleted−11

This diff is too big to show here.

runtime/queries/protobuf/indents.tomlnew file+12

This diff is too big to show here.

runtime/queries/protobuf/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/prql/highlights.scmdeleted−143

This diff is too big to show here.

runtime/queries/prql/injections.scmdeleted−8

This diff is too big to show here.

runtime/queries/purescript/highlights.scmdeleted−164

This diff is too big to show here.

runtime/queries/purescript/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/purescript/locals.scmdeleted−4

This diff is too big to show here.

runtime/queries/purescript/textobjects.scmdeleted−13

This diff is too big to show here.

runtime/queries/python/highlights.scm+35−142

This diff is too big to show here.

runtime/queries/python/indents.scmdeleted−84

This diff is too big to show here.

runtime/queries/python/indents.tomlnew file+39

This diff is too big to show here.

runtime/queries/python/locals.scmdeleted−44

This diff is too big to show here.

runtime/queries/python/textobjects.scm+3−12

This diff is too big to show here.

runtime/queries/qml/highlights.scmdeleted−90

This diff is too big to show here.

runtime/queries/qml/indents.scmdeleted−6

This diff is too big to show here.

runtime/queries/qml/injections.scmdeleted−16

This diff is too big to show here.

runtime/queries/r/highlights.scmdeleted−128

This diff is too big to show here.

runtime/queries/r/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/r/locals.scmdeleted−11

This diff is too big to show here.

runtime/queries/racket/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/racket/indents.scmdeleted−1

This diff is too big to show here.

runtime/queries/racket/injections.scmdeleted−1

This diff is too big to show here.

runtime/queries/regex/highlights.scmdeleted−53

This diff is too big to show here.

runtime/queries/rego/highlights.scmdeleted−68

This diff is too big to show here.

runtime/queries/rego/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/rescript/highlights.scmdeleted−220

This diff is too big to show here.

runtime/queries/rescript/injections.scmdeleted−8

This diff is too big to show here.

runtime/queries/rescript/locals.scmdeleted−7

This diff is too big to show here.

runtime/queries/rescript/textobjects.scmdeleted−112

This diff is too big to show here.

runtime/queries/rmarkdown/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/rmarkdown/indents.scmdeleted−1

This diff is too big to show here.

runtime/queries/rmarkdown/injections.scmdeleted−1

This diff is too big to show here.

runtime/queries/robot/highlights.scmdeleted−59

This diff is too big to show here.

runtime/queries/ron/highlights.scmdeleted−43

This diff is too big to show here.

runtime/queries/ron/indents.scmdeleted−12

This diff is too big to show here.

runtime/queries/ron/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/rst/highlights.scmdeleted−38

This diff is too big to show here.

runtime/queries/ruby/highlights.scm+38−82

This diff is too big to show here.

runtime/queries/ruby/indents.scmdeleted−24

This diff is too big to show here.

runtime/queries/ruby/indents.tomlnew file+25

This diff is too big to show here.

runtime/queries/ruby/injections.scmdeleted−8

This diff is too big to show here.

runtime/queries/ruby/textobjects.scmdeleted−44

This diff is too big to show here.

runtime/queries/rust/highlights.scm+44−74

This diff is too big to show here.

runtime/queries/rust/indents.scmdeleted−148

This diff is too big to show here.

runtime/queries/rust/indents.tomlnew file+28

This diff is too big to show here.

runtime/queries/rust/injections.scm−47

This diff is too big to show here.

runtime/queries/rust/locals.scm+5−19

This diff is too big to show here.

runtime/queries/rust/textobjects.scm+4−36

This diff is too big to show here.

runtime/queries/sage/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/sage/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/sage/textobjects.scmdeleted−1

This diff is too big to show here.

runtime/queries/scala/highlights.scm+30−102

This diff is too big to show here.

runtime/queries/scala/indents.scmdeleted−22

This diff is too big to show here.

runtime/queries/scala/indents.tomlnew file+23

This diff is too big to show here.

runtime/queries/scala/injections.scm+1−2

This diff is too big to show here.

runtime/queries/scala/locals.scmdeleted−29

This diff is too big to show here.

runtime/queries/scheme/highlights.scmdeleted−104

This diff is too big to show here.

runtime/queries/scheme/indents.scmdeleted−43

This diff is too big to show here.

runtime/queries/scheme/injections.scmdeleted−5

This diff is too big to show here.

runtime/queries/scss/highlights.scmdeleted−86

This diff is too big to show here.

runtime/queries/scss/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/slint/highlights.scmdeleted−171

This diff is too big to show here.

runtime/queries/slint/indents.scmdeleted−12

This diff is too big to show here.

runtime/queries/slint/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/slint/locals.scmdeleted−3

This diff is too big to show here.

runtime/queries/smali/folds.scmdeleted−12

This diff is too big to show here.

runtime/queries/smali/highlights.scmdeleted−216

This diff is too big to show here.

runtime/queries/smali/indents.scmdeleted−31

This diff is too big to show here.

runtime/queries/smali/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/smali/locals.scmdeleted−42

This diff is too big to show here.

runtime/queries/smithy/highlights.scmdeleted−102

This diff is too big to show here.

runtime/queries/sml/highlights.scmdeleted−91

This diff is too big to show here.

runtime/queries/solidity/highlights.scmdeleted−219

This diff is too big to show here.

runtime/queries/solidity/locals.scmdeleted−9

This diff is too big to show here.

runtime/queries/sql/highlights.scmdeleted−429

This diff is too big to show here.

runtime/queries/sshclientconfig/highlights.scmdeleted−324

This diff is too big to show here.

runtime/queries/starlark/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/starlark/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/starlark/textobjects.scmdeleted−1

This diff is too big to show here.

runtime/queries/strace/highlights.scmdeleted−8

This diff is too big to show here.

runtime/queries/svelte/indents.scmdeleted−18

This diff is too big to show here.

runtime/queries/svelte/indents.tomlnew file+18

This diff is too big to show here.

runtime/queries/svelte/injections.scm−10

This diff is too big to show here.

runtime/queries/sway/highlights.scmdeleted−336

This diff is too big to show here.

runtime/queries/sway/indents.scmdeleted−71

This diff is too big to show here.

runtime/queries/sway/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/sway/locals.scmdeleted−17

This diff is too big to show here.

runtime/queries/sway/textobjects.scmdeleted−52

This diff is too big to show here.

runtime/queries/swift/highlights.scmdeleted−171

This diff is too big to show here.

runtime/queries/swift/locals.scmdeleted−7

This diff is too big to show here.

runtime/queries/t32/highlights.scmdeleted−227

This diff is too big to show here.

runtime/queries/t32/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/tablegen/indents.scmdeleted−3

This diff is too big to show here.

runtime/queries/tablegen/indents.tomlnew file+7

This diff is too big to show here.

runtime/queries/tablegen/textobjects.scm−9

This diff is too big to show here.

runtime/queries/task/highlights.scmdeleted−4

This diff is too big to show here.

runtime/queries/task/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/templ/highlights.scmdeleted−99

This diff is too big to show here.

runtime/queries/templ/injections.scmdeleted−4

This diff is too big to show here.

runtime/queries/tfvars/folds.scmdeleted−1

This diff is too big to show here.

runtime/queries/tfvars/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/tfvars/indents.scmdeleted−1

This diff is too big to show here.

runtime/queries/tfvars/injections.scmdeleted−1

This diff is too big to show here.

runtime/queries/todotxt/highlights.scmdeleted−6

This diff is too big to show here.

runtime/queries/toml/highlights.scm+2−17

This diff is too big to show here.

runtime/queries/toml/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/tsq/highlights.scm+4−8

This diff is too big to show here.

runtime/queries/tsq/injections.scm−6

This diff is too big to show here.

runtime/queries/tsx/highlights.scm+1−3

This diff is too big to show here.

runtime/queries/tsx/indents.scmdeleted−3

This diff is too big to show here.

runtime/queries/tsx/injections.scmdeleted−3

This diff is too big to show here.

runtime/queries/tsx/locals.scmdeleted−3

This diff is too big to show here.

runtime/queries/tsx/tags.scmdeleted−3

This diff is too big to show here.

runtime/queries/tsx/textobjects.scmdeleted−3

This diff is too big to show here.

runtime/queries/twig/highlights.scmdeleted−60

This diff is too big to show here.

runtime/queries/twig/injections.scmdeleted−3

This diff is too big to show here.

runtime/queries/typescript/highlights.scm+35−2

This diff is too big to show here.

runtime/queries/typescript/indents.scmdeleted−3

This diff is too big to show here.

runtime/queries/typescript/indents.tomlnew file+1

This diff is too big to show here.

runtime/queries/typescript/injections.scmdeleted−3

This diff is too big to show here.

runtime/queries/typescript/locals.scm+2−3

This diff is too big to show here.

runtime/queries/typescript/tags.scm+22−2

This diff is too big to show here.

runtime/queries/typescript/textobjects.scmdeleted−3

This diff is too big to show here.

runtime/queries/typst/highlights.scmdeleted−77

This diff is too big to show here.

runtime/queries/typst/injections.scmdeleted−6

This diff is too big to show here.

runtime/queries/ungrammar/highlights.scmdeleted−17

This diff is too big to show here.

runtime/queries/unison/highlights.scmdeleted−87

This diff is too big to show here.

runtime/queries/unison/injections.scmdeleted−1

This diff is too big to show here.

runtime/queries/uxntal/highlights.scmdeleted−15

This diff is too big to show here.

runtime/queries/v/highlights.scmdeleted−241

This diff is too big to show here.

runtime/queries/v/indents.scmdeleted−16

This diff is too big to show here.

runtime/queries/v/injections.scmdeleted−6

This diff is too big to show here.

runtime/queries/v/textobjects.scmdeleted−27

This diff is too big to show here.

runtime/queries/vala/highlights.scmdeleted−218

This diff is too big to show here.

runtime/queries/verilog/highlights.scmdeleted−311

This diff is too big to show here.

runtime/queries/verilog/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/verilog/locals.scmdeleted−61

This diff is too big to show here.

runtime/queries/verilog/textobjects.scmdeleted−6

This diff is too big to show here.

runtime/queries/vhdl/highlights.scmdeleted−338

This diff is too big to show here.

runtime/queries/vhs/highlights.scmdeleted−36

This diff is too big to show here.

runtime/queries/vue/injections.scm+3−30

This diff is too big to show here.

runtime/queries/wast/highlights.scmdeleted−21

This diff is too big to show here.

runtime/queries/wat/highlights.scmdeleted−20

This diff is too big to show here.

runtime/queries/webc/highlights.scmdeleted−1

This diff is too big to show here.

runtime/queries/webc/injections.scmdeleted−1

This diff is too big to show here.

runtime/queries/wgsl/highlights.scm+79−94

This diff is too big to show here.

runtime/queries/wgsl/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/wit/highlights.scmdeleted−67

This diff is too big to show here.

runtime/queries/wit/indents.scmdeleted−13

This diff is too big to show here.

runtime/queries/wren/highlights.scmdeleted−82

This diff is too big to show here.

runtime/queries/wren/indents.scmdeleted−29

This diff is too big to show here.

runtime/queries/wren/injections.scmdeleted−3

This diff is too big to show here.

runtime/queries/wren/locals.scmdeleted−21

This diff is too big to show here.

runtime/queries/wren/textobjects.scmdeleted−16

This diff is too big to show here.

runtime/queries/xit/highlights.scmdeleted−11

This diff is too big to show here.

runtime/queries/xml/highlights.scmdeleted−42

This diff is too big to show here.

runtime/queries/xml/indents.scmdeleted−1

This diff is too big to show here.

runtime/queries/xml/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/yaml/indents.scmdeleted−36

This diff is too big to show here.

runtime/queries/yaml/indents.tomlnew file+3

This diff is too big to show here.

runtime/queries/yaml/injections.scm+1−53

This diff is too big to show here.

runtime/queries/yuck/highlights.scmdeleted−107

This diff is too big to show here.

runtime/queries/yuck/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/zig/highlights.scm+56−52

This diff is too big to show here.

runtime/queries/zig/indents.scmdeleted−17

This diff is too big to show here.

runtime/queries/zig/indents.tomlnew file+13

This diff is too big to show here.

runtime/queries/zig/injections.scmdeleted−2

This diff is too big to show here.

runtime/queries/zig/textobjects.scmdeleted−23

This diff is too big to show here.

runtime/themes/README.md−8

This diff is too big to show here.

runtime/themes/acme.tomldeleted−45

This diff is too big to show here.

runtime/themes/adwaita-dark.tomldeleted−172

This diff is too big to show here.

runtime/themes/amberwood.tomldeleted−138

This diff is too big to show here.

runtime/themes/autumn.tomldeleted−101

This diff is too big to show here.

runtime/themes/autumn_night.tomldeleted−33

This diff is too big to show here.

runtime/themes/ayu_dark.tomldeleted−89

This diff is too big to show here.

runtime/themes/ayu_evolve.tomldeleted−37

This diff is too big to show here.

runtime/themes/ayu_light.tomldeleted−91

This diff is too big to show here.

runtime/themes/ayu_mirage.tomldeleted−89

This diff is too big to show here.

runtime/themes/base16_default_dark.toml+3−16

This diff is too big to show here.

runtime/themes/base16_default_light.toml+3−16

This diff is too big to show here.

runtime/themes/base16_terminal.toml+4−14

This diff is too big to show here.

runtime/themes/base16_transparent.tomldeleted−79

This diff is too big to show here.

runtime/themes/bogster.toml+54−96

This diff is too big to show here.

runtime/themes/bogster_light.tomldeleted−101

This diff is too big to show here.

runtime/themes/boo_berry.tomldeleted−81

This diff is too big to show here.

runtime/themes/catppuccin_frappe.tomldeleted−38

This diff is too big to show here.

runtime/themes/catppuccin_latte.tomldeleted−38

This diff is too big to show here.

runtime/themes/catppuccin_macchiato.tomldeleted−38

This diff is too big to show here.

runtime/themes/catppuccin_mocha.tomldeleted−159

This diff is too big to show here.

runtime/themes/cyan_light.tomldeleted−154

This diff is too big to show here.

runtime/themes/darcula-solid.tomldeleted−16

This diff is too big to show here.

runtime/themes/darcula.tomldeleted−105

This diff is too big to show here.

runtime/themes/dark_high_contrast.tomldeleted−113

This diff is too big to show here.

runtime/themes/dark_plus.toml+17−51

This diff is too big to show here.

runtime/themes/doom_acario_dark.tomldeleted−102

This diff is too big to show here.

runtime/themes/dracula.toml+48−129

This diff is too big to show here.

runtime/themes/dracula_at_night.tomldeleted−72

This diff is too big to show here.

runtime/themes/emacs.tomldeleted−639

This diff is too big to show here.

runtime/themes/everblush.tomldeleted−115

This diff is too big to show here.

runtime/themes/everforest_dark.toml+43−97

This diff is too big to show here.

runtime/themes/everforest_light.toml+44−97

This diff is too big to show here.

runtime/themes/ferra.tomldeleted−83

This diff is too big to show here.

runtime/themes/flatwhite.tomldeleted−122

This diff is too big to show here.

runtime/themes/fleet_dark.tomldeleted−166

This diff is too big to show here.

runtime/themes/github_dark.tomldeleted−229

This diff is too big to show here.

runtime/themes/github_dark_colorblind.tomldeleted−151

This diff is too big to show here.

runtime/themes/github_dark_dimmed.tomldeleted−151

This diff is too big to show here.

runtime/themes/github_dark_high_contrast.tomldeleted−151

This diff is too big to show here.

runtime/themes/github_dark_tritanopia.tomldeleted−151

This diff is too big to show here.

runtime/themes/github_light.tomldeleted−229

This diff is too big to show here.

runtime/themes/github_light_colorblind.tomldeleted−151

This diff is too big to show here.

runtime/themes/github_light_high_contrast.tomldeleted−151

This diff is too big to show here.

runtime/themes/github_light_tritanopia.tomldeleted−151

This diff is too big to show here.

runtime/themes/gruber-darker.tomldeleted−114

This diff is too big to show here.

runtime/themes/gruvbox.toml+8−29

This diff is too big to show here.

runtime/themes/gruvbox_dark_hard.tomldeleted−13

This diff is too big to show here.

runtime/themes/gruvbox_dark_soft.tomldeleted−7

This diff is too big to show here.

runtime/themes/gruvbox_light.tomldeleted−31

This diff is too big to show here.

runtime/themes/heisenberg.tomldeleted−86

This diff is too big to show here.

runtime/themes/hex_lavender.tomldeleted−31

This diff is too big to show here.

runtime/themes/hex_steel.tomldeleted−115

This diff is too big to show here.

runtime/themes/hex_toxic.tomldeleted−30

This diff is too big to show here.

runtime/themes/horizon-dark.tomldeleted−80

This diff is too big to show here.

runtime/themes/ingrid.toml+4−25

This diff is too big to show here.

runtime/themes/jellybeans.tomldeleted−138

This diff is too big to show here.

runtime/themes/kanagawa.tomldeleted−152

This diff is too big to show here.

runtime/themes/kaolin-dark.tomldeleted−108

This diff is too big to show here.

runtime/themes/kaolin-light.tomldeleted−60

This diff is too big to show here.

runtime/themes/kaolin-valley-dark.tomldeleted−73

This diff is too big to show here.

runtime/themes/licenses/everforest.LICENSEdeleted−21

This diff is too big to show here.

runtime/themes/licenses/modus_vivendi.LICENSEdeleted−5

This diff is too big to show here.

runtime/themes/licenses/modus_vivendi_deuteranopia.LICENSEdeleted−5

This diff is too big to show here.

runtime/themes/licenses/modus_vivendi_tinted.LICENSEdeleted−5

This diff is too big to show here.

runtime/themes/licenses/modus_vivendi_tritanopia.LICENSEdeleted−5

This diff is too big to show here.

runtime/themes/licenses/poimandres.LICENSEdeleted−21

This diff is too big to show here.

runtime/themes/licenses/serika-syntax.LICENSEdeleted−21

This diff is too big to show here.

runtime/themes/licenses/sonokai.LICENSEdeleted−21

This diff is too big to show here.

runtime/themes/licenses/starlight.LICENSEdeleted−24

This diff is too big to show here.

runtime/themes/material_darker.tomldeleted−20

This diff is too big to show here.

runtime/themes/material_deep_ocean.tomldeleted−123

This diff is too big to show here.

runtime/themes/material_oceanic.tomldeleted−21

This diff is too big to show here.

runtime/themes/material_palenight.tomldeleted−19

This diff is too big to show here.

runtime/themes/meliora.tomldeleted−101

This diff is too big to show here.

runtime/themes/mellow.tomldeleted−143

This diff is too big to show here.

runtime/themes/merionette.tomldeleted−98

This diff is too big to show here.

runtime/themes/modus_operandi.tomldeleted−194

This diff is too big to show here.

runtime/themes/modus_operandi_deuteranopia.tomldeleted−46

This diff is too big to show here.

runtime/themes/modus_operandi_tinted.tomldeleted−45

This diff is too big to show here.

runtime/themes/modus_operandi_tritanopia.tomldeleted−73

This diff is too big to show here.

runtime/themes/modus_vivendi.tomldeleted−242

This diff is too big to show here.

runtime/themes/modus_vivendi_deuteranopia.tomldeleted−158

This diff is too big to show here.

runtime/themes/modus_vivendi_tinted.tomldeleted−144

This diff is too big to show here.

runtime/themes/modus_vivendi_tritanopia.tomldeleted−186

This diff is too big to show here.

runtime/themes/molokai.tomldeleted−48

This diff is too big to show here.

runtime/themes/monokai.toml+8−32

This diff is too big to show here.

runtime/themes/monokai_aqua.tomldeleted−17

This diff is too big to show here.

runtime/themes/monokai_pro.toml+5−24

This diff is too big to show here.

runtime/themes/monokai_pro_machine.toml+4−20

This diff is too big to show here.

runtime/themes/monokai_pro_octagon.toml+4−23

This diff is too big to show here.

runtime/themes/monokai_pro_ristretto.toml+4−20

This diff is too big to show here.

runtime/themes/monokai_pro_spectrum.toml+7−23

This diff is too big to show here.

runtime/themes/naysayer.tomldeleted−91

This diff is too big to show here.

runtime/themes/new_moon.tomldeleted−124

This diff is too big to show here.

runtime/themes/night_owl.tomldeleted−114

This diff is too big to show here.

runtime/themes/nightfox.tomldeleted−188

This diff is too big to show here.

runtime/themes/noctis.tomldeleted−207

This diff is too big to show here.

runtime/themes/noctis_bordo.tomldeleted−87

This diff is too big to show here.

runtime/themes/nord-night.tomldeleted−23

This diff is too big to show here.

runtime/themes/nord.toml+88−171

This diff is too big to show here.

runtime/themes/nord_light.tomldeleted−83

This diff is too big to show here.

runtime/themes/onedark.toml+7−28

This diff is too big to show here.

runtime/themes/onedarker.tomldeleted−105

This diff is too big to show here.

runtime/themes/onelight.tomldeleted−190

This diff is too big to show here.

runtime/themes/papercolor-dark.tomldeleted−75

This diff is too big to show here.

runtime/themes/papercolor-light.tomldeleted−214

This diff is too big to show here.

runtime/themes/penumbra+.tomldeleted−126

This diff is too big to show here.

runtime/themes/poimandres.tomldeleted−113

This diff is too big to show here.

runtime/themes/poimandres_storm.tomldeleted−19

This diff is too big to show here.

runtime/themes/pop-dark.tomldeleted−162

This diff is too big to show here.

runtime/themes/rasmus.tomldeleted−140

This diff is too big to show here.

runtime/themes/rose_pine.toml+66−183

This diff is too big to show here.

runtime/themes/rose_pine_dawn.toml+72−27

This diff is too big to show here.

runtime/themes/rose_pine_moon.tomldeleted−30

This diff is too big to show here.

runtime/themes/serika-dark.tomldeleted−108

This diff is too big to show here.

runtime/themes/serika-light.tomldeleted−109

This diff is too big to show here.

runtime/themes/snazzy.tomldeleted−116

This diff is too big to show here.

runtime/themes/solarized_dark.toml+5−36

This diff is too big to show here.

runtime/themes/solarized_light.toml+7−58

This diff is too big to show here.

runtime/themes/sonokai.tomldeleted−113

This diff is too big to show here.

runtime/themes/spacebones_light.toml+11−48

This diff is too big to show here.

runtime/themes/starlight.tomldeleted−113

This diff is too big to show here.

runtime/themes/tokyonight.tomldeleted−96

This diff is too big to show here.

runtime/themes/tokyonight_storm.tomldeleted−8

This diff is too big to show here.

runtime/themes/varua.tomldeleted−104

This diff is too big to show here.

runtime/themes/vim_dark_high_contrast.tomldeleted−72

This diff is too big to show here.

runtime/themes/yellowed.tomldeleted−135

This diff is too big to show here.

runtime/themes/zed_onedark.tomldeleted−110

This diff is too big to show here.

runtime/themes/zed_onelight.tomldeleted−55

This diff is too big to show here.

runtime/themes/zenburn.tomldeleted−63

This diff is too big to show here.

runtime/tutordeleted−1345

This diff is too big to show here.

runtime/tutor.txtnew file+421

This diff is too big to show here.

rust-toolchain.toml+2−2

This diff is too big to show here.

screenshot.png

Binary file not shown.

shell.nix+3−5

This diff is too big to show here.

theme.toml+3−18

This diff is too big to show here.

xtask/Cargo.toml+5−13

This diff is too big to show here.

xtask/src/docgen.rsdeleted−118

This diff is too big to show here.

xtask/src/helpers.rsdeleted−44

This diff is too big to show here.

xtask/src/main.rs+241−25

This diff is too big to show here.

xtask/src/path.rsdeleted−24

This diff is too big to show here.

xtask/src/querycheck.rsdeleted−39

This diff is too big to show here.

xtask/src/themelint.rsdeleted−200

This diff is too big to show here.