Compare commits

..

4 Commits

Author SHA1 Message Date
Julia Ryan
bded0e12f4 wip 2025-07-22 14:08:11 -07:00
Julia Ryan
124b4645c4 switch from action to event 2025-07-18 14:34:31 -07:00
Julia Ryan
b24a30916a wip: start adding action 2025-07-18 14:34:31 -07:00
Julia Ryan
05e0a812c4 Add gutter runnable edit buttons 2025-07-18 14:34:31 -07:00
31 changed files with 269 additions and 775 deletions

1
Cargo.lock generated
View File

@@ -9134,7 +9134,6 @@ dependencies = [
"futures 0.3.31",
"gpui",
"http_client",
"indoc",
"language",
"log",
"lsp",

View File

@@ -176,14 +176,6 @@ impl AgentThreadEntry {
None
}
}
pub fn locations(&self) -> Option<&[acp::ToolCallLocation]> {
if let AgentThreadEntry::ToolCall(ToolCall { locations, .. }) = self {
Some(locations)
} else {
None
}
}
}
#[derive(Debug)]

View File

@@ -925,43 +925,10 @@ impl AcpThreadView {
.size(IconSize::Small)
.color(Color::Muted),
)
.child(if tool_call.locations.len() == 1 {
let name = tool_call.locations[0]
.path
.file_name()
.unwrap_or_default()
.display()
.to_string();
h_flex()
.id(("open-tool-call-location", entry_ix))
.child(name)
.w_full()
.max_w_full()
.pr_1()
.gap_0p5()
.cursor_pointer()
.rounded_sm()
.opacity(0.8)
.hover(|label| {
label.opacity(1.).bg(cx
.theme()
.colors()
.element_hover
.opacity(0.5))
})
.tooltip(Tooltip::text("Jump to File"))
.on_click(cx.listener(move |this, _, window, cx| {
this.open_tool_call_location(entry_ix, 0, window, cx);
}))
.into_any_element()
} else {
self.render_markdown(
tool_call.label.clone(),
default_markdown_style(needs_confirmation, window, cx),
)
.into_any()
}),
.child(self.render_markdown(
tool_call.label.clone(),
default_markdown_style(needs_confirmation, window, cx),
)),
)
.child(
h_flex()
@@ -1021,19 +988,15 @@ impl AcpThreadView {
cx: &Context<Self>,
) -> AnyElement {
match content {
ToolCallContent::Markdown { markdown } => {
div()
.p_2()
.child(self.render_markdown(
markdown.clone(),
default_markdown_style(false, window, cx),
))
.into_any_element()
}
ToolCallContent::Markdown { markdown } => self
.render_markdown(markdown.clone(), default_markdown_style(false, window, cx))
.into_any_element(),
ToolCallContent::Diff {
diff: Diff { multibuffer, .. },
diff: Diff {
path, multibuffer, ..
},
..
} => self.render_diff_editor(multibuffer),
} => self.render_diff_editor(multibuffer, path),
}
}
@@ -1453,9 +1416,10 @@ impl AcpThreadView {
}
}
fn render_diff_editor(&self, multibuffer: &Entity<MultiBuffer>) -> AnyElement {
fn render_diff_editor(&self, multibuffer: &Entity<MultiBuffer>, path: &Path) -> AnyElement {
v_flex()
.h_full()
.child(path.to_string_lossy().to_string())
.child(
if let Some(editor) = self.diff_editors.get(&multibuffer.entity_id()) {
editor.clone().into_any_element()
@@ -2112,64 +2076,6 @@ impl AcpThreadView {
}
}
fn open_tool_call_location(
&self,
entry_ix: usize,
location_ix: usize,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<()> {
let location = self
.thread()?
.read(cx)
.entries()
.get(entry_ix)?
.locations()?
.get(location_ix)?;
let project_path = self
.project
.read(cx)
.find_project_path(&location.path, cx)?;
let open_task = self
.workspace
.update(cx, |worskpace, cx| {
worskpace.open_path(project_path, None, true, window, cx)
})
.log_err()?;
window
.spawn(cx, async move |cx| {
let item = open_task.await?;
let Some(active_editor) = item.downcast::<Editor>() else {
return anyhow::Ok(());
};
active_editor.update_in(cx, |editor, window, cx| {
let snapshot = editor.buffer().read(cx).snapshot(cx);
let first_hunk = editor
.diff_hunks_in_ranges(
&[editor::Anchor::min()..editor::Anchor::max()],
&snapshot,
)
.next();
if let Some(first_hunk) = first_hunk {
let first_hunk_start = first_hunk.multi_buffer_range().start;
editor.change_selections(Default::default(), window, cx, |selections| {
selections.select_anchor_ranges([first_hunk_start..first_hunk_start]);
})
}
})?;
anyhow::Ok(())
})
.detach_and_log_err(cx);
None
}
pub fn open_thread_as_markdown(
&self,
workspace: Entity<Workspace>,

View File

@@ -547,7 +547,6 @@ async fn handle_envs(
}
};
let mut env_vars = HashMap::default();
for path in env_files {
let Some(path) = path
.and_then(|s| PathBuf::from_str(s).ok())
@@ -557,33 +556,13 @@ async fn handle_envs(
};
if let Ok(file) = fs.open_sync(&path).await {
let file_envs: HashMap<String, String> = dotenvy::from_read_iter(file)
.filter_map(Result::ok)
.collect();
envs.extend(file_envs.iter().map(|(k, v)| (k.clone(), v.clone())));
env_vars.extend(file_envs);
envs.extend(dotenvy::from_read_iter(file).filter_map(Result::ok))
} else {
warn!("While starting Go debug session: failed to read env file {path:?}");
};
}
let mut env_obj: serde_json::Map<String, Value> = serde_json::Map::new();
for (k, v) in env_vars {
env_obj.insert(k, Value::String(v));
}
if let Some(existing_env) = config.get("env").and_then(|v| v.as_object()) {
for (k, v) in existing_env {
env_obj.insert(k.clone(), v.clone());
}
}
if !env_obj.is_empty() {
config.insert("env".to_string(), Value::Object(env_obj));
}
// remove envFile now that it's been handled
config.remove("envFile");
config.remove("entry");
Some(())
}

View File

@@ -32,19 +32,12 @@ use workspace::{
ui::{Button, Clickable, ContextMenu, Label, LabelCommon, PopoverMenu, h_flex},
};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum View {
AdapterLogs,
RpcMessages,
InitializationSequence,
}
struct DapLogView {
editor: Entity<Editor>,
focus_handle: FocusHandle,
log_store: Entity<LogStore>,
editor_subscriptions: Vec<Subscription>,
current_view: Option<(SessionId, View)>,
current_view: Option<(SessionId, LogKind)>,
project: Entity<Project>,
_subscriptions: Vec<Subscription>,
}
@@ -84,7 +77,6 @@ struct DebugAdapterState {
id: SessionId,
log_messages: VecDeque<SharedString>,
rpc_messages: RpcMessages,
session_label: SharedString,
adapter_name: DebugAdapterName,
has_adapter_logs: bool,
is_terminated: bool,
@@ -129,18 +121,12 @@ impl MessageKind {
}
impl DebugAdapterState {
fn new(
id: SessionId,
adapter_name: DebugAdapterName,
session_label: SharedString,
has_adapter_logs: bool,
) -> Self {
fn new(id: SessionId, adapter_name: DebugAdapterName, has_adapter_logs: bool) -> Self {
Self {
id,
log_messages: VecDeque::new(),
rpc_messages: RpcMessages::new(),
adapter_name,
session_label,
has_adapter_logs,
is_terminated: false,
}
@@ -385,21 +371,18 @@ impl LogStore {
return None;
};
let (adapter_name, session_label, has_adapter_logs) =
session.read_with(cx, |session, _| {
(
session.adapter(),
session.label(),
session
.adapter_client()
.map_or(false, |client| client.has_adapter_logs()),
)
});
let (adapter_name, has_adapter_logs) = session.read_with(cx, |session, _| {
(
session.adapter(),
session
.adapter_client()
.map_or(false, |client| client.has_adapter_logs()),
)
});
state.insert(DebugAdapterState::new(
id.session_id,
adapter_name,
session_label,
has_adapter_logs,
));
@@ -523,13 +506,12 @@ impl Render for DapLogToolbarItemView {
current_client
.map(|sub_item| {
Cow::Owned(format!(
"{} - {} - {}",
"{} ({}) - {}",
sub_item.adapter_name,
sub_item.session_label,
sub_item.session_id.0,
match sub_item.selected_entry {
View::AdapterLogs => ADAPTER_LOGS,
View::RpcMessages => RPC_MESSAGES,
View::InitializationSequence => INITIALIZATION_SEQUENCE,
LogKind::Adapter => ADAPTER_LOGS,
LogKind::Rpc => RPC_MESSAGES,
}
))
})
@@ -547,8 +529,8 @@ impl Render for DapLogToolbarItemView {
.pl_2()
.child(
Label::new(format!(
"{} - {}",
row.adapter_name, row.session_label
"{}. {}",
row.session_id.0, row.adapter_name,
))
.color(workspace::ui::Color::Muted),
)
@@ -687,16 +669,9 @@ impl DapLogView {
let events_subscriptions = cx.subscribe(&log_store, |log_view, _, event, cx| match event {
Event::NewLogEntry { id, entry, kind } => {
let is_current_view = match (log_view.current_view, *kind) {
(Some((i, View::AdapterLogs)), LogKind::Adapter)
| (Some((i, View::RpcMessages)), LogKind::Rpc)
if i == id.session_id =>
{
log_view.project == *id.project
}
_ => false,
};
if is_current_view {
if log_view.current_view == Some((id.session_id, *kind))
&& log_view.project == *id.project
{
log_view.editor.update(cx, |editor, cx| {
editor.set_read_only(false);
let last_point = editor.buffer().read(cx).len(cx);
@@ -793,11 +768,10 @@ impl DapLogView {
.map(|state| DapMenuItem {
session_id: state.id,
adapter_name: state.adapter_name.clone(),
session_label: state.session_label.clone(),
has_adapter_logs: state.has_adapter_logs,
selected_entry: self
.current_view
.map_or(View::AdapterLogs, |(_, kind)| kind),
.map_or(LogKind::Adapter, |(_, kind)| kind),
})
.collect::<Vec<_>>()
})
@@ -815,7 +789,7 @@ impl DapLogView {
.map(|state| log_contents(state.iter().cloned()))
});
if let Some(rpc_log) = rpc_log {
self.current_view = Some((id.session_id, View::RpcMessages));
self.current_view = Some((id.session_id, LogKind::Rpc));
let (editor, editor_subscriptions) = Self::editor_for_logs(rpc_log, window, cx);
let language = self.project.read(cx).languages().language_for_name("JSON");
editor
@@ -856,7 +830,7 @@ impl DapLogView {
.map(|state| log_contents(state.iter().cloned()))
});
if let Some(message_log) = message_log {
self.current_view = Some((id.session_id, View::AdapterLogs));
self.current_view = Some((id.session_id, LogKind::Adapter));
let (editor, editor_subscriptions) = Self::editor_for_logs(message_log, window, cx);
editor
.read(cx)
@@ -885,7 +859,7 @@ impl DapLogView {
.map(|state| log_contents(state.iter().cloned()))
});
if let Some(rpc_log) = rpc_log {
self.current_view = Some((id.session_id, View::InitializationSequence));
self.current_view = Some((id.session_id, LogKind::Rpc));
let (editor, editor_subscriptions) = Self::editor_for_logs(rpc_log, window, cx);
let language = self.project.read(cx).languages().language_for_name("JSON");
editor
@@ -925,12 +899,11 @@ fn log_contents(lines: impl Iterator<Item = SharedString>) -> String {
}
#[derive(Clone, PartialEq)]
struct DapMenuItem {
session_id: SessionId,
session_label: SharedString,
adapter_name: DebugAdapterName,
has_adapter_logs: bool,
selected_entry: View,
pub(crate) struct DapMenuItem {
pub session_id: SessionId,
pub adapter_name: DebugAdapterName,
pub has_adapter_logs: bool,
pub selected_entry: LogKind,
}
const ADAPTER_LOGS: &str = "Adapter Logs";

View File

@@ -36,12 +36,12 @@ use task::{DebugScenario, TaskContext};
use tree_sitter::{Query, StreamingIterator as _};
use ui::{ContextMenu, Divider, PopoverMenuHandle, Tooltip, prelude::*};
use util::{ResultExt, maybe};
use workspace::SplitDirection;
use workspace::item::SaveOptions;
use workspace::{
Item, Pane, Workspace,
dock::{DockPosition, Panel, PanelEvent},
};
use workspace::{OpenInDebugJson, SplitDirection};
use zed_actions::ToggleFocus;
pub enum DebugPanelEvent {
@@ -98,6 +98,25 @@ impl DebugPanel {
},
);
if let Some(entity) = workspace.weak_handle().upgrade() {
let edit_scenario_subscription = cx.subscribe_in(
&entity,
window,
move |this, workspace, OpenInDebugJson { scenario, id }, window, cx| {
let task = this.go_to_scenario_definition(
TaskSourceKind::UserInput,
scenario.clone(),
todo!(),
// *id,
window,
cx,
);
cx.spawn(async move |_, cx| task.await)
.detach_and_log_err(cx);
},
);
}
Self {
size: px(300.),
sessions: vec![],

View File

@@ -343,12 +343,6 @@ impl NewProcessModal {
return;
}
if let NewProcessMode::Launch = &self.mode {
if self.configure_mode.read(cx).save_to_debug_json.selected() {
self.save_debug_scenario(window, cx);
}
}
let Some(debugger) = self.debugger.clone() else {
return;
};
@@ -806,7 +800,6 @@ pub(super) struct ConfigureMode {
program: Entity<Editor>,
cwd: Entity<Editor>,
stop_on_entry: ToggleState,
save_to_debug_json: ToggleState,
}
impl ConfigureMode {
@@ -825,7 +818,6 @@ impl ConfigureMode {
program,
cwd,
stop_on_entry: ToggleState::Unselected,
save_to_debug_json: ToggleState::Unselected,
})
}

View File

@@ -11,7 +11,7 @@ use project::worktree_store::WorktreeStore;
use rpc::proto;
use running::RunningState;
use std::{cell::OnceCell, sync::OnceLock};
use ui::{Indicator, prelude::*};
use ui::{Indicator, Tooltip, prelude::*};
use util::truncate_and_trailoff;
use workspace::{
CollaboratorId, FollowableItem, ViewId, Workspace,
@@ -158,6 +158,7 @@ impl DebugSession {
h_flex()
.id("session-label")
.tooltip(Tooltip::text(format!("Session {}", self.session_id(cx).0,)))
.ml(depth * px(16.0))
.gap_2()
.when_some(icon, |this, indicator| this.child(indicator))

View File

@@ -2241,34 +2241,3 @@ func main() {
)
.await;
}
#[gpui::test]
async fn test_trim_multi_line_inline_value(executor: BackgroundExecutor, cx: &mut TestAppContext) {
let variables = [("y", "hello\n world")];
let before = r#"
fn main() {
let y = "hello\n world";
}
"#
.unindent();
let after = r#"
fn main() {
let y: hello… = "hello\n world";
}
"#
.unindent();
test_inline_values_util(
&variables,
&[],
&before,
&after,
None,
rust_lang(),
executor,
cx,
)
.await;
}

View File

@@ -6,7 +6,7 @@ use editor::{
hover_popover::diagnostics_markdown_style,
};
use gpui::{AppContext, Entity, Focusable, WeakEntity};
use language::{BufferId, Diagnostic, DiagnosticEntry, LanguageRegistry};
use language::{BufferId, Diagnostic, DiagnosticEntry};
use lsp::DiagnosticSeverity;
use markdown::{Markdown, MarkdownElement};
use settings::Settings;
@@ -27,7 +27,6 @@ impl DiagnosticRenderer {
diagnostic_group: Vec<DiagnosticEntry<Point>>,
buffer_id: BufferId,
diagnostics_editor: Option<WeakEntity<ProjectDiagnosticsEditor>>,
languages: Arc<LanguageRegistry>,
cx: &mut App,
) -> Vec<DiagnosticBlock> {
let Some(primary_ix) = diagnostic_group
@@ -80,9 +79,7 @@ impl DiagnosticRenderer {
initial_range: primary.range.clone(),
severity: primary.diagnostic.severity,
diagnostics_editor: diagnostics_editor.clone(),
markdown: cx.new(|cx| {
Markdown::new(markdown.into(), Some(languages.clone()), None, cx)
}),
markdown: cx.new(|cx| Markdown::new(markdown.into(), None, None, cx)),
});
} else if entry.range.start.row.abs_diff(primary.range.start.row) < 5 {
let markdown = Self::markdown(&entry.diagnostic);
@@ -91,9 +88,7 @@ impl DiagnosticRenderer {
initial_range: entry.range.clone(),
severity: entry.diagnostic.severity,
diagnostics_editor: diagnostics_editor.clone(),
markdown: cx.new(|cx| {
Markdown::new(markdown.into(), Some(languages.clone()), None, cx)
}),
markdown: cx.new(|cx| Markdown::new(markdown.into(), None, None, cx)),
});
} else {
let mut markdown = Self::markdown(&entry.diagnostic);
@@ -105,9 +100,7 @@ impl DiagnosticRenderer {
initial_range: entry.range.clone(),
severity: entry.diagnostic.severity,
diagnostics_editor: diagnostics_editor.clone(),
markdown: cx.new(|cx| {
Markdown::new(markdown.into(), Some(languages.clone()), None, cx)
}),
markdown: cx.new(|cx| Markdown::new(markdown.into(), None, None, cx)),
});
}
}
@@ -134,11 +127,9 @@ impl editor::DiagnosticRenderer for DiagnosticRenderer {
buffer_id: BufferId,
snapshot: EditorSnapshot,
editor: WeakEntity<Editor>,
languages: Arc<LanguageRegistry>,
cx: &mut App,
) -> Vec<BlockProperties<Anchor>> {
let blocks =
Self::diagnostic_blocks_for_group(diagnostic_group, buffer_id, None, languages, cx);
let blocks = Self::diagnostic_blocks_for_group(diagnostic_group, buffer_id, None, cx);
blocks
.into_iter()
.map(|block| {
@@ -164,11 +155,9 @@ impl editor::DiagnosticRenderer for DiagnosticRenderer {
diagnostic_group: Vec<DiagnosticEntry<Point>>,
range: Range<Point>,
buffer_id: BufferId,
languages: Arc<LanguageRegistry>,
cx: &mut App,
) -> Option<Entity<Markdown>> {
let blocks =
Self::diagnostic_blocks_for_group(diagnostic_group, buffer_id, None, languages, cx);
let blocks = Self::diagnostic_blocks_for_group(diagnostic_group, buffer_id, None, cx);
blocks.into_iter().find_map(|block| {
if block.initial_range == range {
Some(block.markdown)

View File

@@ -508,15 +508,6 @@ impl ProjectDiagnosticsEditor {
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Result<()>> {
let languages = self
.editor
.read(cx)
.project
.as_ref()
.unwrap()
.read(cx)
.languages()
.clone();
let was_empty = self.multibuffer.read(cx).is_empty();
let buffer_snapshot = buffer.read(cx).snapshot();
let buffer_id = buffer_snapshot.remote_id();
@@ -568,7 +559,6 @@ impl ProjectDiagnosticsEditor {
group,
buffer_snapshot.remote_id(),
Some(this.clone()),
languages.clone(),
cx,
)
})?;

View File

@@ -1392,6 +1392,7 @@ impl CodeActionsMenu {
) -> AnyElement {
let actions = self.actions.clone();
let selected_item = self.selected_item;
let list = uniform_list(
"code_actions_menu",
self.actions.len(),
@@ -1438,6 +1439,30 @@ impl CodeActionsMenu {
.overflow_hidden()
.child("debug: ")
.child(scenario.label.clone())
.child(
IconButton::new(
SharedString::new(format!("edit-{ix}")),
IconName::Pencil,
)
.on_click(cx.listener({
let scenario = scenario.clone();
move |editor, _, _window, cx| {
if let Some((workspace, Some(id))) =
editor.workspace.as_ref()
{
workspace
.update(cx, |_, cx| {
cx.emit(workspace::OpenInDebugJson {
scenario: scenario.clone(),
id: *id,
});
})
.ok();
}
cx.stop_propagation();
}
})),
)
.when(selected, |this| {
this.text_color(colors.text_accent)
}),

View File

@@ -111,9 +111,8 @@ use itertools::Itertools;
use language::{
AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
EditPreview, HighlightedText, IndentKind, IndentSize, Language, LanguageRegistry,
OffsetRangeExt, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
WordsQuery,
EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
language_settings::{
self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
all_language_settings, language_settings,
@@ -403,7 +402,6 @@ pub trait DiagnosticRenderer {
buffer_id: BufferId,
snapshot: EditorSnapshot,
editor: WeakEntity<Editor>,
languages: Arc<LanguageRegistry>,
cx: &mut App,
) -> Vec<BlockProperties<Anchor>>;
@@ -412,7 +410,6 @@ pub trait DiagnosticRenderer {
diagnostic_group: Vec<DiagnosticEntry<Point>>,
range: Range<Point>,
buffer_id: BufferId,
languages: Arc<LanguageRegistry>,
cx: &mut App,
) -> Option<Entity<markdown::Markdown>>;
@@ -2325,10 +2322,7 @@ impl Editor {
editor.update_lsp_data(false, None, window, cx);
}
if editor.mode.is_full() {
editor.report_editor_event("Editor Opened", None, cx);
}
editor.report_editor_event("Editor Opened", None, cx);
editor
}
@@ -16577,20 +16571,13 @@ impl Editor {
let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
return;
};
let languages = self.project.as_ref().unwrap().read(cx).languages().clone();
let diagnostic_group = buffer
.diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
.collect::<Vec<_>>();
let blocks = renderer.render_group(
diagnostic_group,
buffer_id,
snapshot,
cx.weak_entity(),
languages,
cx,
);
let blocks =
renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
let blocks = self.display_map.update(cx, |display_map, cx| {
display_map.insert_blocks(blocks, cx).into_iter().collect()
@@ -19668,9 +19655,8 @@ impl Editor {
Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
hint.text(),
);
if !inlay.text.chars().contains(&'\n') {
new_inlays.push(inlay);
}
new_inlays.push(inlay);
});
}

View File

@@ -2836,7 +2836,6 @@ impl EditorElement {
) -> Vec<AnyElement> {
self.editor.update(cx, |editor, cx| {
let active_task_indicator_row =
// TODO: add edit button on the right side of each row in the context menu
if let Some(crate::CodeContextMenu::CodeActions(CodeActionsMenu {
deployed_from,
actions,
@@ -8035,25 +8034,23 @@ impl Element for EditorElement {
}
};
let (
autoscroll_request,
autoscroll_containing_element,
needs_horizontal_autoscroll,
) = self.editor.update(cx, |editor, cx| {
let autoscroll_request = editor.autoscroll_request();
let autoscroll_containing_element =
// TODO: Autoscrolling for both axes
let mut autoscroll_request = None;
let mut autoscroll_containing_element = false;
let mut autoscroll_horizontally = false;
self.editor.update(cx, |editor, cx| {
autoscroll_request = editor.autoscroll_request();
autoscroll_containing_element =
autoscroll_request.is_some() || editor.has_pending_selection();
let (needs_horizontal_autoscroll, was_scrolled) = editor
.autoscroll_vertically(bounds, line_height, max_scroll_top, window, cx);
if was_scrolled.0 {
snapshot = editor.snapshot(window, cx);
}
(
autoscroll_request,
autoscroll_containing_element,
needs_horizontal_autoscroll,
)
// TODO: Is this horizontal or vertical?!
autoscroll_horizontally = editor.autoscroll_vertically(
bounds,
line_height,
max_scroll_top,
window,
cx,
);
snapshot = editor.snapshot(window, cx);
});
let mut scroll_position = snapshot.scroll_position();
@@ -8462,12 +8459,10 @@ impl Element for EditorElement {
);
self.editor.update(cx, |editor, cx| {
if editor.scroll_manager.clamp_scroll_left(scroll_max.x) {
scroll_position.x = scroll_position.x.min(scroll_max.x);
}
let clamped = editor.scroll_manager.clamp_scroll_left(scroll_max.x);
if needs_horizontal_autoscroll.0
&& let Some(new_scroll_position) = editor.autoscroll_horizontally(
let autoscrolled = if autoscroll_horizontally {
editor.autoscroll_horizontally(
start_row,
editor_content_width,
scroll_width,
@@ -8476,8 +8471,13 @@ impl Element for EditorElement {
window,
cx,
)
{
scroll_position = new_scroll_position;
} else {
false
};
if clamped || autoscrolled {
snapshot = editor.snapshot(window, cx);
scroll_position = snapshot.scroll_position();
}
});
@@ -8592,9 +8592,7 @@ impl Element for EditorElement {
}
} else {
log::error!(
"bug: line_ix {} is out of bounds - row_infos.len(): {}, \
line_layouts.len(): {}, \
crease_trailers.len(): {}",
"bug: line_ix {} is out of bounds - row_infos.len(): {}, line_layouts.len(): {}, crease_trailers.len(): {}",
line_ix,
row_infos.len(),
line_layouts.len(),
@@ -8840,7 +8838,7 @@ impl Element for EditorElement {
underline: None,
strikethrough: None,
}],
None,
None
);
let space_invisible = window.text_system().shape_line(
"".into(),
@@ -8853,7 +8851,7 @@ impl Element for EditorElement {
underline: None,
strikethrough: None,
}],
None,
None
);
let mode = snapshot.mode.clone();

View File

@@ -275,13 +275,6 @@ fn show_hover(
return None;
}
}
let languages = editor
.project
.as_ref()
.unwrap()
.read(cx)
.languages()
.clone();
let hover_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
let all_diagnostics_active = editor.active_diagnostics == ActiveDiagnostic::All;
@@ -347,7 +340,7 @@ fn show_hover(
renderer
.as_ref()
.and_then(|renderer| {
renderer.render_hover(group, point_range, buffer_id, languages, cx)
renderer.render_hover(group, point_range, buffer_id, cx)
})
.context("no rendered diagnostic")
})??;

View File

@@ -813,13 +813,7 @@ impl Item for Editor {
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Result<()>> {
// Add meta data tracking # of auto saves
if options.autosave {
self.report_editor_event("Editor Autosaved", None, cx);
} else {
self.report_editor_event("Editor Saved", None, cx);
}
self.report_editor_event("Editor Saved", None, cx);
let buffers = self.buffer().clone().read(cx).all_buffers();
let buffers = buffers
.into_iter()

View File

@@ -27,8 +27,6 @@ use workspace::{ItemId, WorkspaceId};
pub const SCROLL_EVENT_SEPARATION: Duration = Duration::from_millis(28);
const SCROLLBAR_SHOW_INTERVAL: Duration = Duration::from_secs(1);
pub struct WasScrolled(pub(crate) bool);
#[derive(Default)]
pub struct ScrollbarAutoHide(pub bool);
@@ -217,56 +215,87 @@ impl ScrollManager {
workspace_id: Option<WorkspaceId>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> WasScrolled {
let scroll_top = scroll_position.y.max(0.);
let scroll_top = match EditorSettings::get_global(cx).scroll_beyond_last_line {
ScrollBeyondLastLine::OnePage => scroll_top,
ScrollBeyondLastLine::Off => {
if let Some(height_in_lines) = self.visible_line_count {
let max_row = map.max_point().row().0 as f32;
scroll_top.min(max_row - height_in_lines + 1.).max(0.)
} else {
scroll_top
) {
let (new_anchor, top_row) = if scroll_position.y <= 0. && scroll_position.x <= 0. {
(
ScrollAnchor {
anchor: Anchor::min(),
offset: scroll_position.max(&gpui::Point::default()),
},
0,
)
} else if scroll_position.y <= 0. {
let buffer_point = map
.clip_point(
DisplayPoint::new(DisplayRow(0), scroll_position.x as u32),
Bias::Left,
)
.to_point(map);
let anchor = map.buffer_snapshot.anchor_at(buffer_point, Bias::Right);
(
ScrollAnchor {
anchor: anchor,
offset: scroll_position.max(&gpui::Point::default()),
},
0,
)
} else {
let scroll_top = scroll_position.y;
let scroll_top = match EditorSettings::get_global(cx).scroll_beyond_last_line {
ScrollBeyondLastLine::OnePage => scroll_top,
ScrollBeyondLastLine::Off => {
if let Some(height_in_lines) = self.visible_line_count {
let max_row = map.max_point().row().0 as f32;
scroll_top.min(max_row - height_in_lines + 1.).max(0.)
} else {
scroll_top
}
}
}
ScrollBeyondLastLine::VerticalScrollMargin => {
if let Some(height_in_lines) = self.visible_line_count {
let max_row = map.max_point().row().0 as f32;
scroll_top
.min(max_row - height_in_lines + 1. + self.vertical_scroll_margin)
.max(0.)
} else {
scroll_top
ScrollBeyondLastLine::VerticalScrollMargin => {
if let Some(height_in_lines) = self.visible_line_count {
let max_row = map.max_point().row().0 as f32;
scroll_top
.min(max_row - height_in_lines + 1. + self.vertical_scroll_margin)
.max(0.)
} else {
scroll_top
}
}
}
};
let scroll_top_row = DisplayRow(scroll_top as u32);
let scroll_top_buffer_point = map
.clip_point(
DisplayPoint::new(scroll_top_row, scroll_position.x as u32),
Bias::Left,
)
.to_point(map);
let top_anchor = map
.buffer_snapshot
.anchor_at(scroll_top_buffer_point, Bias::Right);
(
ScrollAnchor {
anchor: top_anchor,
offset: point(
scroll_position.x.max(0.),
scroll_top - top_anchor.to_display_point(map).row().as_f32(),
),
},
scroll_top_buffer_point.row,
)
};
let scroll_top_row = DisplayRow(scroll_top as u32);
let scroll_top_buffer_point = map
.clip_point(
DisplayPoint::new(scroll_top_row, scroll_position.x as u32),
Bias::Left,
)
.to_point(map);
let top_anchor = map
.buffer_snapshot
.anchor_at(scroll_top_buffer_point, Bias::Right);
self.set_anchor(
ScrollAnchor {
anchor: top_anchor,
offset: point(
scroll_position.x.max(0.),
scroll_top - top_anchor.to_display_point(map).row().as_f32(),
),
},
scroll_top_buffer_point.row,
new_anchor,
top_row,
local,
autoscroll,
workspace_id,
window,
cx,
)
);
}
fn set_anchor(
@@ -278,7 +307,7 @@ impl ScrollManager {
workspace_id: Option<WorkspaceId>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> WasScrolled {
) {
let adjusted_anchor = if self.forbid_vertical_scroll {
ScrollAnchor {
offset: gpui::Point::new(anchor.offset.x, self.anchor.offset.y),
@@ -288,14 +317,10 @@ impl ScrollManager {
anchor
};
self.autoscroll_request.take();
if self.anchor == adjusted_anchor {
return WasScrolled(false);
}
self.anchor = adjusted_anchor;
cx.emit(EditorEvent::ScrollPositionChanged { local, autoscroll });
self.show_scrollbars(window, cx);
self.autoscroll_request.take();
if let Some(workspace_id) = workspace_id {
let item_id = cx.entity().entity_id().as_u64() as ItemId;
@@ -317,8 +342,6 @@ impl ScrollManager {
.detach()
}
cx.notify();
WasScrolled(true)
}
pub fn show_scrollbars(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
@@ -529,13 +552,13 @@ impl Editor {
scroll_position: gpui::Point<f32>,
window: &mut Window,
cx: &mut Context<Self>,
) -> WasScrolled {
) {
let mut position = scroll_position;
if self.scroll_manager.forbid_vertical_scroll {
let current_position = self.scroll_position(cx);
position.y = current_position.y;
}
self.set_scroll_position_internal(position, true, false, window, cx)
self.set_scroll_position_internal(position, true, false, window, cx);
}
/// Scrolls so that `row` is at the top of the editor view.
@@ -567,7 +590,7 @@ impl Editor {
autoscroll: bool,
window: &mut Window,
cx: &mut Context<Self>,
) -> WasScrolled {
) {
let map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
self.set_scroll_position_taking_display_map(
scroll_position,
@@ -576,7 +599,7 @@ impl Editor {
map,
window,
cx,
)
);
}
fn set_scroll_position_taking_display_map(
@@ -587,7 +610,7 @@ impl Editor {
display_map: DisplaySnapshot,
window: &mut Window,
cx: &mut Context<Self>,
) -> WasScrolled {
) {
hide_hover(self, cx);
let workspace_id = self.workspace.as_ref().and_then(|workspace| workspace.1);
@@ -601,7 +624,7 @@ impl Editor {
scroll_position
};
let editor_was_scrolled = self.scroll_manager.set_scroll_position(
self.scroll_manager.set_scroll_position(
adjusted_position,
&display_map,
local,
@@ -613,7 +636,6 @@ impl Editor {
self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
self.refresh_colors(false, None, window, cx);
editor_was_scrolled
}
pub fn scroll_position(&self, cx: &mut Context<Self>) -> gpui::Point<f32> {

View File

@@ -1,6 +1,6 @@
use crate::{
DisplayRow, Editor, EditorMode, LineWithInvisibles, RowExt, SelectionEffects,
display_map::ToDisplayPoint, scroll::WasScrolled,
display_map::ToDisplayPoint,
};
use gpui::{Bounds, Context, Pixels, Window, px};
use language::Point;
@@ -99,21 +99,19 @@ impl AutoscrollStrategy {
}
}
pub(crate) struct NeedsHorizontalAutoscroll(pub(crate) bool);
impl Editor {
pub fn autoscroll_request(&self) -> Option<Autoscroll> {
self.scroll_manager.autoscroll_request()
}
pub(crate) fn autoscroll_vertically(
pub fn autoscroll_vertically(
&mut self,
bounds: Bounds<Pixels>,
line_height: Pixels,
max_scroll_top: f32,
window: &mut Window,
cx: &mut Context<Editor>,
) -> (NeedsHorizontalAutoscroll, WasScrolled) {
) -> bool {
let viewport_height = bounds.size.height;
let visible_lines = viewport_height / line_height;
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
@@ -131,14 +129,12 @@ impl Editor {
scroll_position.y = max_scroll_top;
}
let editor_was_scrolled = if original_y != scroll_position.y {
self.set_scroll_position(scroll_position, window, cx)
} else {
WasScrolled(false)
};
if original_y != scroll_position.y {
self.set_scroll_position(scroll_position, window, cx);
}
let Some((autoscroll, local)) = self.scroll_manager.autoscroll_request.take() else {
return (NeedsHorizontalAutoscroll(false), editor_was_scrolled);
return false;
};
let mut target_top;
@@ -216,7 +212,7 @@ impl Editor {
target_bottom = target_top + 1.;
}
let was_autoscrolled = match strategy {
match strategy {
AutoscrollStrategy::Fit | AutoscrollStrategy::Newest => {
let margin = margin.min(self.scroll_manager.vertical_scroll_margin);
let target_top = (target_top - margin).max(0.0);
@@ -229,42 +225,39 @@ impl Editor {
if needs_scroll_up && !needs_scroll_down {
scroll_position.y = target_top;
} else if !needs_scroll_up && needs_scroll_down {
scroll_position.y = target_bottom - visible_lines;
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
if needs_scroll_up ^ needs_scroll_down {
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
} else {
WasScrolled(false)
if !needs_scroll_up && needs_scroll_down {
scroll_position.y = target_bottom - visible_lines;
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
}
AutoscrollStrategy::Center => {
scroll_position.y = (target_top - margin).max(0.0);
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
AutoscrollStrategy::Focused => {
let margin = margin.min(self.scroll_manager.vertical_scroll_margin);
scroll_position.y = (target_top - margin).max(0.0);
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
AutoscrollStrategy::Top => {
scroll_position.y = (target_top).max(0.0);
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
AutoscrollStrategy::Bottom => {
scroll_position.y = (target_bottom - visible_lines).max(0.0);
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
AutoscrollStrategy::TopRelative(lines) => {
scroll_position.y = target_top - lines as f32;
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
AutoscrollStrategy::BottomRelative(lines) => {
scroll_position.y = target_bottom + lines as f32;
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
self.set_scroll_position_internal(scroll_position, local, true, window, cx);
}
};
}
self.scroll_manager.last_autoscroll = Some((
self.scroll_manager.anchor.offset,
@@ -273,8 +266,7 @@ impl Editor {
strategy,
));
let was_scrolled = WasScrolled(editor_was_scrolled.0 || was_autoscrolled.0);
(NeedsHorizontalAutoscroll(true), was_scrolled)
true
}
pub(crate) fn autoscroll_horizontally(
@@ -286,7 +278,7 @@ impl Editor {
layouts: &[LineWithInvisibles],
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<gpui::Point<f32>> {
) -> bool {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let selections = self.selections.all::<Point>(cx);
let mut scroll_position = self.scroll_manager.scroll_position(&display_map);
@@ -327,26 +319,22 @@ impl Editor {
target_right = target_right.min(scroll_width);
if target_right - target_left > viewport_width {
return None;
return false;
}
let scroll_left = self.scroll_manager.anchor.offset.x * em_advance;
let scroll_right = scroll_left + viewport_width;
let was_scrolled = if target_left < scroll_left {
if target_left < scroll_left {
scroll_position.x = target_left / em_advance;
self.set_scroll_position_internal(scroll_position, true, true, window, cx)
self.set_scroll_position_internal(scroll_position, true, true, window, cx);
true
} else if target_right > scroll_right {
scroll_position.x = (target_right - viewport_width) / em_advance;
self.set_scroll_position_internal(scroll_position, true, true, window, cx)
self.set_scroll_position_internal(scroll_position, true, true, window, cx);
true
} else {
WasScrolled(false)
};
if was_scrolled.0 {
Some(scroll_position)
} else {
None
false
}
}

View File

@@ -44,7 +44,6 @@ dap.workspace = true
futures.workspace = true
gpui.workspace = true
http_client.workspace = true
indoc.workspace = true
language.workspace = true
log.workspace = true
lsp.workspace = true

View File

@@ -262,7 +262,6 @@ impl LspAdapter for RustLspAdapter {
_: LanguageServerId,
_: Option<&'_ Buffer>,
) {
// https://zed.dev/cla
static REGEX: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"(?m)`([^`]+)\n`$").expect("Failed to create REGEX"));

View File

@@ -8,10 +8,9 @@ use futures::future::join_all;
use gpui::{App, AppContext, AsyncApp, Task};
use http_client::github::{AssetKind, GitHubLspBinaryVersion, build_asset_url};
use language::{
Buffer, ContextLocation, ContextProvider, File, LanguageToolchainStore, LspAdapter,
LspAdapterDelegate,
ContextLocation, ContextProvider, File, LanguageToolchainStore, LspAdapter, LspAdapterDelegate,
};
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerId, LanguageServerName};
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerName};
use node_runtime::NodeRuntime;
use project::{Fs, lsp_store::language_server_settings};
use serde_json::{Value, json};
@@ -606,7 +605,6 @@ impl LspAdapter for TypeScriptLspAdapter {
}
}
// >>> https://zed.dev/cla <<<
async fn fetch_server_binary(
&self,
latest_version: Box<dyn 'static + Send + Any>,
@@ -750,15 +748,6 @@ impl LspAdapter for TypeScriptLspAdapter {
("TSX".into(), "typescriptreact".into()),
])
}
fn process_diagnostics(
&self,
d: &mut lsp::PublishDiagnosticsParams,
_: LanguageServerId,
_: Option<&'_ Buffer>,
) {
dbg!("called with ", d);
}
}
async fn get_cached_ts_server_binary(

View File

@@ -280,185 +280,6 @@ impl LspAdapter for VtslsLspAdapter {
("TSX".into(), "typescriptreact".into()),
])
}
fn diagnostic_message_to_markdown(&self, message: &str) -> Option<String> {
use regex::{Captures, Regex};
dbg!(&message);
// Helper functions for formatting
let format_type_block = |prefix: &str, content: &str| -> String {
if prefix.is_empty() {
if content.len() > 50 || content.contains('\n') || content.contains('`') {
format!("\n```typescript\ntype a ={}\n```\n", dbg!(content))
} else {
format!("`{}`", dbg!(content))
}
} else {
if content.len() > 50 || content.contains('\n') || content.contains('`') {
format!(
"{}\n```typescript\ntype a ={}\n```\n",
prefix,
dbg!(content)
)
} else {
format!("{} `{}`", prefix, dbg!(content))
}
}
};
let format_typescript_block =
|content: &str| -> String { format!("\n\n```typescript\n{}\n```\n", dbg!(content)) };
let format_simple_type_block = |content: &str| -> String { format!("`{}`", dbg!(content)) };
let unstyle_code_block = |content: &str| -> String { format!("`{}`", dbg!(content)) };
let mut result = message.to_string();
// Format 'key' with "value"
let re = Regex::new(r#"(\w+)(\s+)'(.+?)'(\s+)with(\s+)"(.+?)""#).unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
format!(
"{}{}`{}`{} with `\"{}\"`",
&caps[1], &caps[2], &caps[3], &caps[4], &caps[6]
)
})
.to_string();
// Format "key"
let re = Regex::new(r#"(\s)'"(.*?)"'(\s|:|.|$)"#).unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
format!("{}`\"{}\"`{}", &caps[1], &caps[2], &caps[3])
})
.to_string();
// Format declare module snippet
let re = Regex::new(r#"['"](declare module )['"](.*)['""];['"']"#).unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
format_typescript_block(&format!("{} \"{}\"", &caps[1], &caps[2]))
})
.to_string();
// Format missing props error
let re = Regex::new(r#"(is missing the following properties from type\s?)'(.*)': ([^:]+)"#)
.unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
let props: Vec<&str> = caps[3].split(", ").filter(|s| !s.is_empty()).collect();
let props_html = props
.iter()
.map(|prop| format!("<li>{}</li>", prop))
.collect::<Vec<_>>()
.join("");
format!("{}`{}`: <ul>{}</ul>", &caps[1], &caps[2], props_html)
})
.to_string();
// Format type pairs
let re = Regex::new(r#"(?i)(types) ['"](.*?)['"] and ['"](.*?)['"][.]?"#).unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
format!("{} `{}` and `{}`", &caps[1], &caps[2], &caps[3])
})
.to_string();
// Format type annotation options
let re = Regex::new(r#"(?i)type annotation must be ['"](.*?)['"] or ['"](.*?)['"][.]?"#)
.unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
format!("type annotation must be `{}` or `{}`", &caps[1], &caps[2])
})
.to_string();
// Format overload
let re = Regex::new(r#"(?i)(Overload \d of \d), ['"](.*?)['"], "#).unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
format!("{}, `{}`, ", &caps[1], &caps[2])
})
.to_string();
// Format simple strings
let re = Regex::new(r#"^['"]"[^"]*"['"]$"#).unwrap();
result = re
.replace_all(&result, |caps: &Captures| format_typescript_block(&caps[0]))
.to_string();
// Replace module 'x' by module "x" for ts error #2307
let re = Regex::new(r#"(?i)(module )'([^"]*?)'"#).unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
format!("{}\"{}\"", &caps[1], &caps[2])
})
.to_string();
// Format string types
let re = Regex::new(r#"(?i)(module|file|file name|imported via) ['""](.*?)['""]"#).unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
format_type_block(&caps[1], &format!("\"{}\"", &caps[2]))
})
.to_string();
// Format types
dbg!(&result);
let re = Regex::new(r#"(?i)(type|type alias|interface|module|file|file name|class|method's|subtype of constraint) ['"](.*?)['"]"#).unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
dbg!(&caps);
format_type_block(&caps[1], &caps[2])
})
.to_string();
// Format reversed types
let re = Regex::new(r#"(?i)(.*)['"]([^>]*)['"] (type|interface|return type|file|module|is (not )?assignable)"#).unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
format!("{}`{}` {}", &caps[1], &caps[2], &caps[3])
})
.to_string();
// Format simple types that didn't captured before
let re = Regex::new(
r#"['"]((void|null|undefined|any|boolean|string|number|bigint|symbol)(\[\])?)['"']"#,
)
.unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
format_simple_type_block(&caps[1])
})
.to_string();
// Format some typescript keywords
let re = Regex::new(r#"['"](import|export|require|in|continue|break|let|false|true|const|new|throw|await|for await|[0-9]+)( ?.*?)['"]"#).unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
format_typescript_block(&format!("{}{}", &caps[1], &caps[2]))
})
.to_string();
// Format return values
let re = Regex::new(r#"(?i)(return|operator) ['"](.*?)['"']"#).unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
format!("{} {}", &caps[1], format_typescript_block(&caps[2]))
})
.to_string();
// Format regular code blocks
let re = Regex::new(r#"(\W|^)'([^'"]*?)'(\W|$)"#).unwrap();
result = re
.replace_all(&result, |caps: &Captures| {
format!("{}{}{}", &caps[1], unstyle_code_block(&caps[2]), &caps[3])
})
.to_string();
Some(result)
}
}
async fn get_cached_ts_server_binary(
@@ -480,25 +301,3 @@ async fn get_cached_ts_server_binary(
.await
.log_err()
}
#[cfg(test)]
mod test {
use super::*;
use indoc::indoc;
#[test]
fn test_diagnostic_message_to_markdown() {
let message = "Property 'user' is missing in type '{ person: { username: string; email: string; }; }' but required in type '{ user: { name: string; email: `${string}@${string}.${string}`; age: number; }; }'.";
let expected = indoc! { "
Property `user` is missing in type `{ person: { username: string; email: string; }; }` but required in type
```typescript
{ user: { name: string; email: `${string}@${string}.${string}`; age: number; }; }
```
"};
let result = VtslsLspAdapter::new(NodeRuntime::unavailable())
.diagnostic_message_to_markdown(message)
.unwrap();
pretty_assertions::assert_eq!(result, expected.to_string());
}
}

View File

@@ -1534,26 +1534,12 @@ impl MarkdownElementBuilder {
rendered_index: self.pending_line.text.len(),
source_index: source_range.start,
});
if text.starts_with("type a =") {
self.pending_line.text.push_str(&text["type a =".len()..]);
} else {
self.pending_line.text.push_str(text);
}
self.pending_line.text.push_str(text);
self.current_source_index = source_range.end;
if let Some(Some(language)) = self.code_block_stack.last() {
dbg!(&language);
let mut offset = 0;
for (mut range, highlight_id) in
language.highlight_text(&Rope::from(text), 0..text.len())
{
if text.starts_with("type a =") {
if range.start < "type a =".len() || range.end < "type a =".len() {
continue;
}
range.start -= "type a =".len();
range.end -= "type a =".len();
};
for (range, highlight_id) in language.highlight_text(&Rope::from(text), 0..text.len()) {
if range.start > offset {
self.pending_line
.runs

View File

@@ -560,11 +560,6 @@ impl DapStore {
fn format_value(mut value: String) -> String {
const LIMIT: usize = 100;
if let Some(index) = value.find("\n") {
value.truncate(index);
value.push_str("");
}
if value.len() > LIMIT {
let mut index = LIMIT;
// If index isn't a char boundary truncate will cause a panic
@@ -572,7 +567,7 @@ impl DapStore {
index -= 1;
}
value.truncate(index);
value.push_str("");
value.push_str("...");
}
format!(": {}", value)

View File

@@ -783,12 +783,8 @@ impl KeymapFile {
target: &KeybindUpdateTarget<'a>,
target_action_value: &Value,
) -> Option<(usize, &'b str)> {
let target_context_parsed =
KeyBindingContextPredicate::parse(target.context.unwrap_or("")).ok();
for (index, section) in keymap.sections().enumerate() {
let section_context_parsed =
KeyBindingContextPredicate::parse(&section.context).ok();
if section_context_parsed != target_context_parsed {
if section.context != target.context.unwrap_or("") {
continue;
}
if section.use_key_equivalents != target.use_key_equivalents {
@@ -839,7 +835,6 @@ pub enum KeybindUpdateOperation<'a> {
},
}
#[derive(Debug)]
pub struct KeybindUpdateTarget<'a> {
pub context: Option<&'a str>,
pub keystrokes: &'a [Keystroke],

View File

@@ -283,7 +283,7 @@ impl KeymapEditor {
let table_interaction_state = TableInteractionState::new(window, cx);
let keystroke_editor = cx.new(|cx| {
let mut keystroke_editor = KeystrokeInput::new(None, window, cx);
let mut keystroke_editor = KeystrokeInput::new(window, cx);
keystroke_editor.highlight_on_focus = false;
keystroke_editor
});
@@ -632,11 +632,6 @@ impl KeymapEditor {
Box::new(EditBinding),
)
.action("Create", Box::new(CreateBinding))
.action_disabled_when(
selected_binding_is_unbound,
"Delete",
Box::new(DeleteBinding),
)
.action("Copy action", Box::new(CopyAction))
.action_disabled_when(
selected_binding_has_no_context,
@@ -1303,16 +1298,7 @@ impl KeybindingEditorModal {
window: &mut Window,
cx: &mut App,
) -> Self {
let keybind_editor = cx.new(|cx| {
KeystrokeInput::new(
editing_keybind
.ui_key_binding
.as_ref()
.map(|keybinding| keybinding.keystrokes.clone()),
window,
cx,
)
});
let keybind_editor = cx.new(|cx| KeystrokeInput::new(window, cx));
let context_editor = cx.new(|cx| {
let mut editor = Editor::single_line(window, cx);
@@ -1816,7 +1802,6 @@ async fn remove_keybinding(
struct KeystrokeInput {
keystrokes: Vec<Keystroke>,
placeholder_keystrokes: Option<Vec<Keystroke>>,
highlight_on_focus: bool,
focus_handle: FocusHandle,
intercept_subscription: Option<Subscription>,
@@ -1824,11 +1809,7 @@ struct KeystrokeInput {
}
impl KeystrokeInput {
fn new(
placeholder_keystrokes: Option<Vec<Keystroke>>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
let focus_handle = cx.focus_handle();
let _focus_subscriptions = [
cx.on_focus_in(&focus_handle, window, Self::on_focus_in),
@@ -1836,7 +1817,6 @@ impl KeystrokeInput {
];
Self {
keystrokes: Vec::new(),
placeholder_keystrokes,
highlight_on_focus: true,
focus_handle,
intercept_subscription: None,
@@ -1924,11 +1904,6 @@ impl KeystrokeInput {
}
fn keystrokes(&self) -> &[Keystroke] {
if let Some(placeholders) = self.placeholder_keystrokes.as_ref()
&& self.keystrokes.is_empty()
{
return placeholders;
}
if self
.keystrokes
.last()
@@ -1938,25 +1913,6 @@ impl KeystrokeInput {
}
return &self.keystrokes;
}
fn render_keystrokes(&self) -> impl Iterator<Item = Div> {
let (keystrokes, color) = if let Some(placeholders) = self.placeholder_keystrokes.as_ref()
&& self.keystrokes.is_empty()
{
(placeholders, Color::Placeholder)
} else {
(&self.keystrokes, Color::Default)
};
keystrokes.iter().map(move |keystroke| {
h_flex().children(ui::render_keystroke(
keystroke,
Some(color),
Some(rems(0.875).into()),
ui::PlatformStyle::platform(),
false,
))
})
}
}
impl EventEmitter<()> for KeystrokeInput {}
@@ -2002,7 +1958,15 @@ impl Render for KeystrokeInput {
.justify_center()
.flex_wrap()
.gap(ui::DynamicSpacing::Base04.rems(cx))
.children(self.render_keystrokes()),
.children(self.keystrokes.iter().map(|keystroke| {
h_flex().children(ui::render_keystroke(
keystroke,
None,
Some(rems(0.875).into()),
ui::PlatformStyle::platform(),
false,
))
})),
)
.child(
h_flex()

View File

@@ -51,6 +51,7 @@ impl OnboardingBanner {
}
fn dismiss(&mut self, cx: &mut Context<Self>) {
telemetry::event!("Banner Dismissed", source = self.source);
persist_dismissed(&self.source, cx);
self.dismissed = true;
cx.notify();
@@ -143,10 +144,7 @@ impl Render for OnboardingBanner {
div().border_l_1().border_color(border_color).child(
IconButton::new("close", IconName::Close)
.icon_size(IconSize::Indicator)
.on_click(cx.listener(|this, _, _window, cx| {
telemetry::event!("Banner Dismissed", source = this.source);
this.dismiss(cx)
}))
.on_click(cx.listener(|this, _, _window, cx| this.dismiss(cx)))
.tooltip(|window, cx| {
Tooltip::with_meta(
"Close Announcement Banner",

View File

@@ -54,7 +54,6 @@ impl sqlez::bindable::Bind for SerializedAxis {
}
}
// > https://zed.dev/cla
impl sqlez::bindable::Column for SerializedAxis {
fn column(
statement: &mut sqlez::statement::Statement,

View File

@@ -1092,6 +1092,14 @@ pub struct Workspace {
impl EventEmitter<Event> for Workspace {}
#[derive(Clone)]
pub struct OpenInDebugJson {
pub scenario: DebugScenario,
pub id: WorkspaceId,
}
impl EventEmitter<OpenInDebugJson> for Workspace {}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct ViewId {
pub creator: CollaboratorId,

View File

@@ -56,13 +56,6 @@ function PrepareForBundle {
New-Item -Path "$innoDir\tools" -ItemType Directory -Force
}
function GenerateLicenses {
$oldErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
. $PSScriptRoot/generate-licenses.ps1
$ErrorActionPreference = $oldErrorActionPreference
}
function BuildZedAndItsFriends {
Write-Output "Building Zed and its friends, for channel: $channel"
# Build zed.exe, cli.exe and auto_update_helper.exe
@@ -245,7 +238,6 @@ $innoDir = "$env:ZED_WORKSPACE\inno"
CheckEnvironmentVariables
PrepareForBundle
GenerateLicenses
BuildZedAndItsFriends
MakeAppx
SignZedAndItsFriends

View File

@@ -1,44 +0,0 @@
$CARGO_ABOUT_VERSION="0.7"
$outputFile=$args[0] ? $args[0] : "$(Get-Location)/assets/licenses.md"
$templateFile="script/licenses/template.md.hbs"
New-Item -Path "$outputFile" -ItemType File -Value "" -Force
@(
"# ###### THEME LICENSES ######\n"
Get-Content assets/themes/LICENSES
"\n# ###### ICON LICENSES ######\n"
Get-Content assets/icons/LICENSES
"\n# ###### CODE LICENSES ######\n"
) | Add-Content -Path $outputFile
$versionOutput = cargo about --version
if (-not ($versionOutput -match "cargo-about $CARGO_ABOUT_VERSION")) {
Write-Host "Installing cargo-about@^$CARGO_ABOUT_VERSION..."
cargo install "cargo-about@^$CARGO_ABOUT_VERSION"
} else {
Write-Host "cargo-about@^$CARGO_ABOUT_VERSION" is already installed
}
Write-Host "Generating cargo licenses"
$failFlag = $env:ALLOW_MISSING_LICENSES ? "--fail" : ""
$args = @('about', 'generate', $failFlag, '-c', 'script/licenses/zed-licenses.toml', $templateFile, '-o', $outputFile) | Where-Object { $_ }
cargo @args
Write-Host "Applying replacements"
$replacements = @{
'&quot;' = '"'
'&#x27;' = "'"
'&#x3D;' = '='
'&#x60;' = '`'
'&lt;' = '<'
'&gt;' = '>'
}
$content = Get-Content $outputFile
foreach ($find in $replacements.keys) {
$content = $content -replace $find, $replacements[$find]
}
$content | Set-Content $outputFile
Write-Host "generate-licenses completed. See $outputFile"