Add file icons to multibuffer view (#36836)
<img width="1988" height="1420" alt="multi-buffer-icons-git-diff" src="https://github.com/user-attachments/assets/48f9722f-ca09-4aa7-ad7a-0b7e85f440d9" /> Unfortunately, `cargo format` decided to reformat everything. Probably, because of hitting the right margin, no idea. The essence of this change is the following: ```rust .map(|path_header| { let filename = filename .map(SharedString::from) .unwrap_or_else(|| "untitled".into()); let path = path::Path::new(filename.as_str()); let icon = FileIcons::get_icon(path, cx).unwrap_or_default(); let icon = Icon::from_path(icon).color(Color::Muted); let label = Label::new(filename).single_line().when_some( file_status, |el, status| { el.color(if status.is_conflicted() { Color::Conflict } else if status.is_modified() { Color::Modified } else if status.is_deleted() { Color::Disabled } else { Color::Created }) .when(status.is_deleted(), |el| el.strikethrough()) }, ); path_header.child(icon).child(label) }) ``` Release Notes: - Added file icons to multi buffer view
This commit is contained in:
parent
a79aef7bdd
commit
11545c669e
1 changed files with 175 additions and 164 deletions
|
@ -74,7 +74,7 @@ use std::{
|
||||||
fmt::{self, Write},
|
fmt::{self, Write},
|
||||||
iter, mem,
|
iter, mem,
|
||||||
ops::{Deref, Range},
|
ops::{Deref, Range},
|
||||||
path::Path,
|
path::{self, Path},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
|
@ -90,8 +90,8 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||||
use util::post_inc;
|
use util::post_inc;
|
||||||
use util::{RangeExt, ResultExt, debug_panic};
|
use util::{RangeExt, ResultExt, debug_panic};
|
||||||
use workspace::{
|
use workspace::{
|
||||||
CollaboratorId, OpenInTerminal, OpenTerminal, RevealInProjectPanel, Workspace, item::Item,
|
CollaboratorId, ItemSettings, OpenInTerminal, OpenTerminal, RevealInProjectPanel, Workspace,
|
||||||
notifications::NotifyTaskExt,
|
item::Item, notifications::NotifyTaskExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Determines what kinds of highlights should be applied to a lines background.
|
/// Determines what kinds of highlights should be applied to a lines background.
|
||||||
|
@ -3603,176 +3603,187 @@ impl EditorElement {
|
||||||
let focus_handle = editor.focus_handle(cx);
|
let focus_handle = editor.focus_handle(cx);
|
||||||
let colors = cx.theme().colors();
|
let colors = cx.theme().colors();
|
||||||
|
|
||||||
let header =
|
let header = div()
|
||||||
div()
|
.p_1()
|
||||||
.p_1()
|
.w_full()
|
||||||
.w_full()
|
.h(FILE_HEADER_HEIGHT as f32 * window.line_height())
|
||||||
.h(FILE_HEADER_HEIGHT as f32 * window.line_height())
|
.child(
|
||||||
.child(
|
h_flex()
|
||||||
h_flex()
|
.size_full()
|
||||||
.size_full()
|
.gap_2()
|
||||||
.gap_2()
|
.flex_basis(Length::Definite(DefiniteLength::Fraction(0.667)))
|
||||||
.flex_basis(Length::Definite(DefiniteLength::Fraction(0.667)))
|
.pl_0p5()
|
||||||
.pl_0p5()
|
.pr_5()
|
||||||
.pr_5()
|
.rounded_sm()
|
||||||
.rounded_sm()
|
.when(is_sticky, |el| el.shadow_md())
|
||||||
.when(is_sticky, |el| el.shadow_md())
|
.border_1()
|
||||||
.border_1()
|
.map(|div| {
|
||||||
.map(|div| {
|
let border_color = if is_selected
|
||||||
let border_color = if is_selected
|
&& is_folded
|
||||||
&& is_folded
|
&& focus_handle.contains_focused(window, cx)
|
||||||
&& focus_handle.contains_focused(window, cx)
|
{
|
||||||
{
|
colors.border_focused
|
||||||
colors.border_focused
|
} else {
|
||||||
} else {
|
colors.border
|
||||||
colors.border
|
};
|
||||||
};
|
div.border_color(border_color)
|
||||||
div.border_color(border_color)
|
})
|
||||||
})
|
.bg(colors.editor_subheader_background)
|
||||||
.bg(colors.editor_subheader_background)
|
.hover(|style| style.bg(colors.element_hover))
|
||||||
.hover(|style| style.bg(colors.element_hover))
|
.map(|header| {
|
||||||
.map(|header| {
|
let editor = self.editor.clone();
|
||||||
let editor = self.editor.clone();
|
let buffer_id = for_excerpt.buffer_id;
|
||||||
let buffer_id = for_excerpt.buffer_id;
|
let toggle_chevron_icon =
|
||||||
let toggle_chevron_icon =
|
FileIcons::get_chevron_icon(!is_folded, cx).map(Icon::from_path);
|
||||||
FileIcons::get_chevron_icon(!is_folded, cx).map(Icon::from_path);
|
header.child(
|
||||||
header.child(
|
div()
|
||||||
div()
|
.hover(|style| style.bg(colors.element_selected))
|
||||||
.hover(|style| style.bg(colors.element_selected))
|
.rounded_xs()
|
||||||
.rounded_xs()
|
.child(
|
||||||
.child(
|
ButtonLike::new("toggle-buffer-fold")
|
||||||
ButtonLike::new("toggle-buffer-fold")
|
.style(ui::ButtonStyle::Transparent)
|
||||||
.style(ui::ButtonStyle::Transparent)
|
.height(px(28.).into())
|
||||||
.height(px(28.).into())
|
.width(px(28.))
|
||||||
.width(px(28.))
|
.children(toggle_chevron_icon)
|
||||||
.children(toggle_chevron_icon)
|
.tooltip({
|
||||||
.tooltip({
|
let focus_handle = focus_handle.clone();
|
||||||
let focus_handle = focus_handle.clone();
|
move |window, cx| {
|
||||||
move |window, cx| {
|
Tooltip::with_meta_in(
|
||||||
Tooltip::with_meta_in(
|
"Toggle Excerpt Fold",
|
||||||
"Toggle Excerpt Fold",
|
Some(&ToggleFold),
|
||||||
Some(&ToggleFold),
|
"Alt+click to toggle all",
|
||||||
"Alt+click to toggle all",
|
&focus_handle,
|
||||||
&focus_handle,
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_click(move |event, window, cx| {
|
||||||
|
if event.modifiers().alt {
|
||||||
|
// Alt+click toggles all buffers
|
||||||
|
editor.update(cx, |editor, cx| {
|
||||||
|
editor.toggle_fold_all(
|
||||||
|
&ToggleFoldAll,
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
)
|
);
|
||||||
}
|
});
|
||||||
})
|
} else {
|
||||||
.on_click(move |event, window, cx| {
|
// Regular click toggles single buffer
|
||||||
if event.modifiers().alt {
|
if is_folded {
|
||||||
// Alt+click toggles all buffers
|
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
editor.toggle_fold_all(
|
editor.unfold_buffer(buffer_id, cx);
|
||||||
&ToggleFoldAll,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Regular click toggles single buffer
|
editor.update(cx, |editor, cx| {
|
||||||
if is_folded {
|
editor.fold_buffer(buffer_id, cx);
|
||||||
editor.update(cx, |editor, cx| {
|
});
|
||||||
editor.unfold_buffer(buffer_id, cx);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
editor.update(cx, |editor, cx| {
|
|
||||||
editor.fold_buffer(buffer_id, cx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
),
|
}),
|
||||||
)
|
),
|
||||||
})
|
|
||||||
.children(
|
|
||||||
editor
|
|
||||||
.addons
|
|
||||||
.values()
|
|
||||||
.filter_map(|addon| {
|
|
||||||
addon.render_buffer_header_controls(for_excerpt, window, cx)
|
|
||||||
})
|
|
||||||
.take(1),
|
|
||||||
)
|
)
|
||||||
.child(
|
})
|
||||||
h_flex()
|
.children(
|
||||||
.size(Pixels(12.0))
|
editor
|
||||||
.justify_center()
|
.addons
|
||||||
.children(indicator),
|
.values()
|
||||||
)
|
.filter_map(|addon| {
|
||||||
.child(
|
addon.render_buffer_header_controls(for_excerpt, window, cx)
|
||||||
h_flex()
|
})
|
||||||
.cursor_pointer()
|
.take(1),
|
||||||
.id("path header block")
|
)
|
||||||
.size_full()
|
.child(
|
||||||
.justify_between()
|
h_flex()
|
||||||
.overflow_hidden()
|
.size(Pixels(12.0))
|
||||||
.child(
|
.justify_center()
|
||||||
h_flex()
|
.children(indicator),
|
||||||
.gap_2()
|
)
|
||||||
.child(
|
.child(
|
||||||
Label::new(
|
h_flex()
|
||||||
filename
|
.cursor_pointer()
|
||||||
.map(SharedString::from)
|
.id("path header block")
|
||||||
.unwrap_or_else(|| "untitled".into()),
|
.size_full()
|
||||||
)
|
.justify_between()
|
||||||
.single_line()
|
.overflow_hidden()
|
||||||
.when_some(file_status, |el, status| {
|
.child(
|
||||||
el.color(if status.is_conflicted() {
|
h_flex()
|
||||||
Color::Conflict
|
.gap_2()
|
||||||
} else if status.is_modified() {
|
.map(|path_header| {
|
||||||
Color::Modified
|
let filename = filename
|
||||||
} else if status.is_deleted() {
|
.map(SharedString::from)
|
||||||
Color::Disabled
|
.unwrap_or_else(|| "untitled".into());
|
||||||
} else {
|
|
||||||
Color::Created
|
path_header
|
||||||
})
|
.when(ItemSettings::get_global(cx).file_icons, |el| {
|
||||||
.when(status.is_deleted(), |el| el.strikethrough())
|
let path = path::Path::new(filename.as_str());
|
||||||
}),
|
let icon = FileIcons::get_icon(path, cx)
|
||||||
)
|
.unwrap_or_default();
|
||||||
.when_some(parent_path, |then, path| {
|
let icon =
|
||||||
then.child(div().child(path).text_color(
|
Icon::from_path(icon).color(Color::Muted);
|
||||||
if file_status.is_some_and(FileStatus::is_deleted) {
|
el.child(icon)
|
||||||
colors.text_disabled
|
})
|
||||||
} else {
|
.child(Label::new(filename).single_line().when_some(
|
||||||
colors.text_muted
|
file_status,
|
||||||
|
|el, status| {
|
||||||
|
el.color(if status.is_conflicted() {
|
||||||
|
Color::Conflict
|
||||||
|
} else if status.is_modified() {
|
||||||
|
Color::Modified
|
||||||
|
} else if status.is_deleted() {
|
||||||
|
Color::Disabled
|
||||||
|
} else {
|
||||||
|
Color::Created
|
||||||
|
})
|
||||||
|
.when(status.is_deleted(), |el| {
|
||||||
|
el.strikethrough()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}),
|
})
|
||||||
)
|
.when_some(parent_path, |then, path| {
|
||||||
.when(
|
then.child(div().child(path).text_color(
|
||||||
can_open_excerpts && is_selected && relative_path.is_some(),
|
if file_status.is_some_and(FileStatus::is_deleted) {
|
||||||
|el| {
|
colors.text_disabled
|
||||||
el.child(
|
} else {
|
||||||
h_flex()
|
colors.text_muted
|
||||||
.id("jump-to-file-button")
|
},
|
||||||
.gap_2p5()
|
))
|
||||||
.child(Label::new("Jump To File"))
|
}),
|
||||||
.children(
|
)
|
||||||
KeyBinding::for_action_in(
|
.when(
|
||||||
&OpenExcerpts,
|
can_open_excerpts && is_selected && relative_path.is_some(),
|
||||||
&focus_handle,
|
|el| {
|
||||||
window,
|
el.child(
|
||||||
cx,
|
h_flex()
|
||||||
)
|
.id("jump-to-file-button")
|
||||||
.map(|binding| binding.into_any_element()),
|
.gap_2p5()
|
||||||
),
|
.child(Label::new("Jump To File"))
|
||||||
)
|
.children(
|
||||||
},
|
KeyBinding::for_action_in(
|
||||||
)
|
&OpenExcerpts,
|
||||||
.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
|
&focus_handle,
|
||||||
.on_click(window.listener_for(&self.editor, {
|
window,
|
||||||
move |editor, e: &ClickEvent, window, cx| {
|
cx,
|
||||||
editor.open_excerpts_common(
|
)
|
||||||
Some(jump_data.clone()),
|
.map(|binding| binding.into_any_element()),
|
||||||
e.modifiers().secondary(),
|
),
|
||||||
window,
|
)
|
||||||
cx,
|
},
|
||||||
);
|
)
|
||||||
}
|
.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
|
||||||
})),
|
.on_click(window.listener_for(&self.editor, {
|
||||||
),
|
move |editor, e: &ClickEvent, window, cx| {
|
||||||
);
|
editor.open_excerpts_common(
|
||||||
|
Some(jump_data.clone()),
|
||||||
|
e.modifiers().secondary(),
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
let file = for_excerpt.buffer.file().cloned();
|
let file = for_excerpt.buffer.file().cloned();
|
||||||
let editor = self.editor.clone();
|
let editor = self.editor.clone();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue