Combine excerpt footer and header into a single block (#19441)
This simplifies rendering of excerpt headers and footers, and removes the need to store a `BlockDisposition` on these boundary blocks. It's a step toward implementing "replace blocks", which we want to use in the assistant panel. We've also cleaned up the way heights are specified for headers and footers and fixed some visual asymmetries between the "expand upward" and "expand downward" buttons. Release Notes: - N/A --------- Co-authored-by: Richard <richard@zed.dev>
This commit is contained in:
parent
3e0c5c10b7
commit
d209eab058
7 changed files with 401 additions and 553 deletions
|
@ -962,7 +962,6 @@ fn random_diagnostic(
|
||||||
|
|
||||||
const FILE_HEADER: &str = "file header";
|
const FILE_HEADER: &str = "file header";
|
||||||
const EXCERPT_HEADER: &str = "excerpt header";
|
const EXCERPT_HEADER: &str = "excerpt header";
|
||||||
const EXCERPT_FOOTER: &str = "excerpt footer";
|
|
||||||
|
|
||||||
fn editor_blocks(
|
fn editor_blocks(
|
||||||
editor: &View<Editor>,
|
editor: &View<Editor>,
|
||||||
|
@ -998,7 +997,7 @@ fn editor_blocks(
|
||||||
.ok()?
|
.ok()?
|
||||||
}
|
}
|
||||||
|
|
||||||
Block::ExcerptHeader {
|
Block::ExcerptBoundary {
|
||||||
starts_new_buffer, ..
|
starts_new_buffer, ..
|
||||||
} => {
|
} => {
|
||||||
if *starts_new_buffer {
|
if *starts_new_buffer {
|
||||||
|
@ -1007,7 +1006,6 @@ fn editor_blocks(
|
||||||
EXCERPT_HEADER.into()
|
EXCERPT_HEADER.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Block::ExcerptFooter { .. } => EXCERPT_FOOTER.into(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Some((row, name))
|
Some((row, name))
|
||||||
|
|
|
@ -5,8 +5,8 @@ use super::{
|
||||||
use crate::{EditorStyle, GutterDimensions};
|
use crate::{EditorStyle, GutterDimensions};
|
||||||
use collections::{Bound, HashMap, HashSet};
|
use collections::{Bound, HashMap, HashSet};
|
||||||
use gpui::{AnyElement, EntityId, Pixels, WindowContext};
|
use gpui::{AnyElement, EntityId, Pixels, WindowContext};
|
||||||
use language::{BufferSnapshot, Chunk, Patch, Point};
|
use language::{Chunk, Patch, Point};
|
||||||
use multi_buffer::{Anchor, ExcerptId, ExcerptRange, MultiBufferRow, ToPoint as _};
|
use multi_buffer::{Anchor, ExcerptId, ExcerptInfo, MultiBufferRow, ToPoint as _};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
|
@ -128,26 +128,17 @@ pub struct BlockContext<'a, 'b> {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum BlockId {
|
pub enum BlockId {
|
||||||
Custom(CustomBlockId),
|
Custom(CustomBlockId),
|
||||||
ExcerptHeader(ExcerptId),
|
ExcerptBoundary(Option<ExcerptId>),
|
||||||
ExcerptFooter(ExcerptId),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<BlockId> for EntityId {
|
|
||||||
fn from(value: BlockId) -> Self {
|
|
||||||
match value {
|
|
||||||
BlockId::Custom(CustomBlockId(id)) => EntityId::from(id as u64),
|
|
||||||
BlockId::ExcerptHeader(id) => id.into(),
|
|
||||||
BlockId::ExcerptFooter(id) => id.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BlockId> for ElementId {
|
impl From<BlockId> for ElementId {
|
||||||
fn from(value: BlockId) -> Self {
|
fn from(value: BlockId) -> Self {
|
||||||
match value {
|
match value {
|
||||||
BlockId::Custom(CustomBlockId(id)) => ("Block", id).into(),
|
BlockId::Custom(CustomBlockId(id)) => ("Block", id).into(),
|
||||||
BlockId::ExcerptHeader(id) => ("ExcerptHeader", EntityId::from(id)).into(),
|
BlockId::ExcerptBoundary(next_excerpt) => match next_excerpt {
|
||||||
BlockId::ExcerptFooter(id) => ("ExcerptFooter", EntityId::from(id)).into(),
|
Some(id) => ("ExcerptBoundary", EntityId::from(id)).into(),
|
||||||
|
None => "LastExcerptBoundary".into(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,8 +147,7 @@ impl std::fmt::Display for BlockId {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Custom(id) => write!(f, "Block({id:?})"),
|
Self::Custom(id) => write!(f, "Block({id:?})"),
|
||||||
Self::ExcerptHeader(id) => write!(f, "ExcerptHeader({id:?})"),
|
Self::ExcerptBoundary(id) => write!(f, "ExcerptHeader({id:?})"),
|
||||||
Self::ExcerptFooter(id) => write!(f, "ExcerptFooter({id:?})"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,8 +167,7 @@ struct Transform {
|
||||||
|
|
||||||
pub(crate) enum BlockType {
|
pub(crate) enum BlockType {
|
||||||
Custom(CustomBlockId),
|
Custom(CustomBlockId),
|
||||||
Header,
|
ExcerptBoundary,
|
||||||
Footer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait BlockLike {
|
pub(crate) trait BlockLike {
|
||||||
|
@ -191,27 +180,20 @@ pub(crate) trait BlockLike {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Block {
|
pub enum Block {
|
||||||
Custom(Arc<CustomBlock>),
|
Custom(Arc<CustomBlock>),
|
||||||
ExcerptHeader {
|
ExcerptBoundary {
|
||||||
id: ExcerptId,
|
prev_excerpt: Option<ExcerptInfo>,
|
||||||
buffer: BufferSnapshot,
|
next_excerpt: Option<ExcerptInfo>,
|
||||||
range: ExcerptRange<text::Anchor>,
|
|
||||||
height: u32,
|
height: u32,
|
||||||
starts_new_buffer: bool,
|
starts_new_buffer: bool,
|
||||||
show_excerpt_controls: bool,
|
show_excerpt_controls: bool,
|
||||||
},
|
},
|
||||||
ExcerptFooter {
|
|
||||||
id: ExcerptId,
|
|
||||||
disposition: BlockDisposition,
|
|
||||||
height: u32,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockLike for Block {
|
impl BlockLike for Block {
|
||||||
fn block_type(&self) -> BlockType {
|
fn block_type(&self) -> BlockType {
|
||||||
match self {
|
match self {
|
||||||
Block::Custom(block) => BlockType::Custom(block.id),
|
Block::Custom(block) => BlockType::Custom(block.id),
|
||||||
Block::ExcerptHeader { .. } => BlockType::Header,
|
Block::ExcerptBoundary { .. } => BlockType::ExcerptBoundary,
|
||||||
Block::ExcerptFooter { .. } => BlockType::Footer,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,8 +204,7 @@ impl BlockLike for Block {
|
||||||
fn priority(&self) -> usize {
|
fn priority(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Block::Custom(block) => block.priority,
|
Block::Custom(block) => block.priority,
|
||||||
Block::ExcerptHeader { .. } => usize::MAX,
|
Block::ExcerptBoundary { .. } => usize::MAX,
|
||||||
Block::ExcerptFooter { .. } => 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,32 +213,36 @@ impl Block {
|
||||||
pub fn id(&self) -> BlockId {
|
pub fn id(&self) -> BlockId {
|
||||||
match self {
|
match self {
|
||||||
Block::Custom(block) => BlockId::Custom(block.id),
|
Block::Custom(block) => BlockId::Custom(block.id),
|
||||||
Block::ExcerptHeader { id, .. } => BlockId::ExcerptHeader(*id),
|
Block::ExcerptBoundary { next_excerpt, .. } => {
|
||||||
Block::ExcerptFooter { id, .. } => BlockId::ExcerptFooter(*id),
|
BlockId::ExcerptBoundary(next_excerpt.as_ref().map(|info| info.id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disposition(&self) -> BlockDisposition {
|
fn disposition(&self) -> BlockDisposition {
|
||||||
match self {
|
match self {
|
||||||
Block::Custom(block) => block.disposition,
|
Block::Custom(block) => block.disposition,
|
||||||
Block::ExcerptHeader { .. } => BlockDisposition::Above,
|
Block::ExcerptBoundary { next_excerpt, .. } => {
|
||||||
Block::ExcerptFooter { disposition, .. } => *disposition,
|
if next_excerpt.is_some() {
|
||||||
|
BlockDisposition::Above
|
||||||
|
} else {
|
||||||
|
BlockDisposition::Below
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn height(&self) -> u32 {
|
pub fn height(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
Block::Custom(block) => block.height,
|
Block::Custom(block) => block.height,
|
||||||
Block::ExcerptHeader { height, .. } => *height,
|
Block::ExcerptBoundary { height, .. } => *height,
|
||||||
Block::ExcerptFooter { height, .. } => *height,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn style(&self) -> BlockStyle {
|
pub fn style(&self) -> BlockStyle {
|
||||||
match self {
|
match self {
|
||||||
Block::Custom(block) => block.style,
|
Block::Custom(block) => block.style,
|
||||||
Block::ExcerptHeader { .. } => BlockStyle::Sticky,
|
Block::ExcerptBoundary { .. } => BlockStyle::Sticky,
|
||||||
Block::ExcerptFooter { .. } => BlockStyle::Sticky,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,24 +251,17 @@ impl Debug for Block {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Custom(block) => f.debug_struct("Custom").field("block", block).finish(),
|
Self::Custom(block) => f.debug_struct("Custom").field("block", block).finish(),
|
||||||
Self::ExcerptHeader {
|
Self::ExcerptBoundary {
|
||||||
buffer,
|
|
||||||
starts_new_buffer,
|
starts_new_buffer,
|
||||||
id,
|
next_excerpt,
|
||||||
|
prev_excerpt,
|
||||||
..
|
..
|
||||||
} => f
|
} => f
|
||||||
.debug_struct("ExcerptHeader")
|
.debug_struct("ExcerptBoundary")
|
||||||
.field("id", &id)
|
.field("prev_excerpt", &prev_excerpt)
|
||||||
.field("path", &buffer.file().map(|f| f.path()))
|
.field("next_excerpt", &next_excerpt)
|
||||||
.field("starts_new_buffer", &starts_new_buffer)
|
.field("starts_new_buffer", &starts_new_buffer)
|
||||||
.finish(),
|
.finish(),
|
||||||
Block::ExcerptFooter {
|
|
||||||
id, disposition, ..
|
|
||||||
} => f
|
|
||||||
.debug_struct("ExcerptFooter")
|
|
||||||
.field("id", &id)
|
|
||||||
.field("disposition", &disposition)
|
|
||||||
.finish(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -595,66 +573,62 @@ impl BlockMap {
|
||||||
{
|
{
|
||||||
buffer
|
buffer
|
||||||
.excerpt_boundaries_in_range(range)
|
.excerpt_boundaries_in_range(range)
|
||||||
.flat_map(move |excerpt_boundary| {
|
.filter_map(move |excerpt_boundary| {
|
||||||
let mut wrap_row = wrap_snapshot
|
let wrap_row;
|
||||||
.make_wrap_point(Point::new(excerpt_boundary.row.0, 0), Bias::Left)
|
if excerpt_boundary.next.is_some() {
|
||||||
.row();
|
wrap_row = wrap_snapshot
|
||||||
|
.make_wrap_point(Point::new(excerpt_boundary.row.0, 0), Bias::Left)
|
||||||
[
|
.row();
|
||||||
show_excerpt_controls
|
} else {
|
||||||
.then(|| {
|
wrap_row = wrap_snapshot
|
||||||
let disposition;
|
.make_wrap_point(
|
||||||
if excerpt_boundary.next.is_some() {
|
Point::new(
|
||||||
disposition = BlockDisposition::Above;
|
excerpt_boundary.row.0,
|
||||||
} else {
|
buffer.line_len(excerpt_boundary.row),
|
||||||
wrap_row = wrap_snapshot
|
),
|
||||||
.make_wrap_point(
|
Bias::Left,
|
||||||
Point::new(
|
|
||||||
excerpt_boundary.row.0,
|
|
||||||
buffer.line_len(excerpt_boundary.row),
|
|
||||||
),
|
|
||||||
Bias::Left,
|
|
||||||
)
|
|
||||||
.row();
|
|
||||||
disposition = BlockDisposition::Below;
|
|
||||||
}
|
|
||||||
|
|
||||||
excerpt_boundary.prev.as_ref().map(|prev| {
|
|
||||||
(
|
|
||||||
wrap_row,
|
|
||||||
Block::ExcerptFooter {
|
|
||||||
id: prev.id,
|
|
||||||
height: excerpt_footer_height,
|
|
||||||
disposition,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.flatten(),
|
|
||||||
excerpt_boundary.next.map(|next| {
|
|
||||||
let starts_new_buffer = excerpt_boundary
|
|
||||||
.prev
|
|
||||||
.map_or(true, |prev| prev.buffer_id != next.buffer_id);
|
|
||||||
|
|
||||||
(
|
|
||||||
wrap_row,
|
|
||||||
Block::ExcerptHeader {
|
|
||||||
id: next.id,
|
|
||||||
buffer: next.buffer,
|
|
||||||
range: next.range,
|
|
||||||
height: if starts_new_buffer {
|
|
||||||
buffer_header_height
|
|
||||||
} else {
|
|
||||||
excerpt_header_height
|
|
||||||
},
|
|
||||||
starts_new_buffer,
|
|
||||||
show_excerpt_controls,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}),
|
.row();
|
||||||
]
|
}
|
||||||
|
|
||||||
|
let starts_new_buffer = match (&excerpt_boundary.prev, &excerpt_boundary.next) {
|
||||||
|
(_, None) => false,
|
||||||
|
(None, Some(_)) => true,
|
||||||
|
(Some(prev), Some(next)) => prev.buffer_id != next.buffer_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut height = 0;
|
||||||
|
if excerpt_boundary.prev.is_some() {
|
||||||
|
if show_excerpt_controls {
|
||||||
|
height += excerpt_footer_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if excerpt_boundary.next.is_some() {
|
||||||
|
if starts_new_buffer {
|
||||||
|
height += buffer_header_height;
|
||||||
|
if show_excerpt_controls {
|
||||||
|
height += excerpt_header_height;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
height += excerpt_header_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if height == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some((
|
||||||
|
wrap_row,
|
||||||
|
Block::ExcerptBoundary {
|
||||||
|
prev_excerpt: excerpt_boundary.prev,
|
||||||
|
next_excerpt: excerpt_boundary.next,
|
||||||
|
height,
|
||||||
|
starts_new_buffer,
|
||||||
|
show_excerpt_controls,
|
||||||
|
},
|
||||||
|
))
|
||||||
})
|
})
|
||||||
.flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sort_blocks<B: BlockLike>(blocks: &mut [(u32, B)]) {
|
pub(crate) fn sort_blocks<B: BlockLike>(blocks: &mut [(u32, B)]) {
|
||||||
|
@ -665,12 +639,9 @@ impl BlockMap {
|
||||||
.disposition()
|
.disposition()
|
||||||
.cmp(&block_b.disposition())
|
.cmp(&block_b.disposition())
|
||||||
.then_with(|| match ((block_a.block_type()), (block_b.block_type())) {
|
.then_with(|| match ((block_a.block_type()), (block_b.block_type())) {
|
||||||
(BlockType::Footer, BlockType::Footer) => Ordering::Equal,
|
(BlockType::ExcerptBoundary, BlockType::ExcerptBoundary) => Ordering::Equal,
|
||||||
(BlockType::Footer, _) => Ordering::Less,
|
(BlockType::ExcerptBoundary, _) => Ordering::Less,
|
||||||
(_, BlockType::Footer) => Ordering::Greater,
|
(_, BlockType::ExcerptBoundary) => Ordering::Greater,
|
||||||
(BlockType::Header, BlockType::Header) => Ordering::Equal,
|
|
||||||
(BlockType::Header, _) => Ordering::Less,
|
|
||||||
(_, BlockType::Header) => Ordering::Greater,
|
|
||||||
(BlockType::Custom(a_id), BlockType::Custom(b_id)) => block_b
|
(BlockType::Custom(a_id), BlockType::Custom(b_id)) => block_b
|
||||||
.priority()
|
.priority()
|
||||||
.cmp(&block_a.priority())
|
.cmp(&block_a.priority())
|
||||||
|
@ -1045,33 +1016,19 @@ impl BlockSnapshot {
|
||||||
let custom_block = self.custom_blocks_by_id.get(&custom_block_id)?;
|
let custom_block = self.custom_blocks_by_id.get(&custom_block_id)?;
|
||||||
Some(Block::Custom(custom_block.clone()))
|
Some(Block::Custom(custom_block.clone()))
|
||||||
}
|
}
|
||||||
BlockId::ExcerptHeader(excerpt_id) => {
|
BlockId::ExcerptBoundary(next_excerpt_id) => {
|
||||||
let excerpt_range = buffer.range_for_excerpt::<Point>(excerpt_id)?;
|
let wrap_point;
|
||||||
let wrap_point = self
|
if let Some(next_excerpt_id) = next_excerpt_id {
|
||||||
.wrap_snapshot
|
let excerpt_range = buffer.range_for_excerpt::<Point>(next_excerpt_id)?;
|
||||||
.make_wrap_point(excerpt_range.start, Bias::Left);
|
wrap_point = self
|
||||||
let mut cursor = self.transforms.cursor::<(WrapRow, BlockRow)>(&());
|
.wrap_snapshot
|
||||||
cursor.seek(&WrapRow(wrap_point.row()), Bias::Left, &());
|
.make_wrap_point(excerpt_range.start, Bias::Left);
|
||||||
while let Some(transform) = cursor.item() {
|
} else {
|
||||||
if let Some(block) = transform.block.as_ref() {
|
wrap_point = self
|
||||||
if block.id() == block_id {
|
.wrap_snapshot
|
||||||
return Some(block.clone());
|
.make_wrap_point(buffer.max_point(), Bias::Left);
|
||||||
}
|
|
||||||
} else if cursor.start().0 > WrapRow(wrap_point.row()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor.next(&());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
BlockId::ExcerptFooter(excerpt_id) => {
|
|
||||||
let excerpt_range = buffer.range_for_excerpt::<Point>(excerpt_id)?;
|
|
||||||
let wrap_point = self
|
|
||||||
.wrap_snapshot
|
|
||||||
.make_wrap_point(excerpt_range.end, Bias::Left);
|
|
||||||
|
|
||||||
let mut cursor = self.transforms.cursor::<(WrapRow, BlockRow)>(&());
|
let mut cursor = self.transforms.cursor::<(WrapRow, BlockRow)>(&());
|
||||||
cursor.seek(&WrapRow(wrap_point.row()), Bias::Left, &());
|
cursor.seek(&WrapRow(wrap_point.row()), Bias::Left, &());
|
||||||
while let Some(transform) = cursor.item() {
|
while let Some(transform) = cursor.item() {
|
||||||
|
@ -1468,7 +1425,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
use gpui::{div, font, px, AppContext, Context as _, Element};
|
use gpui::{div, font, px, AppContext, Context as _, Element};
|
||||||
use language::{Buffer, Capability};
|
use language::{Buffer, Capability};
|
||||||
use multi_buffer::MultiBuffer;
|
use multi_buffer::{ExcerptRange, MultiBuffer};
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use settings::SettingsStore;
|
use settings::SettingsStore;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
@ -1724,22 +1681,20 @@ mod tests {
|
||||||
// Each excerpt has a header above and footer below. Excerpts are also *separated* by a newline.
|
// Each excerpt has a header above and footer below. Excerpts are also *separated* by a newline.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.text(),
|
snapshot.text(),
|
||||||
"\nBuff\ner 1\n\n\nBuff\ner 2\n\n\nBuff\ner 3\n"
|
"\n\nBuff\ner 1\n\n\n\nBuff\ner 2\n\n\n\nBuff\ner 3\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
let blocks: Vec<_> = snapshot
|
let blocks: Vec<_> = snapshot
|
||||||
.blocks_in_range(0..u32::MAX)
|
.blocks_in_range(0..u32::MAX)
|
||||||
.map(|(row, block)| (row, block.id()))
|
.map(|(row, block)| (row..row + block.height(), block.id()))
|
||||||
.collect();
|
.collect();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
blocks,
|
blocks,
|
||||||
vec![
|
vec![
|
||||||
(0, BlockId::ExcerptHeader(excerpt_ids[0])),
|
(0..2, BlockId::ExcerptBoundary(Some(excerpt_ids[0]))), // path, header
|
||||||
(3, BlockId::ExcerptFooter(excerpt_ids[0])),
|
(4..7, BlockId::ExcerptBoundary(Some(excerpt_ids[1]))), // footer, path, header
|
||||||
(4, BlockId::ExcerptHeader(excerpt_ids[1])),
|
(9..12, BlockId::ExcerptBoundary(Some(excerpt_ids[2]))), // footer, path, header
|
||||||
(7, BlockId::ExcerptFooter(excerpt_ids[1])),
|
(14..15, BlockId::ExcerptBoundary(None)), // footer
|
||||||
(8, BlockId::ExcerptHeader(excerpt_ids[2])),
|
|
||||||
(11, BlockId::ExcerptFooter(excerpt_ids[2]))
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2283,13 +2238,10 @@ mod tests {
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
enum ExpectedBlock {
|
enum ExpectedBlock {
|
||||||
ExcerptHeader {
|
ExcerptBoundary {
|
||||||
height: u32,
|
height: u32,
|
||||||
starts_new_buffer: bool,
|
starts_new_buffer: bool,
|
||||||
},
|
is_last: bool,
|
||||||
ExcerptFooter {
|
|
||||||
height: u32,
|
|
||||||
disposition: BlockDisposition,
|
|
||||||
},
|
},
|
||||||
Custom {
|
Custom {
|
||||||
disposition: BlockDisposition,
|
disposition: BlockDisposition,
|
||||||
|
@ -2303,8 +2255,7 @@ mod tests {
|
||||||
fn block_type(&self) -> BlockType {
|
fn block_type(&self) -> BlockType {
|
||||||
match self {
|
match self {
|
||||||
ExpectedBlock::Custom { id, .. } => BlockType::Custom(*id),
|
ExpectedBlock::Custom { id, .. } => BlockType::Custom(*id),
|
||||||
ExpectedBlock::ExcerptHeader { .. } => BlockType::Header,
|
ExpectedBlock::ExcerptBoundary { .. } => BlockType::ExcerptBoundary,
|
||||||
ExpectedBlock::ExcerptFooter { .. } => BlockType::Footer,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2315,8 +2266,7 @@ mod tests {
|
||||||
fn priority(&self) -> usize {
|
fn priority(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
ExpectedBlock::Custom { priority, .. } => *priority,
|
ExpectedBlock::Custom { priority, .. } => *priority,
|
||||||
ExpectedBlock::ExcerptHeader { .. } => usize::MAX,
|
ExpectedBlock::ExcerptBoundary { .. } => usize::MAX,
|
||||||
ExpectedBlock::ExcerptFooter { .. } => 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2324,17 +2274,21 @@ mod tests {
|
||||||
impl ExpectedBlock {
|
impl ExpectedBlock {
|
||||||
fn height(&self) -> u32 {
|
fn height(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
ExpectedBlock::ExcerptHeader { height, .. } => *height,
|
ExpectedBlock::ExcerptBoundary { height, .. } => *height,
|
||||||
ExpectedBlock::Custom { height, .. } => *height,
|
ExpectedBlock::Custom { height, .. } => *height,
|
||||||
ExpectedBlock::ExcerptFooter { height, .. } => *height,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disposition(&self) -> BlockDisposition {
|
fn disposition(&self) -> BlockDisposition {
|
||||||
match self {
|
match self {
|
||||||
ExpectedBlock::ExcerptHeader { .. } => BlockDisposition::Above,
|
ExpectedBlock::ExcerptBoundary { is_last, .. } => {
|
||||||
|
if *is_last {
|
||||||
|
BlockDisposition::Below
|
||||||
|
} else {
|
||||||
|
BlockDisposition::Above
|
||||||
|
}
|
||||||
|
}
|
||||||
ExpectedBlock::Custom { disposition, .. } => *disposition,
|
ExpectedBlock::Custom { disposition, .. } => *disposition,
|
||||||
ExpectedBlock::ExcerptFooter { disposition, .. } => *disposition,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2348,21 +2302,15 @@ mod tests {
|
||||||
height: block.height,
|
height: block.height,
|
||||||
priority: block.priority,
|
priority: block.priority,
|
||||||
},
|
},
|
||||||
Block::ExcerptHeader {
|
Block::ExcerptBoundary {
|
||||||
height,
|
height,
|
||||||
starts_new_buffer,
|
starts_new_buffer,
|
||||||
|
next_excerpt,
|
||||||
..
|
..
|
||||||
} => ExpectedBlock::ExcerptHeader {
|
} => ExpectedBlock::ExcerptBoundary {
|
||||||
height,
|
height,
|
||||||
starts_new_buffer,
|
starts_new_buffer,
|
||||||
},
|
is_last: next_excerpt.is_none(),
|
||||||
Block::ExcerptFooter {
|
|
||||||
height,
|
|
||||||
disposition,
|
|
||||||
..
|
|
||||||
} => ExpectedBlock::ExcerptFooter {
|
|
||||||
height,
|
|
||||||
disposition,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2380,8 +2328,7 @@ mod tests {
|
||||||
fn as_custom(&self) -> Option<&CustomBlock> {
|
fn as_custom(&self) -> Option<&CustomBlock> {
|
||||||
match self {
|
match self {
|
||||||
Block::Custom(block) => Some(block),
|
Block::Custom(block) => Some(block),
|
||||||
Block::ExcerptHeader { .. } => None,
|
Block::ExcerptBoundary { .. } => None,
|
||||||
Block::ExcerptFooter { .. } => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,12 +73,12 @@ use git::blame::GitBlame;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, impl_actions, point, prelude::*, px, relative, size, uniform_list, Action, AnyElement,
|
div, impl_actions, point, prelude::*, px, relative, size, uniform_list, Action, AnyElement,
|
||||||
AppContext, AsyncWindowContext, AvailableSpace, BackgroundExecutor, Bounds, ClipboardEntry,
|
AppContext, AsyncWindowContext, AvailableSpace, BackgroundExecutor, Bounds, ClipboardEntry,
|
||||||
ClipboardItem, Context, DispatchPhase, ElementId, EntityId, EventEmitter, FocusHandle,
|
ClipboardItem, Context, DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusOutEvent,
|
||||||
FocusOutEvent, FocusableView, FontId, FontWeight, HighlightStyle, Hsla, InteractiveText,
|
FocusableView, FontId, FontWeight, HighlightStyle, Hsla, InteractiveText, KeyContext,
|
||||||
KeyContext, ListSizingBehavior, Model, MouseButton, PaintQuad, ParentElement, Pixels, Render,
|
ListSizingBehavior, Model, MouseButton, PaintQuad, ParentElement, Pixels, Render, SharedString,
|
||||||
SharedString, Size, StrikethroughStyle, Styled, StyledText, Subscription, Task, TextStyle,
|
Size, StrikethroughStyle, Styled, StyledText, Subscription, Task, TextStyle, UTF16Selection,
|
||||||
UTF16Selection, UnderlineStyle, UniformListScrollHandle, View, ViewContext, ViewInputHandler,
|
UnderlineStyle, UniformListScrollHandle, View, ViewContext, ViewInputHandler, VisualContext,
|
||||||
VisualContext, WeakFocusHandle, WeakView, WindowContext,
|
WeakFocusHandle, WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
use highlight_matching_bracket::refresh_matching_bracket_highlights;
|
use highlight_matching_bracket::refresh_matching_bracket_highlights;
|
||||||
use hover_popover::{hide_hover, HoverState};
|
use hover_popover::{hide_hover, HoverState};
|
||||||
|
@ -171,7 +171,7 @@ use workspace::{Item as WorkspaceItem, OpenInTerminal, OpenTerminal, TabBarSetti
|
||||||
use crate::hover_links::find_url;
|
use crate::hover_links::find_url;
|
||||||
use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
|
use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
|
||||||
|
|
||||||
pub const FILE_HEADER_HEIGHT: u32 = 1;
|
pub const FILE_HEADER_HEIGHT: u32 = 2;
|
||||||
pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
|
pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
|
||||||
pub const MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT: u32 = 1;
|
pub const MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT: u32 = 1;
|
||||||
pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
|
pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
|
||||||
|
@ -640,7 +640,6 @@ pub struct Editor {
|
||||||
tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
|
tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
|
||||||
tasks_update_task: Option<Task<()>>,
|
tasks_update_task: Option<Task<()>>,
|
||||||
previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
|
previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
|
||||||
file_header_size: u32,
|
|
||||||
breadcrumb_header: Option<String>,
|
breadcrumb_header: Option<String>,
|
||||||
focused_block: Option<FocusedBlock>,
|
focused_block: Option<FocusedBlock>,
|
||||||
next_scroll_position: NextScrollCursorCenterTopBottom,
|
next_scroll_position: NextScrollCursorCenterTopBottom,
|
||||||
|
@ -1846,7 +1845,6 @@ impl Editor {
|
||||||
}),
|
}),
|
||||||
merge_adjacent: true,
|
merge_adjacent: true,
|
||||||
};
|
};
|
||||||
let file_header_size = if show_excerpt_controls { 3 } else { 2 };
|
|
||||||
let display_map = cx.new_model(|cx| {
|
let display_map = cx.new_model(|cx| {
|
||||||
DisplayMap::new(
|
DisplayMap::new(
|
||||||
buffer.clone(),
|
buffer.clone(),
|
||||||
|
@ -1854,7 +1852,7 @@ impl Editor {
|
||||||
font_size,
|
font_size,
|
||||||
None,
|
None,
|
||||||
show_excerpt_controls,
|
show_excerpt_controls,
|
||||||
file_header_size,
|
FILE_HEADER_HEIGHT,
|
||||||
MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
|
MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
|
||||||
MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT,
|
MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT,
|
||||||
fold_placeholder,
|
fold_placeholder,
|
||||||
|
@ -2038,7 +2036,6 @@ impl Editor {
|
||||||
.restore_unsaved_buffers,
|
.restore_unsaved_buffers,
|
||||||
blame: None,
|
blame: None,
|
||||||
blame_subscription: None,
|
blame_subscription: None,
|
||||||
file_header_size,
|
|
||||||
tasks: Default::default(),
|
tasks: Default::default(),
|
||||||
_subscriptions: vec![
|
_subscriptions: vec![
|
||||||
cx.observe(&buffer, Self::on_buffer_changed),
|
cx.observe(&buffer, Self::on_buffer_changed),
|
||||||
|
@ -12808,7 +12805,7 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_header_size(&self) -> u32 {
|
pub fn file_header_size(&self) -> u32 {
|
||||||
self.file_header_size
|
FILE_HEADER_HEIGHT
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn revert(
|
pub fn revert(
|
||||||
|
@ -14120,7 +14117,7 @@ pub fn diagnostic_block_renderer(
|
||||||
|
|
||||||
let multi_line_diagnostic = diagnostic.message.contains('\n');
|
let multi_line_diagnostic = diagnostic.message.contains('\n');
|
||||||
|
|
||||||
let buttons = |diagnostic: &Diagnostic, block_id: BlockId| {
|
let buttons = |diagnostic: &Diagnostic| {
|
||||||
if multi_line_diagnostic {
|
if multi_line_diagnostic {
|
||||||
v_flex()
|
v_flex()
|
||||||
} else {
|
} else {
|
||||||
|
@ -14128,7 +14125,7 @@ pub fn diagnostic_block_renderer(
|
||||||
}
|
}
|
||||||
.when(allow_closing, |div| {
|
.when(allow_closing, |div| {
|
||||||
div.children(diagnostic.is_primary.then(|| {
|
div.children(diagnostic.is_primary.then(|| {
|
||||||
IconButton::new(("close-block", EntityId::from(block_id)), IconName::XCircle)
|
IconButton::new("close-block", IconName::XCircle)
|
||||||
.icon_color(Color::Muted)
|
.icon_color(Color::Muted)
|
||||||
.size(ButtonSize::Compact)
|
.size(ButtonSize::Compact)
|
||||||
.style(ButtonStyle::Transparent)
|
.style(ButtonStyle::Transparent)
|
||||||
|
@ -14138,7 +14135,7 @@ pub fn diagnostic_block_renderer(
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
.child(
|
.child(
|
||||||
IconButton::new(("copy-block", EntityId::from(block_id)), IconName::Copy)
|
IconButton::new("copy-block", IconName::Copy)
|
||||||
.icon_color(Color::Muted)
|
.icon_color(Color::Muted)
|
||||||
.size(ButtonSize::Compact)
|
.size(ButtonSize::Compact)
|
||||||
.style(ButtonStyle::Transparent)
|
.style(ButtonStyle::Transparent)
|
||||||
|
@ -14153,7 +14150,7 @@ pub fn diagnostic_block_renderer(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let icon_size = buttons(&diagnostic, cx.block_id)
|
let icon_size = buttons(&diagnostic)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
.layout_as_root(AvailableSpace::min_size(), cx);
|
.layout_as_root(AvailableSpace::min_size(), cx);
|
||||||
|
|
||||||
|
@ -14170,7 +14167,7 @@ pub fn diagnostic_block_renderer(
|
||||||
.w(cx.anchor_x - cx.gutter_dimensions.width - icon_size.width)
|
.w(cx.anchor_x - cx.gutter_dimensions.width - icon_size.width)
|
||||||
.flex_shrink(),
|
.flex_shrink(),
|
||||||
)
|
)
|
||||||
.child(buttons(&diagnostic, cx.block_id))
|
.child(buttons(&diagnostic))
|
||||||
.child(div().flex().flex_shrink_0().child(
|
.child(div().flex().flex_shrink_0().child(
|
||||||
StyledText::new(text_without_backticks.clone()).with_highlights(
|
StyledText::new(text_without_backticks.clone()).with_highlights(
|
||||||
&text_style,
|
&text_style,
|
||||||
|
|
|
@ -21,7 +21,8 @@ use crate::{
|
||||||
EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GutterDimensions, HalfPageDown,
|
EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GutterDimensions, HalfPageDown,
|
||||||
HalfPageUp, HandleInput, HoveredCursor, HoveredHunk, LineDown, LineUp, OpenExcerpts, PageDown,
|
HalfPageUp, HandleInput, HoveredCursor, HoveredHunk, LineDown, LineUp, OpenExcerpts, PageDown,
|
||||||
PageUp, Point, RowExt, RowRangeExt, SelectPhase, Selection, SoftWrap, ToPoint,
|
PageUp, Point, RowExt, RowRangeExt, SelectPhase, Selection, SoftWrap, ToPoint,
|
||||||
CURSORS_VISIBLE_FOR, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN,
|
CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN,
|
||||||
|
MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
|
||||||
};
|
};
|
||||||
use client::ParticipantIndex;
|
use client::ParticipantIndex;
|
||||||
use collections::{BTreeMap, HashMap};
|
use collections::{BTreeMap, HashMap};
|
||||||
|
@ -31,7 +32,7 @@ use gpui::{
|
||||||
anchored, deferred, div, fill, outline, point, px, quad, relative, size, svg,
|
anchored, deferred, div, fill, outline, point, px, quad, relative, size, svg,
|
||||||
transparent_black, Action, AnchorCorner, AnyElement, AvailableSpace, Bounds, ClipboardItem,
|
transparent_black, Action, AnchorCorner, AnyElement, AvailableSpace, Bounds, ClipboardItem,
|
||||||
ContentMask, Corners, CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity,
|
ContentMask, Corners, CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity,
|
||||||
EntityId, FontId, GlobalElementId, Hitbox, Hsla, InteractiveElement, IntoElement, Length,
|
FontId, GlobalElementId, Hitbox, Hsla, InteractiveElement, IntoElement, Length,
|
||||||
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad,
|
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad,
|
||||||
ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString, Size,
|
ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString, Size,
|
||||||
StatefulInteractiveElement, Style, Styled, TextRun, TextStyle, TextStyleRefinement, View,
|
StatefulInteractiveElement, Style, Styled, TextRun, TextStyle, TextStyleRefinement, View,
|
||||||
|
@ -46,7 +47,7 @@ use language::{
|
||||||
ChunkRendererContext,
|
ChunkRendererContext,
|
||||||
};
|
};
|
||||||
use lsp::DiagnosticSeverity;
|
use lsp::DiagnosticSeverity;
|
||||||
use multi_buffer::{Anchor, MultiBufferPoint, MultiBufferRow};
|
use multi_buffer::{Anchor, ExcerptId, ExpandExcerptDirection, MultiBufferPoint, MultiBufferRow};
|
||||||
use project::{
|
use project::{
|
||||||
project_settings::{GitGutterSetting, ProjectSettings},
|
project_settings::{GitGutterSetting, ProjectSettings},
|
||||||
ProjectPath,
|
ProjectPath,
|
||||||
|
@ -1632,7 +1633,7 @@ impl EditorElement {
|
||||||
let mut block_offset = 0;
|
let mut block_offset = 0;
|
||||||
let mut found_excerpt_header = false;
|
let mut found_excerpt_header = false;
|
||||||
for (_, block) in snapshot.blocks_in_range(prev_line..row_range.start) {
|
for (_, block) in snapshot.blocks_in_range(prev_line..row_range.start) {
|
||||||
if matches!(block, Block::ExcerptHeader { .. }) {
|
if matches!(block, Block::ExcerptBoundary { .. }) {
|
||||||
found_excerpt_header = true;
|
found_excerpt_header = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1649,7 +1650,7 @@ impl EditorElement {
|
||||||
let mut block_height = 0;
|
let mut block_height = 0;
|
||||||
let mut found_excerpt_header = false;
|
let mut found_excerpt_header = false;
|
||||||
for (_, block) in snapshot.blocks_in_range(row_range.end..cons_line) {
|
for (_, block) in snapshot.blocks_in_range(row_range.end..cons_line) {
|
||||||
if matches!(block, Block::ExcerptHeader { .. }) {
|
if matches!(block, Block::ExcerptBoundary { .. }) {
|
||||||
found_excerpt_header = true;
|
found_excerpt_header = true;
|
||||||
}
|
}
|
||||||
block_height += block.height();
|
block_height += block.height();
|
||||||
|
@ -2100,23 +2101,14 @@ impl EditorElement {
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
|
|
||||||
Block::ExcerptHeader {
|
Block::ExcerptBoundary {
|
||||||
buffer,
|
prev_excerpt,
|
||||||
range,
|
next_excerpt,
|
||||||
|
show_excerpt_controls,
|
||||||
starts_new_buffer,
|
starts_new_buffer,
|
||||||
height,
|
height,
|
||||||
id,
|
|
||||||
show_excerpt_controls,
|
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let include_root = self
|
|
||||||
.editor
|
|
||||||
.read(cx)
|
|
||||||
.project
|
|
||||||
.as_ref()
|
|
||||||
.map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct JumpData {
|
struct JumpData {
|
||||||
position: Point,
|
position: Point,
|
||||||
|
@ -2125,233 +2117,227 @@ impl EditorElement {
|
||||||
line_offset_from_top: u32,
|
line_offset_from_top: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
let jump_data = project::File::from_dyn(buffer.file()).map(|file| {
|
|
||||||
let jump_path = ProjectPath {
|
|
||||||
worktree_id: file.worktree_id(cx),
|
|
||||||
path: file.path.clone(),
|
|
||||||
};
|
|
||||||
let jump_anchor = range
|
|
||||||
.primary
|
|
||||||
.as_ref()
|
|
||||||
.map_or(range.context.start, |primary| primary.start);
|
|
||||||
|
|
||||||
let excerpt_start = range.context.start;
|
|
||||||
let jump_position = language::ToPoint::to_point(&jump_anchor, buffer);
|
|
||||||
let offset_from_excerpt_start = if jump_anchor == excerpt_start {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
let excerpt_start_row =
|
|
||||||
language::ToPoint::to_point(&jump_anchor, buffer).row;
|
|
||||||
jump_position.row - excerpt_start_row
|
|
||||||
};
|
|
||||||
|
|
||||||
let line_offset_from_top =
|
|
||||||
block_row_start.0 + *height + offset_from_excerpt_start
|
|
||||||
- snapshot
|
|
||||||
.scroll_anchor
|
|
||||||
.scroll_position(&snapshot.display_snapshot)
|
|
||||||
.y as u32;
|
|
||||||
|
|
||||||
JumpData {
|
|
||||||
position: jump_position,
|
|
||||||
anchor: jump_anchor,
|
|
||||||
path: jump_path,
|
|
||||||
line_offset_from_top,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let icon_offset = gutter_dimensions.width
|
let icon_offset = gutter_dimensions.width
|
||||||
- (gutter_dimensions.left_padding + gutter_dimensions.margin);
|
- (gutter_dimensions.left_padding + gutter_dimensions.margin);
|
||||||
|
|
||||||
let element = if *starts_new_buffer {
|
let header_padding = px(6.0);
|
||||||
let path = buffer.resolve_file_path(cx, include_root);
|
|
||||||
let mut filename = None;
|
|
||||||
let mut parent_path = None;
|
|
||||||
// Can't use .and_then() because `.file_name()` and `.parent()` return references :(
|
|
||||||
if let Some(path) = path {
|
|
||||||
filename = path.file_name().map(|f| f.to_string_lossy().to_string());
|
|
||||||
parent_path = path
|
|
||||||
.parent()
|
|
||||||
.map(|p| SharedString::from(p.to_string_lossy().to_string() + "/"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let header_padding = px(6.0);
|
let mut result = v_flex().id(block_id).w_full();
|
||||||
|
|
||||||
v_flex()
|
if let Some(prev_excerpt) = prev_excerpt {
|
||||||
.id(("path excerpt header", EntityId::from(block_id)))
|
if *show_excerpt_controls {
|
||||||
.w_full()
|
result = result.child(
|
||||||
.px(header_padding)
|
|
||||||
.pt(header_padding)
|
|
||||||
.child(
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.flex_basis(Length::Definite(DefiniteLength::Fraction(0.667)))
|
.w(icon_offset)
|
||||||
.id("path header block")
|
.h(MULTI_BUFFER_EXCERPT_HEADER_HEIGHT as f32 * cx.line_height())
|
||||||
.h(2. * cx.line_height())
|
|
||||||
.px(gpui::px(12.))
|
|
||||||
.rounded_md()
|
|
||||||
.shadow_md()
|
|
||||||
.border_1()
|
|
||||||
.border_color(cx.theme().colors().border)
|
|
||||||
.bg(cx.theme().colors().editor_subheader_background)
|
|
||||||
.justify_between()
|
|
||||||
.hover(|style| style.bg(cx.theme().colors().element_hover))
|
|
||||||
.child(
|
|
||||||
h_flex().gap_3().child(
|
|
||||||
h_flex()
|
|
||||||
.gap_2()
|
|
||||||
.child(
|
|
||||||
filename
|
|
||||||
.map(SharedString::from)
|
|
||||||
.unwrap_or_else(|| "untitled".into()),
|
|
||||||
)
|
|
||||||
.when_some(parent_path, |then, path| {
|
|
||||||
then.child(
|
|
||||||
div()
|
|
||||||
.child(path)
|
|
||||||
.text_color(cx.theme().colors().text_muted),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.when_some(jump_data.clone(), |el, jump_data| {
|
|
||||||
el.child(Icon::new(IconName::ArrowUpRight))
|
|
||||||
.cursor_pointer()
|
|
||||||
.tooltip(|cx| {
|
|
||||||
Tooltip::for_action("Jump to File", &OpenExcerpts, cx)
|
|
||||||
})
|
|
||||||
.on_mouse_down(MouseButton::Left, |_, cx| {
|
|
||||||
cx.stop_propagation()
|
|
||||||
})
|
|
||||||
.on_click(cx.listener_for(&self.editor, {
|
|
||||||
move |editor, _, cx| {
|
|
||||||
editor.jump(
|
|
||||||
jump_data.path.clone(),
|
|
||||||
jump_data.position,
|
|
||||||
jump_data.anchor,
|
|
||||||
jump_data.line_offset_from_top,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.children(show_excerpt_controls.then(|| {
|
|
||||||
h_flex()
|
|
||||||
.flex_basis(Length::Definite(DefiniteLength::Fraction(0.333)))
|
|
||||||
.h(1. * cx.line_height())
|
|
||||||
.pt_1()
|
|
||||||
.justify_end()
|
|
||||||
.flex_none()
|
.flex_none()
|
||||||
.w(icon_offset - header_padding)
|
.justify_end()
|
||||||
.child(
|
.child(self.render_expand_excerpt_button(
|
||||||
ButtonLike::new("expand-icon")
|
prev_excerpt.id,
|
||||||
.style(ButtonStyle::Transparent)
|
ExpandExcerptDirection::Down,
|
||||||
.child(
|
IconName::ArrowDownFromLine,
|
||||||
svg()
|
cx,
|
||||||
.path(IconName::ArrowUpFromLine.path())
|
)),
|
||||||
.size(IconSize::XSmall.rems())
|
);
|
||||||
.text_color(cx.theme().colors().editor_line_number)
|
}
|
||||||
.group("")
|
}
|
||||||
.hover(|style| {
|
|
||||||
style.text_color(
|
if let Some(next_excerpt) = next_excerpt {
|
||||||
cx.theme()
|
let buffer = &next_excerpt.buffer;
|
||||||
.colors()
|
let range = &next_excerpt.range;
|
||||||
.editor_active_line_number,
|
let jump_data = project::File::from_dyn(buffer.file()).map(|file| {
|
||||||
)
|
let jump_path = ProjectPath {
|
||||||
}),
|
worktree_id: file.worktree_id(cx),
|
||||||
)
|
path: file.path.clone(),
|
||||||
.on_click(cx.listener_for(&self.editor, {
|
};
|
||||||
let id = *id;
|
let jump_anchor = range
|
||||||
move |editor, _, cx| {
|
.primary
|
||||||
editor.expand_excerpt(
|
.as_ref()
|
||||||
id,
|
.map_or(range.context.start, |primary| primary.start);
|
||||||
multi_buffer::ExpandExcerptDirection::Up,
|
|
||||||
cx,
|
let excerpt_start = range.context.start;
|
||||||
);
|
let jump_position = language::ToPoint::to_point(&jump_anchor, buffer);
|
||||||
}
|
let offset_from_excerpt_start = if jump_anchor == excerpt_start {
|
||||||
}))
|
0
|
||||||
.tooltip({
|
} else {
|
||||||
move |cx| {
|
let excerpt_start_row =
|
||||||
Tooltip::for_action(
|
language::ToPoint::to_point(&jump_anchor, buffer).row;
|
||||||
"Expand Excerpt",
|
jump_position.row - excerpt_start_row
|
||||||
&ExpandExcerpts { lines: 0 },
|
};
|
||||||
cx,
|
|
||||||
)
|
let line_offset_from_top =
|
||||||
}
|
block_row_start.0 + *height + offset_from_excerpt_start
|
||||||
}),
|
- snapshot
|
||||||
)
|
.scroll_anchor
|
||||||
}))
|
.scroll_position(&snapshot.display_snapshot)
|
||||||
} else {
|
.y as u32;
|
||||||
v_flex()
|
|
||||||
.id(("excerpt header", EntityId::from(block_id)))
|
JumpData {
|
||||||
.w_full()
|
position: jump_position,
|
||||||
.h(snapshot.excerpt_header_height() as f32 * cx.line_height())
|
anchor: jump_anchor,
|
||||||
.child(
|
path: jump_path,
|
||||||
|
line_offset_from_top,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if *starts_new_buffer {
|
||||||
|
let include_root = self
|
||||||
|
.editor
|
||||||
|
.read(cx)
|
||||||
|
.project
|
||||||
|
.as_ref()
|
||||||
|
.map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
|
||||||
|
.unwrap_or_default();
|
||||||
|
let path = buffer.resolve_file_path(cx, include_root);
|
||||||
|
let filename = path
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|path| Some(path.file_name()?.to_string_lossy().to_string()));
|
||||||
|
let parent_path = path.as_ref().and_then(|path| {
|
||||||
|
Some(path.parent()?.to_string_lossy().to_string() + "/")
|
||||||
|
});
|
||||||
|
|
||||||
|
result = result.child(
|
||||||
div()
|
div()
|
||||||
.flex()
|
.px(header_padding)
|
||||||
.v_flex()
|
.pt(header_padding)
|
||||||
|
.w_full()
|
||||||
|
.h(FILE_HEADER_HEIGHT as f32 * cx.line_height())
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.id("path header block")
|
||||||
|
.size_full()
|
||||||
|
.flex_basis(Length::Definite(DefiniteLength::Fraction(
|
||||||
|
0.667,
|
||||||
|
)))
|
||||||
|
.px(gpui::px(12.))
|
||||||
|
.rounded_md()
|
||||||
|
.shadow_md()
|
||||||
|
.border_1()
|
||||||
|
.border_color(cx.theme().colors().border)
|
||||||
|
.bg(cx.theme().colors().editor_subheader_background)
|
||||||
|
.justify_between()
|
||||||
|
.hover(|style| style.bg(cx.theme().colors().element_hover))
|
||||||
|
.child(
|
||||||
|
h_flex().gap_3().child(
|
||||||
|
h_flex()
|
||||||
|
.gap_2()
|
||||||
|
.child(
|
||||||
|
filename
|
||||||
|
.map(SharedString::from)
|
||||||
|
.unwrap_or_else(|| "untitled".into()),
|
||||||
|
)
|
||||||
|
.when_some(parent_path, |then, path| {
|
||||||
|
then.child(div().child(path).text_color(
|
||||||
|
cx.theme().colors().text_muted,
|
||||||
|
))
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.when_some(jump_data, |el, jump_data| {
|
||||||
|
el.child(Icon::new(IconName::ArrowUpRight))
|
||||||
|
.cursor_pointer()
|
||||||
|
.tooltip(|cx| {
|
||||||
|
Tooltip::for_action(
|
||||||
|
"Jump to File",
|
||||||
|
&OpenExcerpts,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.on_mouse_down(MouseButton::Left, |_, cx| {
|
||||||
|
cx.stop_propagation()
|
||||||
|
})
|
||||||
|
.on_click(cx.listener_for(&self.editor, {
|
||||||
|
move |editor, _, cx| {
|
||||||
|
editor.jump(
|
||||||
|
jump_data.path.clone(),
|
||||||
|
jump_data.position,
|
||||||
|
jump_data.anchor,
|
||||||
|
jump_data.line_offset_from_top,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if *show_excerpt_controls {
|
||||||
|
result = result.child(
|
||||||
|
h_flex()
|
||||||
|
.w(icon_offset)
|
||||||
|
.h(MULTI_BUFFER_EXCERPT_HEADER_HEIGHT as f32 * cx.line_height())
|
||||||
|
.flex_none()
|
||||||
|
.justify_end()
|
||||||
|
.child(self.render_expand_excerpt_button(
|
||||||
|
next_excerpt.id,
|
||||||
|
ExpandExcerptDirection::Up,
|
||||||
|
IconName::ArrowUpFromLine,
|
||||||
|
cx,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = result.child(
|
||||||
|
h_flex()
|
||||||
|
.id("excerpt header block")
|
||||||
|
.group("excerpt-jump-action")
|
||||||
.justify_start()
|
.justify_start()
|
||||||
.id("jump to collapsed context")
|
.w_full()
|
||||||
.w(relative(1.0))
|
.h(MULTI_BUFFER_EXCERPT_HEADER_HEIGHT as f32 * cx.line_height())
|
||||||
.h_full()
|
.relative()
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.h_px()
|
.top(px(0.))
|
||||||
|
.absolute()
|
||||||
.w_full()
|
.w_full()
|
||||||
|
.h_px()
|
||||||
.bg(cx.theme().colors().border_variant)
|
.bg(cx.theme().colors().border_variant)
|
||||||
.group_hover("excerpt-jump-action", |style| {
|
.group_hover("excerpt-jump-action", |style| {
|
||||||
style.bg(cx.theme().colors().border)
|
style.bg(cx.theme().colors().border)
|
||||||
}),
|
}),
|
||||||
),
|
)
|
||||||
)
|
.cursor_pointer()
|
||||||
.child(
|
.when_some(jump_data.clone(), |this, jump_data| {
|
||||||
h_flex()
|
this.on_click(cx.listener_for(&self.editor, {
|
||||||
.justify_end()
|
let path = jump_data.path.clone();
|
||||||
.flex_none()
|
move |editor, _, cx| {
|
||||||
.w(icon_offset)
|
cx.stop_propagation();
|
||||||
.h_full()
|
|
||||||
|
editor.jump(
|
||||||
|
path.clone(),
|
||||||
|
jump_data.position,
|
||||||
|
jump_data.anchor,
|
||||||
|
jump_data.line_offset_from_top,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.tooltip(move |cx| {
|
||||||
|
Tooltip::for_action(
|
||||||
|
format!(
|
||||||
|
"Jump to {}:L{}",
|
||||||
|
jump_data.path.path.display(),
|
||||||
|
jump_data.position.row + 1
|
||||||
|
),
|
||||||
|
&OpenExcerpts,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
.child(
|
.child(
|
||||||
show_excerpt_controls
|
h_flex()
|
||||||
.then(|| {
|
.w(icon_offset)
|
||||||
ButtonLike::new("expand-icon")
|
.h(MULTI_BUFFER_EXCERPT_HEADER_HEIGHT as f32
|
||||||
.style(ButtonStyle::Transparent)
|
* cx.line_height())
|
||||||
.child(
|
.flex_none()
|
||||||
svg()
|
.justify_end()
|
||||||
.path(IconName::ArrowUpFromLine.path())
|
.child(if *show_excerpt_controls {
|
||||||
.size(IconSize::XSmall.rems())
|
self.render_expand_excerpt_button(
|
||||||
.text_color(
|
next_excerpt.id,
|
||||||
cx.theme().colors().editor_line_number,
|
ExpandExcerptDirection::Up,
|
||||||
)
|
IconName::ArrowUpFromLine,
|
||||||
.group("")
|
cx,
|
||||||
.hover(|style| {
|
)
|
||||||
style.text_color(
|
} else {
|
||||||
cx.theme()
|
|
||||||
.colors()
|
|
||||||
.editor_active_line_number,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.on_click(cx.listener_for(&self.editor, {
|
|
||||||
let id = *id;
|
|
||||||
move |editor, _, cx| {
|
|
||||||
editor.expand_excerpt(
|
|
||||||
id,
|
|
||||||
multi_buffer::ExpandExcerptDirection::Up,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.tooltip({
|
|
||||||
move |cx| {
|
|
||||||
Tooltip::for_action(
|
|
||||||
"Expand Excerpt",
|
|
||||||
&ExpandExcerpts { lines: 0 },
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
ButtonLike::new("jump-icon")
|
ButtonLike::new("jump-icon")
|
||||||
.style(ButtonStyle::Transparent)
|
.style(ButtonStyle::Transparent)
|
||||||
.child(
|
.child(
|
||||||
|
@ -2361,7 +2347,6 @@ impl EditorElement {
|
||||||
.text_color(
|
.text_color(
|
||||||
cx.theme().colors().border_variant,
|
cx.theme().colors().border_variant,
|
||||||
)
|
)
|
||||||
.group("excerpt-jump-action")
|
|
||||||
.group_hover(
|
.group_hover(
|
||||||
"excerpt-jump-action",
|
"excerpt-jump-action",
|
||||||
|style| {
|
|style| {
|
||||||
|
@ -2371,118 +2356,13 @@ impl EditorElement {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.when_some(jump_data.clone(), |this, jump_data| {
|
|
||||||
this.on_click(cx.listener_for(&self.editor, {
|
|
||||||
let path = jump_data.path.clone();
|
|
||||||
move |editor, _, cx| {
|
|
||||||
cx.stop_propagation();
|
|
||||||
|
|
||||||
editor.jump(
|
|
||||||
path.clone(),
|
|
||||||
jump_data.position,
|
|
||||||
jump_data.anchor,
|
|
||||||
jump_data.line_offset_from_top,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.tooltip(move |cx| {
|
|
||||||
Tooltip::for_action(
|
|
||||||
format!(
|
|
||||||
"Jump to {}:L{}",
|
|
||||||
jump_data.path.path.display(),
|
|
||||||
jump_data.position.row + 1
|
|
||||||
),
|
|
||||||
&OpenExcerpts,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
);
|
||||||
.group("excerpt-jump-action")
|
}
|
||||||
.cursor_pointer()
|
}
|
||||||
.when_some(jump_data.clone(), |this, jump_data| {
|
|
||||||
this.on_click(cx.listener_for(&self.editor, {
|
|
||||||
let path = jump_data.path.clone();
|
|
||||||
move |editor, _, cx| {
|
|
||||||
cx.stop_propagation();
|
|
||||||
|
|
||||||
editor.jump(
|
result.into_any()
|
||||||
path.clone(),
|
|
||||||
jump_data.position,
|
|
||||||
jump_data.anchor,
|
|
||||||
jump_data.line_offset_from_top,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.tooltip(move |cx| {
|
|
||||||
Tooltip::for_action(
|
|
||||||
format!(
|
|
||||||
"Jump to {}:L{}",
|
|
||||||
jump_data.path.path.display(),
|
|
||||||
jump_data.position.row + 1
|
|
||||||
),
|
|
||||||
&OpenExcerpts,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
};
|
|
||||||
element.into_any()
|
|
||||||
}
|
|
||||||
|
|
||||||
Block::ExcerptFooter { id, .. } => {
|
|
||||||
let element = v_flex()
|
|
||||||
.id(("excerpt footer", EntityId::from(block_id)))
|
|
||||||
.w_full()
|
|
||||||
.h(snapshot.excerpt_footer_height() as f32 * cx.line_height())
|
|
||||||
.child(
|
|
||||||
h_flex()
|
|
||||||
.justify_end()
|
|
||||||
.flex_none()
|
|
||||||
.w(gutter_dimensions.width
|
|
||||||
- (gutter_dimensions.left_padding + gutter_dimensions.margin))
|
|
||||||
.h_full()
|
|
||||||
.child(
|
|
||||||
ButtonLike::new("expand-icon")
|
|
||||||
.style(ButtonStyle::Transparent)
|
|
||||||
.child(
|
|
||||||
svg()
|
|
||||||
.path(IconName::ArrowDownFromLine.path())
|
|
||||||
.size(IconSize::XSmall.rems())
|
|
||||||
.text_color(cx.theme().colors().editor_line_number)
|
|
||||||
.group("")
|
|
||||||
.hover(|style| {
|
|
||||||
style.text_color(
|
|
||||||
cx.theme().colors().editor_active_line_number,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.on_click(cx.listener_for(&self.editor, {
|
|
||||||
let id = *id;
|
|
||||||
move |editor, _, cx| {
|
|
||||||
editor.expand_excerpt(
|
|
||||||
id,
|
|
||||||
multi_buffer::ExpandExcerptDirection::Down,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.tooltip({
|
|
||||||
move |cx| {
|
|
||||||
Tooltip::for_action(
|
|
||||||
"Expand Excerpt",
|
|
||||||
&ExpandExcerpts { lines: 0 },
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
element.into_any()
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2509,6 +2389,33 @@ impl EditorElement {
|
||||||
(element, final_size)
|
(element, final_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_expand_excerpt_button(
|
||||||
|
&self,
|
||||||
|
excerpt_id: ExcerptId,
|
||||||
|
direction: ExpandExcerptDirection,
|
||||||
|
icon: IconName,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> ButtonLike {
|
||||||
|
ButtonLike::new("expand-icon")
|
||||||
|
.style(ButtonStyle::Transparent)
|
||||||
|
.child(
|
||||||
|
svg()
|
||||||
|
.path(icon.path())
|
||||||
|
.size(IconSize::XSmall.rems())
|
||||||
|
.text_color(cx.theme().colors().editor_line_number)
|
||||||
|
.group("")
|
||||||
|
.hover(|style| style.text_color(cx.theme().colors().editor_active_line_number)),
|
||||||
|
)
|
||||||
|
.on_click(cx.listener_for(&self.editor, {
|
||||||
|
move |editor, _, cx| {
|
||||||
|
editor.expand_excerpt(excerpt_id, direction, cx);
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.tooltip({
|
||||||
|
move |cx| Tooltip::for_action("Expand Excerpt", &ExpandExcerpts { lines: 0 }, cx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn render_blocks(
|
fn render_blocks(
|
||||||
&self,
|
&self,
|
||||||
|
@ -3367,7 +3274,7 @@ impl EditorElement {
|
||||||
let end_row_in_current_excerpt = snapshot
|
let end_row_in_current_excerpt = snapshot
|
||||||
.blocks_in_range(start_row..end_row)
|
.blocks_in_range(start_row..end_row)
|
||||||
.find_map(|(start_row, block)| {
|
.find_map(|(start_row, block)| {
|
||||||
if matches!(block, Block::ExcerptHeader { .. }) {
|
if matches!(block, Block::ExcerptBoundary { .. }) {
|
||||||
Some(start_row)
|
Some(start_row)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -952,7 +952,7 @@ mod tests {
|
||||||
px(14.0),
|
px(14.0),
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
2,
|
0,
|
||||||
2,
|
2,
|
||||||
0,
|
0,
|
||||||
FoldPlaceholder::test(),
|
FoldPlaceholder::test(),
|
||||||
|
|
|
@ -189,6 +189,7 @@ pub struct MultiBufferSnapshot {
|
||||||
show_headers: bool,
|
show_headers: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ExcerptInfo {
|
pub struct ExcerptInfo {
|
||||||
pub id: ExcerptId,
|
pub id: ExcerptId,
|
||||||
pub buffer: BufferSnapshot,
|
pub buffer: BufferSnapshot,
|
||||||
|
@ -201,6 +202,7 @@ impl std::fmt::Debug for ExcerptInfo {
|
||||||
f.debug_struct(type_name::<Self>())
|
f.debug_struct(type_name::<Self>())
|
||||||
.field("id", &self.id)
|
.field("id", &self.id)
|
||||||
.field("buffer_id", &self.buffer_id)
|
.field("buffer_id", &self.buffer_id)
|
||||||
|
.field("path", &self.buffer.file().map(|f| f.path()))
|
||||||
.field("range", &self.range)
|
.field("range", &self.range)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,7 @@ use editor::{
|
||||||
use futures::io::BufReader;
|
use futures::io::BufReader;
|
||||||
use futures::{AsyncBufReadExt as _, FutureExt as _, StreamExt as _};
|
use futures::{AsyncBufReadExt as _, FutureExt as _, StreamExt as _};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::*, EntityId, EventEmitter, Model, Render, Subscription, Task, View, ViewContext,
|
div, prelude::*, EventEmitter, Model, Render, Subscription, Task, View, ViewContext, WeakView,
|
||||||
WeakView,
|
|
||||||
};
|
};
|
||||||
use language::Point;
|
use language::Point;
|
||||||
use project::Fs;
|
use project::Fs;
|
||||||
|
@ -149,23 +148,21 @@ impl EditorBlock {
|
||||||
.w(text_line_height)
|
.w(text_line_height)
|
||||||
.h(text_line_height)
|
.h(text_line_height)
|
||||||
.child(
|
.child(
|
||||||
IconButton::new(
|
IconButton::new("close_output_area", IconName::Close)
|
||||||
("close_output_area", EntityId::from(cx.block_id)),
|
.icon_size(IconSize::Small)
|
||||||
IconName::Close,
|
.icon_color(Color::Muted)
|
||||||
)
|
.size(ButtonSize::Compact)
|
||||||
.icon_size(IconSize::Small)
|
.shape(IconButtonShape::Square)
|
||||||
.icon_color(Color::Muted)
|
.tooltip(|cx| Tooltip::text("Close output area", cx))
|
||||||
.size(ButtonSize::Compact)
|
.on_click(move |_, cx| {
|
||||||
.shape(IconButtonShape::Square)
|
if let BlockId::Custom(block_id) = block_id {
|
||||||
.tooltip(|cx| Tooltip::text("Close output area", cx))
|
(on_close)(block_id, cx)
|
||||||
.on_click(move |_, cx| {
|
}
|
||||||
if let BlockId::Custom(block_id) = block_id {
|
}),
|
||||||
(on_close)(block_id, cx)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
div()
|
div()
|
||||||
|
.id(cx.block_id)
|
||||||
.flex()
|
.flex()
|
||||||
.items_start()
|
.items_start()
|
||||||
.min_h(text_line_height)
|
.min_h(text_line_height)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue