Compare commits
4 Commits
pretty-typ
...
debug-edit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bded0e12f4 | ||
|
|
124b4645c4 | ||
|
|
b24a30916a | ||
|
|
05e0a812c4 |
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -9134,7 +9134,6 @@ dependencies = [
|
||||
"futures 0.3.31",
|
||||
"gpui",
|
||||
"http_client",
|
||||
"indoc",
|
||||
"language",
|
||||
"log",
|
||||
"lsp",
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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![],
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
})?;
|
||||
|
||||
@@ -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)
|
||||
}),
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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")
|
||||
})??;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"));
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(§ion.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],
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = @{
|
||||
'"' = '"'
|
||||
''' = "'"
|
||||
'=' = '='
|
||||
'`' = '`'
|
||||
'<' = '<'
|
||||
'>' = '>'
|
||||
}
|
||||
$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"
|
||||
Reference in New Issue
Block a user