Support bracket colorization (rainbow brackets) (#43172)
Deals with https://github.com/zed-industries/zed/issues/5259 Highlights brackets with different colors based on their depth. Uses existing tree-sitter queries from brackets.scm to find brackets, uses theme's accents to color them. https://github.com/user-attachments/assets/cc5f3aba-22fa-446d-9af7-ba6e772029da 1. Adds `colorize_brackets` language setting that allows, per language or globally for all languages, to configure whether Zed should color the brackets for a particular language. Disabled for all languages by default. 2. Any given language can opt-out a certain bracket pair by amending the brackets.scm like `("\"" @open "\"" @close) ` -> `(("\"" @open "\"" @close) (#set! rainbow.exclude))` 3. Brackets are using colors from theme accents, which can be overridden as ```jsonc "theme_overrides": { "One Dark": { "accents": ["#ff69b4", "#7fff00", "#ff1493", "#00ffff", "#ff8c00", "#9400d3"] } }, ``` Release Notes: - Added bracket colorization (rainbow brackets) support. Use `colorize_brackets` language setting to enable. --------- Co-authored-by: MrSubidubi <dev@bahn.sh> Co-authored-by: Lukas Wirth <lukas@zed.dev> Co-authored-by: MrSubidubi <finn@zed.dev> Co-authored-by: Lukas Wirth <me@lukaswirth.dev> Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
This commit is contained in:
co-authored by
MrSubidubi
Lukas Wirth
MrSubidubi
Lukas Wirth
Smit Barmase
parent
e6e5ccbf10
commit
7e341bcf94
@@ -0,0 +1,121 @@
|
||||
//! A row chunk is an exclusive range of rows, [`BufferRow`] within a buffer of a certain version, [`Global`].
|
||||
//! All but the last chunk are of a constant, given size.
|
||||
|
||||
use std::{ops::Range, sync::Arc};
|
||||
|
||||
use clock::Global;
|
||||
use text::{Anchor, OffsetRangeExt as _, Point};
|
||||
use util::RangeExt;
|
||||
|
||||
use crate::BufferRow;
|
||||
|
||||
/// An range of rows, exclusive as [`lsp::Range`] and
|
||||
/// <https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#range>
|
||||
/// denote.
|
||||
///
|
||||
/// Represents an area in a text editor, adjacent to other ones.
|
||||
/// Together, chunks form entire document at a particular version [`Global`].
|
||||
/// Each chunk is queried for inlays as `(start_row, 0)..(end_exclusive, 0)` via
|
||||
/// <https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#inlayHintParams>
|
||||
#[derive(Clone)]
|
||||
pub struct RowChunks {
|
||||
pub(crate) snapshot: text::BufferSnapshot,
|
||||
chunks: Arc<[RowChunk]>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for RowChunks {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("RowChunks")
|
||||
.field("version", self.snapshot.version())
|
||||
.field("chunks", &self.chunks)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl RowChunks {
|
||||
pub fn new(snapshot: text::BufferSnapshot, max_rows_per_chunk: u32) -> Self {
|
||||
let buffer_point_range = (0..snapshot.len()).to_point(&snapshot);
|
||||
let last_row = buffer_point_range.end.row;
|
||||
let chunks = (buffer_point_range.start.row..=last_row)
|
||||
.step_by(max_rows_per_chunk as usize)
|
||||
.enumerate()
|
||||
.map(|(id, chunk_start)| RowChunk {
|
||||
id,
|
||||
start: chunk_start,
|
||||
end_exclusive: (chunk_start + max_rows_per_chunk).min(last_row),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
Self {
|
||||
snapshot,
|
||||
chunks: Arc::from(chunks),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn version(&self) -> &Global {
|
||||
self.snapshot.version()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.chunks.len()
|
||||
}
|
||||
|
||||
pub fn applicable_chunks(
|
||||
&self,
|
||||
ranges: &[Range<text::Anchor>],
|
||||
) -> impl Iterator<Item = RowChunk> {
|
||||
let row_ranges = ranges
|
||||
.iter()
|
||||
.map(|range| range.to_point(&self.snapshot))
|
||||
// Be lenient and yield multiple chunks if they "touch" the exclusive part of the range.
|
||||
// This will result in LSP hints [re-]queried for more ranges, but also more hints already visible when scrolling around.
|
||||
.map(|point_range| point_range.start.row..point_range.end.row + 1)
|
||||
.collect::<Vec<_>>();
|
||||
self.chunks
|
||||
.iter()
|
||||
.filter(move |chunk| -> bool {
|
||||
let chunk_range = chunk.row_range().to_inclusive();
|
||||
row_ranges
|
||||
.iter()
|
||||
.any(|row_range| chunk_range.overlaps(&row_range))
|
||||
})
|
||||
.copied()
|
||||
}
|
||||
|
||||
pub fn chunk_range(&self, chunk: RowChunk) -> Option<Range<Anchor>> {
|
||||
if !self.chunks.contains(&chunk) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let start = Point::new(chunk.start, 0);
|
||||
let end = if self.chunks.last() == Some(&chunk) {
|
||||
Point::new(
|
||||
chunk.end_exclusive,
|
||||
self.snapshot.line_len(chunk.end_exclusive),
|
||||
)
|
||||
} else {
|
||||
Point::new(chunk.end_exclusive, 0)
|
||||
};
|
||||
Some(self.snapshot.anchor_before(start)..self.snapshot.anchor_after(end))
|
||||
}
|
||||
|
||||
pub fn previous_chunk(&self, chunk: RowChunk) -> Option<RowChunk> {
|
||||
if chunk.id == 0 {
|
||||
None
|
||||
} else {
|
||||
self.chunks.get(chunk.id - 1).copied()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct RowChunk {
|
||||
pub id: usize,
|
||||
pub start: BufferRow,
|
||||
pub end_exclusive: BufferRow,
|
||||
}
|
||||
|
||||
impl RowChunk {
|
||||
pub fn row_range(&self) -> Range<BufferRow> {
|
||||
self.start..self.end_exclusive
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user