Render a "Jump to Buffer" icon on all excerpt headers
This commit is contained in:
parent
c2eaf6128e
commit
712d47d94f
7 changed files with 86 additions and 74 deletions
|
@ -9,13 +9,13 @@ use editor::{
|
||||||
ToOffset,
|
ToOffset,
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, elements::*, fonts::TextStyle, impl_internal_actions, platform::CursorStyle,
|
actions, elements::*, fonts::TextStyle, impl_internal_actions, serde_json, AnyViewHandle,
|
||||||
serde_json, AnyViewHandle, AppContext, Entity, ModelHandle, MutableAppContext, RenderContext,
|
AppContext, Entity, ModelHandle, MutableAppContext, RenderContext, Task, View, ViewContext,
|
||||||
Task, View, ViewContext, ViewHandle, WeakViewHandle,
|
ViewHandle, WeakViewHandle,
|
||||||
};
|
};
|
||||||
use language::{
|
use language::{
|
||||||
Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection,
|
Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection,
|
||||||
SelectionGoal, ToPoint,
|
SelectionGoal,
|
||||||
};
|
};
|
||||||
use project::{DiagnosticSummary, Project, ProjectPath};
|
use project::{DiagnosticSummary, Project, ProjectPath};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
@ -342,20 +342,13 @@ impl ProjectDiagnosticsEditor {
|
||||||
is_first_excerpt_for_group = false;
|
is_first_excerpt_for_group = false;
|
||||||
let mut primary =
|
let mut primary =
|
||||||
group.entries[group.primary_ix].diagnostic.clone();
|
group.entries[group.primary_ix].diagnostic.clone();
|
||||||
let anchor = group.entries[group.primary_ix].range.start;
|
|
||||||
let position = anchor.to_point(&snapshot);
|
|
||||||
primary.message =
|
primary.message =
|
||||||
primary.message.split('\n').next().unwrap().to_string();
|
primary.message.split('\n').next().unwrap().to_string();
|
||||||
group_state.block_count += 1;
|
group_state.block_count += 1;
|
||||||
blocks_to_add.push(BlockProperties {
|
blocks_to_add.push(BlockProperties {
|
||||||
position: header_position,
|
position: header_position,
|
||||||
height: 2,
|
height: 2,
|
||||||
render: diagnostic_header_renderer(
|
render: diagnostic_header_renderer(primary),
|
||||||
primary,
|
|
||||||
path.clone(),
|
|
||||||
position,
|
|
||||||
anchor,
|
|
||||||
),
|
|
||||||
disposition: BlockDisposition::Above,
|
disposition: BlockDisposition::Above,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -612,18 +605,10 @@ impl workspace::Item for ProjectDiagnosticsEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diagnostic_header_renderer(
|
fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock {
|
||||||
diagnostic: Diagnostic,
|
|
||||||
path: ProjectPath,
|
|
||||||
position: Point,
|
|
||||||
anchor: Anchor,
|
|
||||||
) -> RenderBlock {
|
|
||||||
enum JumpIcon {}
|
|
||||||
|
|
||||||
let (message, highlights) = highlight_diagnostic_message(&diagnostic.message);
|
let (message, highlights) = highlight_diagnostic_message(&diagnostic.message);
|
||||||
Arc::new(move |cx| {
|
Arc::new(move |cx| {
|
||||||
let settings = cx.global::<Settings>();
|
let settings = cx.global::<Settings>();
|
||||||
let tooltip_style = settings.theme.tooltip.clone();
|
|
||||||
let theme = &settings.theme.editor;
|
let theme = &settings.theme.editor;
|
||||||
let style = theme.diagnostic_header.clone();
|
let style = theme.diagnostic_header.clone();
|
||||||
let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
|
let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
|
||||||
|
@ -664,43 +649,6 @@ fn diagnostic_header_renderer(
|
||||||
.aligned()
|
.aligned()
|
||||||
.boxed()
|
.boxed()
|
||||||
}))
|
}))
|
||||||
.with_child(
|
|
||||||
MouseEventHandler::new::<JumpIcon, _, _>(diagnostic.group_id, cx, |state, _| {
|
|
||||||
let style = style.jump_icon.style_for(state, false);
|
|
||||||
Svg::new("icons/jump.svg")
|
|
||||||
.with_color(style.color)
|
|
||||||
.constrained()
|
|
||||||
.with_width(style.icon_width)
|
|
||||||
.aligned()
|
|
||||||
.contained()
|
|
||||||
.with_style(style.container)
|
|
||||||
.constrained()
|
|
||||||
.with_width(style.button_width)
|
|
||||||
.with_height(style.button_width)
|
|
||||||
.boxed()
|
|
||||||
})
|
|
||||||
.with_cursor_style(CursorStyle::PointingHand)
|
|
||||||
.on_click({
|
|
||||||
let path = path.clone();
|
|
||||||
move |_, _, cx| {
|
|
||||||
cx.dispatch_action(Jump {
|
|
||||||
path: path.clone(),
|
|
||||||
position,
|
|
||||||
anchor,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.with_tooltip(
|
|
||||||
diagnostic.group_id,
|
|
||||||
"Jump to diagnostic".to_string(),
|
|
||||||
Some(Box::new(editor::OpenExcerpts)),
|
|
||||||
tooltip_style,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
.aligned()
|
|
||||||
.flex_float()
|
|
||||||
.boxed(),
|
|
||||||
)
|
|
||||||
.contained()
|
.contained()
|
||||||
.with_style(style.container)
|
.with_style(style.container)
|
||||||
.with_padding_left(x_padding)
|
.with_padding_left(x_padding)
|
||||||
|
|
|
@ -97,6 +97,7 @@ struct Transform {
|
||||||
pub enum TransformBlock {
|
pub enum TransformBlock {
|
||||||
Custom(Arc<Block>),
|
Custom(Arc<Block>),
|
||||||
ExcerptHeader {
|
ExcerptHeader {
|
||||||
|
key: usize,
|
||||||
buffer: BufferSnapshot,
|
buffer: BufferSnapshot,
|
||||||
range: ExcerptRange<text::Anchor>,
|
range: ExcerptRange<text::Anchor>,
|
||||||
height: u8,
|
height: u8,
|
||||||
|
@ -359,6 +360,7 @@ impl BlockMap {
|
||||||
.from_point(Point::new(excerpt_boundary.row, 0), Bias::Left)
|
.from_point(Point::new(excerpt_boundary.row, 0), Bias::Left)
|
||||||
.row(),
|
.row(),
|
||||||
TransformBlock::ExcerptHeader {
|
TransformBlock::ExcerptHeader {
|
||||||
|
key: excerpt_boundary.key,
|
||||||
buffer: excerpt_boundary.buffer,
|
buffer: excerpt_boundary.buffer,
|
||||||
range: excerpt_boundary.range,
|
range: excerpt_boundary.range,
|
||||||
height: if excerpt_boundary.starts_new_buffer {
|
height: if excerpt_boundary.starts_new_buffer {
|
||||||
|
|
|
@ -5849,9 +5849,13 @@ impl Editor {
|
||||||
} else {
|
} else {
|
||||||
buffer.clip_point(position, Bias::Left)
|
buffer.clip_point(position, Bias::Left)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let nav_history = editor.nav_history.take();
|
||||||
editor.change_selections(Some(Autoscroll::Newest), cx, |s| {
|
editor.change_selections(Some(Autoscroll::Newest), cx, |s| {
|
||||||
s.select_ranges([cursor..cursor]);
|
s.select_ranges([cursor..cursor]);
|
||||||
});
|
});
|
||||||
|
editor.nav_history = nav_history;
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
})?;
|
})?;
|
||||||
Some(())
|
Some(())
|
||||||
|
|
|
@ -27,6 +27,7 @@ use gpui::{
|
||||||
};
|
};
|
||||||
use json::json;
|
use json::json;
|
||||||
use language::{Bias, DiagnosticSeverity, Selection};
|
use language::{Bias, DiagnosticSeverity, Selection};
|
||||||
|
use project::ProjectPath;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -795,6 +796,7 @@ impl EditorElement {
|
||||||
return Default::default();
|
return Default::default();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
|
||||||
let scroll_x = snapshot.scroll_position.x();
|
let scroll_x = snapshot.scroll_position.x();
|
||||||
snapshot
|
snapshot
|
||||||
.blocks_in_range(rows.clone())
|
.blocks_in_range(rows.clone())
|
||||||
|
@ -827,10 +829,60 @@ impl EditorElement {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
TransformBlock::ExcerptHeader {
|
TransformBlock::ExcerptHeader {
|
||||||
|
key,
|
||||||
buffer,
|
buffer,
|
||||||
|
range,
|
||||||
starts_new_buffer,
|
starts_new_buffer,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
let jump_icon = project::File::from_dyn(buffer.file()).map(|file| {
|
||||||
|
let jump_position = range
|
||||||
|
.primary
|
||||||
|
.as_ref()
|
||||||
|
.map_or(range.context.start, |primary| primary.start);
|
||||||
|
let jump_action = crate::Jump {
|
||||||
|
path: ProjectPath {
|
||||||
|
worktree_id: file.worktree_id(cx),
|
||||||
|
path: file.path.clone(),
|
||||||
|
},
|
||||||
|
position: language::ToPoint::to_point(&jump_position, buffer),
|
||||||
|
anchor: jump_position,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum JumpIcon {}
|
||||||
|
cx.render(&editor, |_, cx| {
|
||||||
|
MouseEventHandler::new::<JumpIcon, _, _>(*key, cx, |state, _| {
|
||||||
|
let style = style.jump_icon.style_for(state, false);
|
||||||
|
Svg::new("icons/jump.svg")
|
||||||
|
.with_color(style.color)
|
||||||
|
.constrained()
|
||||||
|
.with_width(style.icon_width)
|
||||||
|
.aligned()
|
||||||
|
.contained()
|
||||||
|
.with_style(style.container)
|
||||||
|
.constrained()
|
||||||
|
.with_width(style.button_width)
|
||||||
|
.with_height(style.button_width)
|
||||||
|
.boxed()
|
||||||
|
})
|
||||||
|
.with_cursor_style(CursorStyle::PointingHand)
|
||||||
|
.on_click({
|
||||||
|
move |_, _, cx| cx.dispatch_action(jump_action.clone())
|
||||||
|
})
|
||||||
|
.with_tooltip(
|
||||||
|
*key,
|
||||||
|
"Jump to Buffer".to_string(),
|
||||||
|
Some(Box::new(crate::OpenExcerpts)),
|
||||||
|
tooltip_style.clone(),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.aligned()
|
||||||
|
.flex_float()
|
||||||
|
.boxed()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let padding = gutter_padding + scroll_x * em_width;
|
||||||
if *starts_new_buffer {
|
if *starts_new_buffer {
|
||||||
let style = &self.style.diagnostic_path_header;
|
let style = &self.style.diagnostic_path_header;
|
||||||
let font_size =
|
let font_size =
|
||||||
|
@ -854,6 +906,7 @@ impl EditorElement {
|
||||||
)
|
)
|
||||||
.contained()
|
.contained()
|
||||||
.with_style(style.filename.container)
|
.with_style(style.filename.container)
|
||||||
|
.aligned()
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
.with_children(parent_path.map(|path| {
|
.with_children(parent_path.map(|path| {
|
||||||
|
@ -863,20 +916,25 @@ impl EditorElement {
|
||||||
)
|
)
|
||||||
.contained()
|
.contained()
|
||||||
.with_style(style.path.container)
|
.with_style(style.path.container)
|
||||||
|
.aligned()
|
||||||
.boxed()
|
.boxed()
|
||||||
}))
|
}))
|
||||||
.aligned()
|
.with_children(jump_icon)
|
||||||
.left()
|
|
||||||
.contained()
|
.contained()
|
||||||
.with_style(style.container)
|
.with_style(style.container)
|
||||||
.with_padding_left(gutter_padding + scroll_x * em_width)
|
.with_padding_left(padding)
|
||||||
|
.with_padding_right(padding)
|
||||||
.expanded()
|
.expanded()
|
||||||
.named("path header block")
|
.named("path header block")
|
||||||
} else {
|
} else {
|
||||||
let text_style = self.style.text.clone();
|
let text_style = self.style.text.clone();
|
||||||
Label::new("…".to_string(), text_style)
|
Flex::row()
|
||||||
|
.with_child(Label::new("…".to_string(), text_style).boxed())
|
||||||
|
.with_children(jump_icon)
|
||||||
.contained()
|
.contained()
|
||||||
.with_padding_left(gutter_padding + scroll_x * em_width)
|
.with_padding_left(padding)
|
||||||
|
.with_padding_right(padding)
|
||||||
|
.expanded()
|
||||||
.named("collapsed context")
|
.named("collapsed context")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1980,8 +1980,8 @@ impl BufferSnapshot {
|
||||||
self.selections_update_count
|
self.selections_update_count
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file(&self) -> Option<&Arc<dyn File>> {
|
pub fn file(&self) -> Option<&dyn File> {
|
||||||
self.file.as_ref()
|
self.file.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_update_count(&self) -> usize {
|
pub fn file_update_count(&self) -> usize {
|
||||||
|
|
|
@ -454,6 +454,7 @@ pub struct Editor {
|
||||||
pub code_actions_indicator: Color,
|
pub code_actions_indicator: Color,
|
||||||
pub unnecessary_code_fade: f32,
|
pub unnecessary_code_fade: f32,
|
||||||
pub hover_popover: HoverPopover,
|
pub hover_popover: HoverPopover,
|
||||||
|
pub jump_icon: Interactive<IconButton>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Default)]
|
#[derive(Clone, Deserialize, Default)]
|
||||||
|
@ -473,7 +474,6 @@ pub struct DiagnosticHeader {
|
||||||
pub code: ContainedText,
|
pub code: ContainedText,
|
||||||
pub text_scale_factor: f32,
|
pub text_scale_factor: f32,
|
||||||
pub icon_width_factor: f32,
|
pub icon_width_factor: f32,
|
||||||
pub jump_icon: Interactive<IconButton>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Default)]
|
#[derive(Clone, Deserialize, Default)]
|
||||||
|
|
|
@ -101,14 +101,6 @@ export default function editor(theme: Theme) {
|
||||||
background: backgroundColor(theme, 300),
|
background: backgroundColor(theme, 300),
|
||||||
iconWidthFactor: 1.5,
|
iconWidthFactor: 1.5,
|
||||||
textScaleFactor: 0.857, // NateQ: Will we need dynamic sizing for text? If so let's create tokens for these.
|
textScaleFactor: 0.857, // NateQ: Will we need dynamic sizing for text? If so let's create tokens for these.
|
||||||
jumpIcon: {
|
|
||||||
color: iconColor(theme, "primary"),
|
|
||||||
iconWidth: 10,
|
|
||||||
buttonWidth: 10,
|
|
||||||
hover: {
|
|
||||||
color: iconColor(theme, "active")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
border: border(theme, "secondary", {
|
border: border(theme, "secondary", {
|
||||||
bottom: true,
|
bottom: true,
|
||||||
top: true,
|
top: true,
|
||||||
|
@ -147,6 +139,14 @@ export default function editor(theme: Theme) {
|
||||||
invalidInformationDiagnostic: diagnostic(theme, "muted"),
|
invalidInformationDiagnostic: diagnostic(theme, "muted"),
|
||||||
invalidWarningDiagnostic: diagnostic(theme, "muted"),
|
invalidWarningDiagnostic: diagnostic(theme, "muted"),
|
||||||
hover_popover: hoverPopover(theme),
|
hover_popover: hoverPopover(theme),
|
||||||
|
jumpIcon: {
|
||||||
|
color: iconColor(theme, "primary"),
|
||||||
|
iconWidth: 10,
|
||||||
|
buttonWidth: 10,
|
||||||
|
hover: {
|
||||||
|
color: iconColor(theme, "active")
|
||||||
|
}
|
||||||
|
},
|
||||||
syntax,
|
syntax,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue