Merge branch 'main' into edit-file-tool
This commit is contained in:
commit
d52e0f47b5
30 changed files with 320 additions and 104 deletions
|
@ -1,6 +1,6 @@
|
||||||
# syntax = docker/dockerfile:1.2
|
# syntax = docker/dockerfile:1.2
|
||||||
|
|
||||||
FROM rust:1.89-bookworm as builder
|
FROM rust:1.88-bookworm as builder
|
||||||
WORKDIR app
|
WORKDIR app
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
|
|
@ -596,6 +596,8 @@
|
||||||
// when a corresponding project entry becomes active.
|
// when a corresponding project entry becomes active.
|
||||||
// Gitignored entries are never auto revealed.
|
// Gitignored entries are never auto revealed.
|
||||||
"auto_reveal_entries": true,
|
"auto_reveal_entries": true,
|
||||||
|
// Whether the project panel should open on startup.
|
||||||
|
"starts_open": true,
|
||||||
// Whether to fold directories automatically and show compact folders
|
// Whether to fold directories automatically and show compact folders
|
||||||
// (e.g. "a/b/c" ) when a directory has only one subdirectory inside.
|
// (e.g. "a/b/c" ) when a directory has only one subdirectory inside.
|
||||||
"auto_fold_dirs": true,
|
"auto_fold_dirs": true,
|
||||||
|
@ -1171,6 +1173,9 @@
|
||||||
// Sets a delay after which the inline blame information is shown.
|
// Sets a delay after which the inline blame information is shown.
|
||||||
// Delay is restarted with every cursor movement.
|
// Delay is restarted with every cursor movement.
|
||||||
"delay_ms": 0,
|
"delay_ms": 0,
|
||||||
|
// The amount of padding between the end of the source line and the start
|
||||||
|
// of the inline blame in units of em widths.
|
||||||
|
"padding": 7,
|
||||||
// Whether or not to display the git commit summary on the same line.
|
// Whether or not to display the git commit summary on the same line.
|
||||||
"show_commit_summary": false,
|
"show_commit_summary": false,
|
||||||
// The minimum column number to show the inline blame information at
|
// The minimum column number to show the inline blame information at
|
||||||
|
@ -1233,6 +1238,11 @@
|
||||||
// 2. hour24
|
// 2. hour24
|
||||||
"hour_format": "hour12"
|
"hour_format": "hour12"
|
||||||
},
|
},
|
||||||
|
// Status bar-related settings.
|
||||||
|
"status_bar": {
|
||||||
|
// Whether to show the active language button in the status bar.
|
||||||
|
"active_language_button": true
|
||||||
|
},
|
||||||
// Settings specific to the terminal
|
// Settings specific to the terminal
|
||||||
"terminal": {
|
"terminal": {
|
||||||
// What shell to use when opening a terminal. May take 3 values:
|
// What shell to use when opening a terminal. May take 3 values:
|
||||||
|
|
|
@ -8,7 +8,6 @@ use agent_client_protocol as acp;
|
||||||
use anyhow::{Context as _, Result};
|
use anyhow::{Context as _, Result};
|
||||||
use assistant_tool::ActionLog;
|
use assistant_tool::ActionLog;
|
||||||
use editor::Bias;
|
use editor::Bias;
|
||||||
use futures::future::{Fuse, FusedFuture};
|
|
||||||
use futures::{FutureExt, channel::oneshot, future::BoxFuture};
|
use futures::{FutureExt, channel::oneshot, future::BoxFuture};
|
||||||
use gpui::{AppContext, Context, Entity, EventEmitter, SharedString, Task};
|
use gpui::{AppContext, Context, Entity, EventEmitter, SharedString, Task};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
@ -482,7 +481,7 @@ pub struct AcpThread {
|
||||||
project: Entity<Project>,
|
project: Entity<Project>,
|
||||||
action_log: Entity<ActionLog>,
|
action_log: Entity<ActionLog>,
|
||||||
shared_buffers: HashMap<Entity<Buffer>, BufferSnapshot>,
|
shared_buffers: HashMap<Entity<Buffer>, BufferSnapshot>,
|
||||||
send_task: Option<Fuse<Task<()>>>,
|
send_task: Option<Task<()>>,
|
||||||
connection: Rc<dyn AgentConnection>,
|
connection: Rc<dyn AgentConnection>,
|
||||||
session_id: acp::SessionId,
|
session_id: acp::SessionId,
|
||||||
}
|
}
|
||||||
|
@ -572,11 +571,7 @@ impl AcpThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn status(&self) -> ThreadStatus {
|
pub fn status(&self) -> ThreadStatus {
|
||||||
if self
|
if self.send_task.is_some() {
|
||||||
.send_task
|
|
||||||
.as_ref()
|
|
||||||
.map_or(false, |t| !t.is_terminated())
|
|
||||||
{
|
|
||||||
if self.waiting_for_tool_confirmation() {
|
if self.waiting_for_tool_confirmation() {
|
||||||
ThreadStatus::WaitingForToolConfirmation
|
ThreadStatus::WaitingForToolConfirmation
|
||||||
} else {
|
} else {
|
||||||
|
@ -966,31 +961,29 @@ impl AcpThread {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
let cancel_task = self.cancel(cx);
|
let cancel_task = self.cancel(cx);
|
||||||
|
|
||||||
self.send_task = Some(
|
self.send_task = Some(cx.spawn(async move |this, cx| {
|
||||||
cx.spawn(async move |this, cx| {
|
async {
|
||||||
async {
|
cancel_task.await;
|
||||||
cancel_task.await;
|
|
||||||
|
|
||||||
let result = this
|
let result = this
|
||||||
.update(cx, |this, cx| {
|
.update(cx, |this, cx| {
|
||||||
this.connection.prompt(
|
this.connection.prompt(
|
||||||
acp::PromptRequest {
|
acp::PromptRequest {
|
||||||
prompt: message,
|
prompt: message,
|
||||||
session_id: this.session_id.clone(),
|
session_id: this.session_id.clone(),
|
||||||
},
|
},
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
})?
|
})?
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
tx.send(result).log_err();
|
tx.send(result).log_err();
|
||||||
anyhow::Ok(())
|
|
||||||
}
|
anyhow::Ok(())
|
||||||
.await
|
}
|
||||||
.log_err();
|
.await
|
||||||
})
|
.log_err();
|
||||||
.fuse(),
|
}));
|
||||||
);
|
|
||||||
|
|
||||||
cx.spawn(async move |this, cx| match rx.await {
|
cx.spawn(async move |this, cx| match rx.await {
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
|
@ -998,7 +991,23 @@ impl AcpThread {
|
||||||
.log_err();
|
.log_err();
|
||||||
Err(e)?
|
Err(e)?
|
||||||
}
|
}
|
||||||
_ => {
|
result => {
|
||||||
|
let cancelled = matches!(
|
||||||
|
result,
|
||||||
|
Ok(Ok(acp::PromptResponse {
|
||||||
|
stop_reason: acp::StopReason::Cancelled
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
// We only take the task if the current prompt wasn't cancelled.
|
||||||
|
//
|
||||||
|
// This prompt may have been cancelled because another one was sent
|
||||||
|
// while it was still generating. In these cases, dropping `send_task`
|
||||||
|
// would cause the next generation to be cancelled.
|
||||||
|
if !cancelled {
|
||||||
|
this.update(cx, |this, _cx| this.send_task.take()).ok();
|
||||||
|
}
|
||||||
|
|
||||||
this.update(cx, |_, cx| cx.emit(AcpThreadEvent::Stopped))
|
this.update(cx, |_, cx| cx.emit(AcpThreadEvent::Stopped))
|
||||||
.log_err();
|
.log_err();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -3101,9 +3101,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
|
||||||
// Turn inline-blame-off by default so no state is transferred without us explicitly doing so
|
// Turn inline-blame-off by default so no state is transferred without us explicitly doing so
|
||||||
let inline_blame_off_settings = Some(InlineBlameSettings {
|
let inline_blame_off_settings = Some(InlineBlameSettings {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
delay_ms: None,
|
..Default::default()
|
||||||
min_column: None,
|
|
||||||
show_commit_summary: false,
|
|
||||||
});
|
});
|
||||||
cx_a.update(|cx| {
|
cx_a.update(|cx| {
|
||||||
SettingsStore::update_global(cx, |store, cx| {
|
SettingsStore::update_global(cx, |store, cx| {
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub struct EditorSettings {
|
||||||
pub lsp_highlight_debounce: u64,
|
pub lsp_highlight_debounce: u64,
|
||||||
pub hover_popover_enabled: bool,
|
pub hover_popover_enabled: bool,
|
||||||
pub hover_popover_delay: u64,
|
pub hover_popover_delay: u64,
|
||||||
|
pub status_bar: StatusBar,
|
||||||
pub toolbar: Toolbar,
|
pub toolbar: Toolbar,
|
||||||
pub scrollbar: Scrollbar,
|
pub scrollbar: Scrollbar,
|
||||||
pub minimap: Minimap,
|
pub minimap: Minimap,
|
||||||
|
@ -125,6 +126,14 @@ pub struct JupyterContent {
|
||||||
pub enabled: Option<bool>,
|
pub enabled: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||||
|
pub struct StatusBar {
|
||||||
|
/// Whether to display the active language button in the status bar.
|
||||||
|
///
|
||||||
|
/// Default: true
|
||||||
|
pub active_language_button: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||||
pub struct Toolbar {
|
pub struct Toolbar {
|
||||||
pub breadcrumbs: bool,
|
pub breadcrumbs: bool,
|
||||||
|
@ -440,6 +449,8 @@ pub struct EditorSettingsContent {
|
||||||
///
|
///
|
||||||
/// Default: 300
|
/// Default: 300
|
||||||
pub hover_popover_delay: Option<u64>,
|
pub hover_popover_delay: Option<u64>,
|
||||||
|
/// Status bar related settings
|
||||||
|
pub status_bar: Option<StatusBarContent>,
|
||||||
/// Toolbar related settings
|
/// Toolbar related settings
|
||||||
pub toolbar: Option<ToolbarContent>,
|
pub toolbar: Option<ToolbarContent>,
|
||||||
/// Scrollbar related settings
|
/// Scrollbar related settings
|
||||||
|
@ -567,6 +578,15 @@ pub struct EditorSettingsContent {
|
||||||
pub lsp_document_colors: Option<DocumentColorsRenderMode>,
|
pub lsp_document_colors: Option<DocumentColorsRenderMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Status bar related settings
|
||||||
|
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||||
|
pub struct StatusBarContent {
|
||||||
|
/// Whether to display the active language button in the status bar.
|
||||||
|
///
|
||||||
|
/// Default: true
|
||||||
|
pub active_language_button: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
// Toolbar related settings
|
// Toolbar related settings
|
||||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||||
pub struct ToolbarContent {
|
pub struct ToolbarContent {
|
||||||
|
|
|
@ -86,8 +86,6 @@ use util::post_inc;
|
||||||
use util::{RangeExt, ResultExt, debug_panic};
|
use util::{RangeExt, ResultExt, debug_panic};
|
||||||
use workspace::{CollaboratorId, Workspace, item::Item, notifications::NotifyTaskExt};
|
use workspace::{CollaboratorId, Workspace, item::Item, notifications::NotifyTaskExt};
|
||||||
|
|
||||||
const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 7.;
|
|
||||||
|
|
||||||
/// Determines what kinds of highlights should be applied to a lines background.
|
/// Determines what kinds of highlights should be applied to a lines background.
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
struct LineHighlightSpec {
|
struct LineHighlightSpec {
|
||||||
|
@ -2428,10 +2426,13 @@ impl EditorElement {
|
||||||
let editor = self.editor.read(cx);
|
let editor = self.editor.read(cx);
|
||||||
let blame = editor.blame.clone()?;
|
let blame = editor.blame.clone()?;
|
||||||
let padding = {
|
let padding = {
|
||||||
const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 6.;
|
|
||||||
const INLINE_ACCEPT_SUGGESTION_EM_WIDTHS: f32 = 14.;
|
const INLINE_ACCEPT_SUGGESTION_EM_WIDTHS: f32 = 14.;
|
||||||
|
|
||||||
let mut padding = INLINE_BLAME_PADDING_EM_WIDTHS;
|
let mut padding = ProjectSettings::get_global(cx)
|
||||||
|
.git
|
||||||
|
.inline_blame
|
||||||
|
.unwrap_or_default()
|
||||||
|
.padding as f32;
|
||||||
|
|
||||||
if let Some(edit_prediction) = editor.active_edit_prediction.as_ref() {
|
if let Some(edit_prediction) = editor.active_edit_prediction.as_ref() {
|
||||||
match &edit_prediction.completion {
|
match &edit_prediction.completion {
|
||||||
|
@ -2469,7 +2470,7 @@ impl EditorElement {
|
||||||
let min_column_in_pixels = ProjectSettings::get_global(cx)
|
let min_column_in_pixels = ProjectSettings::get_global(cx)
|
||||||
.git
|
.git
|
||||||
.inline_blame
|
.inline_blame
|
||||||
.and_then(|settings| settings.min_column)
|
.map(|settings| settings.min_column)
|
||||||
.map(|col| self.column_pixels(col as usize, window))
|
.map(|col| self.column_pixels(col as usize, window))
|
||||||
.unwrap_or(px(0.));
|
.unwrap_or(px(0.));
|
||||||
let min_start = content_origin.x - scroll_pixel_position.x + min_column_in_pixels;
|
let min_start = content_origin.x - scroll_pixel_position.x + min_column_in_pixels;
|
||||||
|
@ -8030,12 +8031,20 @@ impl Element for EditorElement {
|
||||||
autoscroll_containing_element,
|
autoscroll_containing_element,
|
||||||
needs_horizontal_autoscroll,
|
needs_horizontal_autoscroll,
|
||||||
) = self.editor.update(cx, |editor, cx| {
|
) = self.editor.update(cx, |editor, cx| {
|
||||||
let autoscroll_request = editor.autoscroll_request();
|
let autoscroll_request = editor.scroll_manager.take_autoscroll_request();
|
||||||
|
|
||||||
let autoscroll_containing_element =
|
let autoscroll_containing_element =
|
||||||
autoscroll_request.is_some() || editor.has_pending_selection();
|
autoscroll_request.is_some() || editor.has_pending_selection();
|
||||||
|
|
||||||
let (needs_horizontal_autoscroll, was_scrolled) = editor
|
let (needs_horizontal_autoscroll, was_scrolled) = editor
|
||||||
.autoscroll_vertically(bounds, line_height, max_scroll_top, window, cx);
|
.autoscroll_vertically(
|
||||||
|
bounds,
|
||||||
|
line_height,
|
||||||
|
max_scroll_top,
|
||||||
|
autoscroll_request,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
if was_scrolled.0 {
|
if was_scrolled.0 {
|
||||||
snapshot = editor.snapshot(window, cx);
|
snapshot = editor.snapshot(window, cx);
|
||||||
}
|
}
|
||||||
|
@ -8357,7 +8366,13 @@ impl Element for EditorElement {
|
||||||
})
|
})
|
||||||
.flatten()?;
|
.flatten()?;
|
||||||
let mut element = render_inline_blame_entry(blame_entry, &style, cx)?;
|
let mut element = render_inline_blame_entry(blame_entry, &style, cx)?;
|
||||||
let inline_blame_padding = INLINE_BLAME_PADDING_EM_WIDTHS * em_advance;
|
let inline_blame_padding = ProjectSettings::get_global(cx)
|
||||||
|
.git
|
||||||
|
.inline_blame
|
||||||
|
.unwrap_or_default()
|
||||||
|
.padding
|
||||||
|
as f32
|
||||||
|
* em_advance;
|
||||||
Some(
|
Some(
|
||||||
element
|
element
|
||||||
.layout_as_root(AvailableSpace::min_size(), window, cx)
|
.layout_as_root(AvailableSpace::min_size(), window, cx)
|
||||||
|
@ -8425,7 +8440,11 @@ impl Element for EditorElement {
|
||||||
Ok(blocks) => blocks,
|
Ok(blocks) => blocks,
|
||||||
Err(resized_blocks) => {
|
Err(resized_blocks) => {
|
||||||
self.editor.update(cx, |editor, cx| {
|
self.editor.update(cx, |editor, cx| {
|
||||||
editor.resize_blocks(resized_blocks, autoscroll_request, cx)
|
editor.resize_blocks(
|
||||||
|
resized_blocks,
|
||||||
|
autoscroll_request.map(|(autoscroll, _)| autoscroll),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
return self.prepaint(None, _inspector_id, bounds, &mut (), window, cx);
|
return self.prepaint(None, _inspector_id, bounds, &mut (), window, cx);
|
||||||
}
|
}
|
||||||
|
@ -8470,6 +8489,7 @@ impl Element for EditorElement {
|
||||||
scroll_width,
|
scroll_width,
|
||||||
em_advance,
|
em_advance,
|
||||||
&line_layouts,
|
&line_layouts,
|
||||||
|
autoscroll_request,
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
|
|
@ -348,8 +348,8 @@ impl ScrollManager {
|
||||||
self.show_scrollbars
|
self.show_scrollbars
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn autoscroll_request(&self) -> Option<Autoscroll> {
|
pub fn take_autoscroll_request(&mut self) -> Option<(Autoscroll, bool)> {
|
||||||
self.autoscroll_request.map(|(autoscroll, _)| autoscroll)
|
self.autoscroll_request.take()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_scrollbar_state(&self) -> Option<&ActiveScrollbarState> {
|
pub fn active_scrollbar_state(&self) -> Option<&ActiveScrollbarState> {
|
||||||
|
|
|
@ -102,15 +102,12 @@ impl AutoscrollStrategy {
|
||||||
pub(crate) struct NeedsHorizontalAutoscroll(pub(crate) bool);
|
pub(crate) struct NeedsHorizontalAutoscroll(pub(crate) bool);
|
||||||
|
|
||||||
impl Editor {
|
impl Editor {
|
||||||
pub fn autoscroll_request(&self) -> Option<Autoscroll> {
|
|
||||||
self.scroll_manager.autoscroll_request()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn autoscroll_vertically(
|
pub(crate) fn autoscroll_vertically(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
line_height: Pixels,
|
line_height: Pixels,
|
||||||
max_scroll_top: f32,
|
max_scroll_top: f32,
|
||||||
|
autoscroll_request: Option<(Autoscroll, bool)>,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Editor>,
|
cx: &mut Context<Editor>,
|
||||||
) -> (NeedsHorizontalAutoscroll, WasScrolled) {
|
) -> (NeedsHorizontalAutoscroll, WasScrolled) {
|
||||||
|
@ -137,7 +134,7 @@ impl Editor {
|
||||||
WasScrolled(false)
|
WasScrolled(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some((autoscroll, local)) = self.scroll_manager.autoscroll_request.take() else {
|
let Some((autoscroll, local)) = autoscroll_request else {
|
||||||
return (NeedsHorizontalAutoscroll(false), editor_was_scrolled);
|
return (NeedsHorizontalAutoscroll(false), editor_was_scrolled);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -284,9 +281,12 @@ impl Editor {
|
||||||
scroll_width: Pixels,
|
scroll_width: Pixels,
|
||||||
em_advance: Pixels,
|
em_advance: Pixels,
|
||||||
layouts: &[LineWithInvisibles],
|
layouts: &[LineWithInvisibles],
|
||||||
|
autoscroll_request: Option<(Autoscroll, bool)>,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Option<gpui::Point<f32>> {
|
) -> Option<gpui::Point<f32>> {
|
||||||
|
let (_, local) = autoscroll_request?;
|
||||||
|
|
||||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
let selections = self.selections.all::<Point>(cx);
|
let selections = self.selections.all::<Point>(cx);
|
||||||
let mut scroll_position = self.scroll_manager.scroll_position(&display_map);
|
let mut scroll_position = self.scroll_manager.scroll_position(&display_map);
|
||||||
|
@ -335,10 +335,10 @@ impl Editor {
|
||||||
|
|
||||||
let was_scrolled = if target_left < scroll_left {
|
let was_scrolled = if target_left < scroll_left {
|
||||||
scroll_position.x = target_left / em_advance;
|
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, local, true, window, cx)
|
||||||
} else if target_right > scroll_right {
|
} else if target_right > scroll_right {
|
||||||
scroll_position.x = (target_right - viewport_width) / em_advance;
|
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, local, true, window, cx)
|
||||||
} else {
|
} else {
|
||||||
WasScrolled(false)
|
WasScrolled(false)
|
||||||
};
|
};
|
||||||
|
|
|
@ -402,11 +402,11 @@ impl GitRepository for FakeGitRepository {
|
||||||
&self,
|
&self,
|
||||||
_paths: Vec<RepoPath>,
|
_paths: Vec<RepoPath>,
|
||||||
_env: Arc<HashMap<String, String>>,
|
_env: Arc<HashMap<String, String>>,
|
||||||
) -> BoxFuture<'_, Result<()>> {
|
) -> BoxFuture<Result<()>> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stash_pop(&self, _env: Arc<HashMap<String, String>>) -> BoxFuture<'_, Result<()>> {
|
fn stash_pop(&self, _env: Arc<HashMap<String, String>>) -> BoxFuture<Result<()>> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -399,9 +399,9 @@ pub trait GitRepository: Send + Sync {
|
||||||
&self,
|
&self,
|
||||||
paths: Vec<RepoPath>,
|
paths: Vec<RepoPath>,
|
||||||
env: Arc<HashMap<String, String>>,
|
env: Arc<HashMap<String, String>>,
|
||||||
) -> BoxFuture<'_, Result<()>>;
|
) -> BoxFuture<Result<()>>;
|
||||||
|
|
||||||
fn stash_pop(&self, env: Arc<HashMap<String, String>>) -> BoxFuture<'_, Result<()>>;
|
fn stash_pop(&self, env: Arc<HashMap<String, String>>) -> BoxFuture<Result<()>>;
|
||||||
|
|
||||||
fn push(
|
fn push(
|
||||||
&self,
|
&self,
|
||||||
|
@ -1203,7 +1203,7 @@ impl GitRepository for RealGitRepository {
|
||||||
&self,
|
&self,
|
||||||
paths: Vec<RepoPath>,
|
paths: Vec<RepoPath>,
|
||||||
env: Arc<HashMap<String, String>>,
|
env: Arc<HashMap<String, String>>,
|
||||||
) -> BoxFuture<'_, Result<()>> {
|
) -> BoxFuture<Result<()>> {
|
||||||
let working_directory = self.working_directory();
|
let working_directory = self.working_directory();
|
||||||
self.executor
|
self.executor
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
|
@ -1227,7 +1227,7 @@ impl GitRepository for RealGitRepository {
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stash_pop(&self, env: Arc<HashMap<String, String>>) -> BoxFuture<'_, Result<()>> {
|
fn stash_pop(&self, env: Arc<HashMap<String, String>>) -> BoxFuture<Result<()>> {
|
||||||
let working_directory = self.working_directory();
|
let working_directory = self.working_directory();
|
||||||
self.executor
|
self.executor
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
|
|
|
@ -1,12 +1,22 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use git::{
|
use git::{
|
||||||
BuildCommitPermalinkParams, BuildPermalinkParams, GitHostingProvider, ParsedGitRemote,
|
BuildCommitPermalinkParams, BuildPermalinkParams, GitHostingProvider, ParsedGitRemote,
|
||||||
RemoteUrl,
|
PullRequest, RemoteUrl,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn pull_request_regex() -> &'static Regex {
|
||||||
|
static PULL_REQUEST_REGEX: LazyLock<Regex> = LazyLock::new(|| {
|
||||||
|
// This matches Bitbucket PR reference pattern: (pull request #xxx)
|
||||||
|
Regex::new(r"\(pull request #(\d+)\)").unwrap()
|
||||||
|
});
|
||||||
|
&PULL_REQUEST_REGEX
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Bitbucket {
|
pub struct Bitbucket {
|
||||||
name: String,
|
name: String,
|
||||||
base_url: Url,
|
base_url: Url,
|
||||||
|
@ -96,6 +106,22 @@ impl GitHostingProvider for Bitbucket {
|
||||||
);
|
);
|
||||||
permalink
|
permalink
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn extract_pull_request(&self, remote: &ParsedGitRemote, message: &str) -> Option<PullRequest> {
|
||||||
|
// Check first line of commit message for PR references
|
||||||
|
let first_line = message.lines().next()?;
|
||||||
|
|
||||||
|
// Try to match against our PR patterns
|
||||||
|
let capture = pull_request_regex().captures(first_line)?;
|
||||||
|
let number = capture.get(1)?.as_str().parse::<u32>().ok()?;
|
||||||
|
|
||||||
|
// Construct the PR URL in Bitbucket format
|
||||||
|
let mut url = self.base_url();
|
||||||
|
let path = format!("/{}/{}/pull-requests/{}", remote.owner, remote.repo, number);
|
||||||
|
url.set_path(&path);
|
||||||
|
|
||||||
|
Some(PullRequest { number, url })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -203,4 +229,34 @@ mod tests {
|
||||||
"https://bitbucket.org/zed-industries/zed/src/f00b4r/main.rs#lines-24:48";
|
"https://bitbucket.org/zed-industries/zed/src/f00b4r/main.rs#lines-24:48";
|
||||||
assert_eq!(permalink.to_string(), expected_url.to_string())
|
assert_eq!(permalink.to_string(), expected_url.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bitbucket_pull_requests() {
|
||||||
|
use indoc::indoc;
|
||||||
|
|
||||||
|
let remote = ParsedGitRemote {
|
||||||
|
owner: "zed-industries".into(),
|
||||||
|
repo: "zed".into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let bitbucket = Bitbucket::public_instance();
|
||||||
|
|
||||||
|
// Test message without PR reference
|
||||||
|
let message = "This does not contain a pull request";
|
||||||
|
assert!(bitbucket.extract_pull_request(&remote, message).is_none());
|
||||||
|
|
||||||
|
// Pull request number at end of first line
|
||||||
|
let message = indoc! {r#"
|
||||||
|
Merged in feature-branch (pull request #123)
|
||||||
|
|
||||||
|
Some detailed description of the changes.
|
||||||
|
"#};
|
||||||
|
|
||||||
|
let pr = bitbucket.extract_pull_request(&remote, message).unwrap();
|
||||||
|
assert_eq!(pr.number, 123);
|
||||||
|
assert_eq!(
|
||||||
|
pr.url.as_str(),
|
||||||
|
"https://bitbucket.org/zed-industries/zed/pull-requests/123"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -461,8 +461,6 @@ fn skip_whitespace(source: &str) -> &str {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use core::slice;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate as gpui;
|
use crate as gpui;
|
||||||
use KeyBindingContextPredicate::*;
|
use KeyBindingContextPredicate::*;
|
||||||
|
@ -676,11 +674,11 @@ mod tests {
|
||||||
assert!(predicate.eval(&contexts));
|
assert!(predicate.eval(&contexts));
|
||||||
|
|
||||||
assert!(!predicate.eval(&[]));
|
assert!(!predicate.eval(&[]));
|
||||||
assert!(!predicate.eval(slice::from_ref(&child_context)));
|
assert!(!predicate.eval(&[child_context.clone()]));
|
||||||
assert!(!predicate.eval(&[parent_context]));
|
assert!(!predicate.eval(&[parent_context]));
|
||||||
|
|
||||||
let zany_predicate = KeyBindingContextPredicate::parse("child > child").unwrap();
|
let zany_predicate = KeyBindingContextPredicate::parse("child > child").unwrap();
|
||||||
assert!(!zany_predicate.eval(slice::from_ref(&child_context)));
|
assert!(!zany_predicate.eval(&[child_context.clone()]));
|
||||||
assert!(zany_predicate.eval(&[child_context.clone(), child_context.clone()]));
|
assert!(zany_predicate.eval(&[child_context.clone(), child_context.clone()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -692,13 +690,13 @@ mod tests {
|
||||||
let parent_context = KeyContext::try_from("parent").unwrap();
|
let parent_context = KeyContext::try_from("parent").unwrap();
|
||||||
let child_context = KeyContext::try_from("child").unwrap();
|
let child_context = KeyContext::try_from("child").unwrap();
|
||||||
|
|
||||||
assert!(not_predicate.eval(slice::from_ref(&workspace_context)));
|
assert!(not_predicate.eval(&[workspace_context.clone()]));
|
||||||
assert!(!not_predicate.eval(slice::from_ref(&editor_context)));
|
assert!(!not_predicate.eval(&[editor_context.clone()]));
|
||||||
assert!(!not_predicate.eval(&[editor_context.clone(), workspace_context.clone()]));
|
assert!(!not_predicate.eval(&[editor_context.clone(), workspace_context.clone()]));
|
||||||
assert!(!not_predicate.eval(&[workspace_context.clone(), editor_context.clone()]));
|
assert!(!not_predicate.eval(&[workspace_context.clone(), editor_context.clone()]));
|
||||||
|
|
||||||
let complex_not = KeyBindingContextPredicate::parse("!editor && workspace").unwrap();
|
let complex_not = KeyBindingContextPredicate::parse("!editor && workspace").unwrap();
|
||||||
assert!(complex_not.eval(slice::from_ref(&workspace_context)));
|
assert!(complex_not.eval(&[workspace_context.clone()]));
|
||||||
assert!(!complex_not.eval(&[editor_context.clone(), workspace_context.clone()]));
|
assert!(!complex_not.eval(&[editor_context.clone(), workspace_context.clone()]));
|
||||||
|
|
||||||
let not_mode_predicate = KeyBindingContextPredicate::parse("!(mode == full)").unwrap();
|
let not_mode_predicate = KeyBindingContextPredicate::parse("!(mode == full)").unwrap();
|
||||||
|
@ -711,18 +709,18 @@ mod tests {
|
||||||
assert!(not_mode_predicate.eval(&[other_mode_context]));
|
assert!(not_mode_predicate.eval(&[other_mode_context]));
|
||||||
|
|
||||||
let not_descendant = KeyBindingContextPredicate::parse("!(parent > child)").unwrap();
|
let not_descendant = KeyBindingContextPredicate::parse("!(parent > child)").unwrap();
|
||||||
assert!(not_descendant.eval(slice::from_ref(&parent_context)));
|
assert!(not_descendant.eval(&[parent_context.clone()]));
|
||||||
assert!(not_descendant.eval(slice::from_ref(&child_context)));
|
assert!(not_descendant.eval(&[child_context.clone()]));
|
||||||
assert!(!not_descendant.eval(&[parent_context.clone(), child_context.clone()]));
|
assert!(!not_descendant.eval(&[parent_context.clone(), child_context.clone()]));
|
||||||
|
|
||||||
let not_descendant = KeyBindingContextPredicate::parse("parent > !child").unwrap();
|
let not_descendant = KeyBindingContextPredicate::parse("parent > !child").unwrap();
|
||||||
assert!(!not_descendant.eval(slice::from_ref(&parent_context)));
|
assert!(!not_descendant.eval(&[parent_context.clone()]));
|
||||||
assert!(!not_descendant.eval(slice::from_ref(&child_context)));
|
assert!(!not_descendant.eval(&[child_context.clone()]));
|
||||||
assert!(!not_descendant.eval(&[parent_context.clone(), child_context.clone()]));
|
assert!(!not_descendant.eval(&[parent_context.clone(), child_context.clone()]));
|
||||||
|
|
||||||
let double_not = KeyBindingContextPredicate::parse("!!editor").unwrap();
|
let double_not = KeyBindingContextPredicate::parse("!!editor").unwrap();
|
||||||
assert!(double_not.eval(slice::from_ref(&editor_context)));
|
assert!(double_not.eval(&[editor_context.clone()]));
|
||||||
assert!(!double_not.eval(slice::from_ref(&workspace_context)));
|
assert!(!double_not.eval(&[workspace_context.clone()]));
|
||||||
|
|
||||||
// Test complex descendant cases
|
// Test complex descendant cases
|
||||||
let workspace_context = KeyContext::try_from("Workspace").unwrap();
|
let workspace_context = KeyContext::try_from("Workspace").unwrap();
|
||||||
|
@ -756,9 +754,9 @@ mod tests {
|
||||||
|
|
||||||
// !Workspace - shouldn't match when Workspace is in the context
|
// !Workspace - shouldn't match when Workspace is in the context
|
||||||
let not_workspace = KeyBindingContextPredicate::parse("!Workspace").unwrap();
|
let not_workspace = KeyBindingContextPredicate::parse("!Workspace").unwrap();
|
||||||
assert!(!not_workspace.eval(slice::from_ref(&workspace_context)));
|
assert!(!not_workspace.eval(&[workspace_context.clone()]));
|
||||||
assert!(not_workspace.eval(slice::from_ref(&pane_context)));
|
assert!(not_workspace.eval(&[pane_context.clone()]));
|
||||||
assert!(not_workspace.eval(slice::from_ref(&editor_context)));
|
assert!(not_workspace.eval(&[editor_context.clone()]));
|
||||||
assert!(!not_workspace.eval(&workspace_pane_editor));
|
assert!(!not_workspace.eval(&workspace_pane_editor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,28 @@
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use windows::Win32::UI::WindowsAndMessaging::HCURSOR;
|
use windows::Win32::{Foundation::HANDLE, UI::WindowsAndMessaging::HCURSOR};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(crate) struct SafeHandle {
|
||||||
|
raw: HANDLE,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for SafeHandle {}
|
||||||
|
unsafe impl Sync for SafeHandle {}
|
||||||
|
|
||||||
|
impl From<HANDLE> for SafeHandle {
|
||||||
|
fn from(value: HANDLE) -> Self {
|
||||||
|
SafeHandle { raw: value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for SafeHandle {
|
||||||
|
type Target = HANDLE;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.raw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) struct SafeCursor {
|
pub(crate) struct SafeCursor {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use editor::Editor;
|
use editor::{Editor, EditorSettings};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
Context, Entity, IntoElement, ParentElement, Render, Subscription, WeakEntity, Window, div,
|
Context, Entity, IntoElement, ParentElement, Render, Subscription, WeakEntity, Window, div,
|
||||||
};
|
};
|
||||||
use language::LanguageName;
|
use language::LanguageName;
|
||||||
|
use settings::Settings as _;
|
||||||
use ui::{Button, ButtonCommon, Clickable, FluentBuilder, LabelSize, Tooltip};
|
use ui::{Button, ButtonCommon, Clickable, FluentBuilder, LabelSize, Tooltip};
|
||||||
use workspace::{StatusItemView, Workspace, item::ItemHandle};
|
use workspace::{StatusItemView, Workspace, item::ItemHandle};
|
||||||
|
|
||||||
|
@ -39,6 +40,13 @@ impl ActiveBufferLanguage {
|
||||||
|
|
||||||
impl Render for ActiveBufferLanguage {
|
impl Render for ActiveBufferLanguage {
|
||||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
if !EditorSettings::get_global(cx)
|
||||||
|
.status_bar
|
||||||
|
.active_language_button
|
||||||
|
{
|
||||||
|
return div();
|
||||||
|
}
|
||||||
|
|
||||||
div().when_some(self.active_language.as_ref(), |el, active_language| {
|
div().when_some(self.active_language.as_ref(), |el, active_language| {
|
||||||
let active_language_text = if let Some(active_language_text) = active_language {
|
let active_language_text = if let Some(active_language_text) = active_language {
|
||||||
active_language_text.to_string()
|
active_language_text.to_string()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name = "C++"
|
name = "C++"
|
||||||
grammar = "cpp"
|
grammar = "cpp"
|
||||||
path_suffixes = ["cc", "hh", "cpp", "h", "hpp", "cxx", "hxx", "c++", "ipp", "inl", "ixx", "cu", "cuh", "C", "H"]
|
path_suffixes = ["cc", "hh", "cpp", "h", "hpp", "cxx", "hxx", "c++", "ipp", "inl", "ino", "ixx", "cu", "cuh", "C", "H"]
|
||||||
line_comments = ["// ", "/// ", "//! "]
|
line_comments = ["// ", "/// ", "//! "]
|
||||||
decrease_indent_patterns = [
|
decrease_indent_patterns = [
|
||||||
{ pattern = "^\\s*\\{.*\\}?\\s*$", valid_after = ["if", "for", "while", "do", "switch", "else"] },
|
{ pattern = "^\\s*\\{.*\\}?\\s*$", valid_after = ["if", "for", "while", "do", "switch", "else"] },
|
||||||
|
|
|
@ -146,6 +146,7 @@
|
||||||
"&&="
|
"&&="
|
||||||
"||="
|
"||="
|
||||||
"??="
|
"??="
|
||||||
|
"..."
|
||||||
] @operator
|
] @operator
|
||||||
|
|
||||||
(regex "/" @string.regex)
|
(regex "/" @string.regex)
|
||||||
|
|
|
@ -146,6 +146,7 @@
|
||||||
"&&="
|
"&&="
|
||||||
"||="
|
"||="
|
||||||
"??="
|
"??="
|
||||||
|
"..."
|
||||||
] @operator
|
] @operator
|
||||||
|
|
||||||
(regex "/" @string.regex)
|
(regex "/" @string.regex)
|
||||||
|
|
|
@ -167,6 +167,7 @@
|
||||||
"&&="
|
"&&="
|
||||||
"||="
|
"||="
|
||||||
"??="
|
"??="
|
||||||
|
"..."
|
||||||
] @operator
|
] @operator
|
||||||
|
|
||||||
(regex "/" @string.regex)
|
(regex "/" @string.regex)
|
||||||
|
|
|
@ -431,10 +431,9 @@ impl GitSettings {
|
||||||
|
|
||||||
pub fn inline_blame_delay(&self) -> Option<Duration> {
|
pub fn inline_blame_delay(&self) -> Option<Duration> {
|
||||||
match self.inline_blame {
|
match self.inline_blame {
|
||||||
Some(InlineBlameSettings {
|
Some(InlineBlameSettings { delay_ms, .. }) if delay_ms > 0 => {
|
||||||
delay_ms: Some(delay_ms),
|
Some(Duration::from_millis(delay_ms))
|
||||||
..
|
}
|
||||||
}) if delay_ms > 0 => Some(Duration::from_millis(delay_ms)),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -470,7 +469,7 @@ pub enum GitGutterSetting {
|
||||||
Hide,
|
Hide,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct InlineBlameSettings {
|
pub struct InlineBlameSettings {
|
||||||
/// Whether or not to show git blame data inline in
|
/// Whether or not to show git blame data inline in
|
||||||
|
@ -483,11 +482,19 @@ pub struct InlineBlameSettings {
|
||||||
/// after a delay once the cursor stops moving.
|
/// after a delay once the cursor stops moving.
|
||||||
///
|
///
|
||||||
/// Default: 0
|
/// Default: 0
|
||||||
pub delay_ms: Option<u64>,
|
#[serde(default)]
|
||||||
|
pub delay_ms: u64,
|
||||||
|
/// The amount of padding between the end of the source line and the start
|
||||||
|
/// of the inline blame in units of columns.
|
||||||
|
///
|
||||||
|
/// Default: 7
|
||||||
|
#[serde(default = "default_inline_blame_padding")]
|
||||||
|
pub padding: u32,
|
||||||
/// The minimum column number to show the inline blame information at
|
/// The minimum column number to show the inline blame information at
|
||||||
///
|
///
|
||||||
/// Default: 0
|
/// Default: 0
|
||||||
pub min_column: Option<u32>,
|
#[serde(default)]
|
||||||
|
pub min_column: u32,
|
||||||
/// Whether to show commit summary as part of the inline blame.
|
/// Whether to show commit summary as part of the inline blame.
|
||||||
///
|
///
|
||||||
/// Default: false
|
/// Default: false
|
||||||
|
@ -495,6 +502,22 @@ pub struct InlineBlameSettings {
|
||||||
pub show_commit_summary: bool,
|
pub show_commit_summary: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_inline_blame_padding() -> u32 {
|
||||||
|
7
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for InlineBlameSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
enabled: true,
|
||||||
|
delay_ms: 0,
|
||||||
|
padding: default_inline_blame_padding(),
|
||||||
|
min_column: 0,
|
||||||
|
show_commit_summary: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
pub struct BinarySettings {
|
pub struct BinarySettings {
|
||||||
pub path: Option<String>,
|
pub path: Option<String>,
|
||||||
|
|
|
@ -5625,6 +5625,10 @@ impl Panel for ProjectPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn starts_open(&self, _: &Window, cx: &App) -> bool {
|
fn starts_open(&self, _: &Window, cx: &App) -> bool {
|
||||||
|
if !ProjectPanelSettings::get_global(cx).starts_open {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let project = &self.project.read(cx);
|
let project = &self.project.read(cx);
|
||||||
project.visible_worktrees(cx).any(|tree| {
|
project.visible_worktrees(cx).any(|tree| {
|
||||||
tree.read(cx)
|
tree.read(cx)
|
||||||
|
|
|
@ -43,6 +43,7 @@ pub struct ProjectPanelSettings {
|
||||||
pub sticky_scroll: bool,
|
pub sticky_scroll: bool,
|
||||||
pub auto_reveal_entries: bool,
|
pub auto_reveal_entries: bool,
|
||||||
pub auto_fold_dirs: bool,
|
pub auto_fold_dirs: bool,
|
||||||
|
pub starts_open: bool,
|
||||||
pub scrollbar: ScrollbarSettings,
|
pub scrollbar: ScrollbarSettings,
|
||||||
pub show_diagnostics: ShowDiagnostics,
|
pub show_diagnostics: ShowDiagnostics,
|
||||||
pub hide_root: bool,
|
pub hide_root: bool,
|
||||||
|
@ -139,6 +140,10 @@ pub struct ProjectPanelSettingsContent {
|
||||||
///
|
///
|
||||||
/// Default: true
|
/// Default: true
|
||||||
pub auto_fold_dirs: Option<bool>,
|
pub auto_fold_dirs: Option<bool>,
|
||||||
|
/// Whether the project panel should open on startup.
|
||||||
|
///
|
||||||
|
/// Default: true
|
||||||
|
pub starts_open: Option<bool>,
|
||||||
/// Scrollbar-related settings
|
/// Scrollbar-related settings
|
||||||
pub scrollbar: Option<ScrollbarSettingsContent>,
|
pub scrollbar: Option<ScrollbarSettingsContent>,
|
||||||
/// Which files containing diagnostic errors/warnings to mark in the project panel.
|
/// Which files containing diagnostic errors/warnings to mark in the project panel.
|
||||||
|
|
|
@ -136,7 +136,7 @@ impl BatchedTextRun {
|
||||||
.shape_line(
|
.shape_line(
|
||||||
self.text.clone().into(),
|
self.text.clone().into(),
|
||||||
self.font_size.to_pixels(window.rem_size()),
|
self.font_size.to_pixels(window.rem_size()),
|
||||||
std::slice::from_ref(&self.style),
|
&[self.style.clone()],
|
||||||
Some(dimensions.cell_width),
|
Some(dimensions.cell_width),
|
||||||
)
|
)
|
||||||
.paint(pos, dimensions.line_height, window, cx);
|
.paint(pos, dimensions.line_height, window, cx);
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 146 KiB |
|
@ -1275,6 +1275,18 @@ Each option controls displaying of a particular toolbar element. If all elements
|
||||||
|
|
||||||
`boolean` values
|
`boolean` values
|
||||||
|
|
||||||
|
## Status Bar
|
||||||
|
|
||||||
|
- Description: Control various elements in the status bar. Note that some items in the status bar have their own settings set elsewhere.
|
||||||
|
- Setting: `status_bar`
|
||||||
|
- Default:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"status_bar": {
|
||||||
|
"active_language_button": true,
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
## LSP
|
## LSP
|
||||||
|
|
||||||
- Description: Configuration for language servers.
|
- Description: Configuration for language servers.
|
||||||
|
@ -1795,7 +1807,6 @@ Example:
|
||||||
{
|
{
|
||||||
"git": {
|
"git": {
|
||||||
"inline_blame": {
|
"inline_blame": {
|
||||||
"enabled": true,
|
|
||||||
"delay_ms": 500
|
"delay_ms": 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1808,7 +1819,6 @@ Example:
|
||||||
{
|
{
|
||||||
"git": {
|
"git": {
|
||||||
"inline_blame": {
|
"inline_blame": {
|
||||||
"enabled": true,
|
|
||||||
"show_commit_summary": true
|
"show_commit_summary": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1821,13 +1831,24 @@ Example:
|
||||||
{
|
{
|
||||||
"git": {
|
"git": {
|
||||||
"inline_blame": {
|
"inline_blame": {
|
||||||
"enabled": true,
|
|
||||||
"min_column": 80
|
"min_column": 80
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
5. Set the padding between the end of the line and the inline blame hint, in ems:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"git": {
|
||||||
|
"inline_blame": {
|
||||||
|
"padding": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Hunk Style
|
### Hunk Style
|
||||||
|
|
||||||
- Description: What styling we should use for the diff hunks.
|
- Description: What styling we should use for the diff hunks.
|
||||||
|
@ -3204,7 +3225,8 @@ Run the `theme selector: toggle` action in the command palette to see a current
|
||||||
"indent_guides": {
|
"indent_guides": {
|
||||||
"show": "always"
|
"show": "always"
|
||||||
},
|
},
|
||||||
"hide_root": false
|
"hide_root": false,
|
||||||
|
"starts_open": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -223,6 +223,7 @@ TBD: Centered layout related settings
|
||||||
"enabled": true, // Show/hide inline blame
|
"enabled": true, // Show/hide inline blame
|
||||||
"delay": 0, // Show after delay (ms)
|
"delay": 0, // Show after delay (ms)
|
||||||
"min_column": 0, // Minimum column to inline display blame
|
"min_column": 0, // Minimum column to inline display blame
|
||||||
|
"padding": 7, // Padding between code and inline blame (em)
|
||||||
"show_commit_summary": false // Show/hide commit summary
|
"show_commit_summary": false // Show/hide commit summary
|
||||||
},
|
},
|
||||||
"hunk_style": "staged_hollow" // staged_hollow, unstaged_hollow
|
"hunk_style": "staged_hollow" // staged_hollow, unstaged_hollow
|
||||||
|
@ -305,6 +306,17 @@ TBD: Centered layout related settings
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Status Bar
|
||||||
|
|
||||||
|
```json
|
||||||
|
"status_bar": {
|
||||||
|
// Show/hide a button that displays the active buffer's language.
|
||||||
|
// Clicking the button brings up the language selector.
|
||||||
|
// Defaults to true.
|
||||||
|
"active_language_button": true,
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
### Multibuffer
|
### Multibuffer
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|
|
@ -9,7 +9,7 @@ repository = "https://github.com/zed-industries/zed"
|
||||||
[language_servers.emmet-language-server]
|
[language_servers.emmet-language-server]
|
||||||
name = "Emmet Language Server"
|
name = "Emmet Language Server"
|
||||||
language = "HTML"
|
language = "HTML"
|
||||||
languages = ["HTML", "PHP", "ERB", "HTML/ERB", "JavaScript", "TSX", "CSS", "HEEX", "Elixir"]
|
languages = ["HTML", "PHP", "ERB", "HTML/ERB", "JavaScript", "TSX", "CSS", "HEEX", "Elixir", "Vue.js"]
|
||||||
|
|
||||||
[language_servers.emmet-language-server.language_ids]
|
[language_servers.emmet-language-server.language_ids]
|
||||||
"HTML" = "html"
|
"HTML" = "html"
|
||||||
|
@ -21,3 +21,4 @@ languages = ["HTML", "PHP", "ERB", "HTML/ERB", "JavaScript", "TSX", "CSS", "HEEX
|
||||||
"CSS" = "css"
|
"CSS" = "css"
|
||||||
"HEEX" = "heex"
|
"HEEX" = "heex"
|
||||||
"Elixir" = "heex"
|
"Elixir" = "heex"
|
||||||
|
"Vue.js" = "vue"
|
||||||
|
|
18
flake.lock
generated
18
flake.lock
generated
|
@ -2,11 +2,11 @@
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"crane": {
|
"crane": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1754269165,
|
"lastModified": 1750266157,
|
||||||
"narHash": "sha256-0tcS8FHd4QjbCVoxN9jI+PjHgA4vc/IjkUSp+N3zy0U=",
|
"narHash": "sha256-tL42YoNg9y30u7zAqtoGDNdTyXTi8EALDeCB13FtbQA=",
|
||||||
"owner": "ipetkov",
|
"owner": "ipetkov",
|
||||||
"repo": "crane",
|
"repo": "crane",
|
||||||
"rev": "444e81206df3f7d92780680e45858e31d2f07a08",
|
"rev": "e37c943371b73ed87faf33f7583860f81f1d5a48",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -33,10 +33,10 @@
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 315532800,
|
"lastModified": 315532800,
|
||||||
"narHash": "sha256-5VYevX3GccubYeccRGAXvCPA1ktrGmIX1IFC0icX07g=",
|
"narHash": "sha256-j+zO+IHQ7VwEam0pjPExdbLT2rVioyVS3iq4bLO3GEc=",
|
||||||
"rev": "a683adc19ff5228af548c6539dbc3440509bfed3",
|
"rev": "61c0f513911459945e2cb8bf333dc849f1b976ff",
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.11pre840248.a683adc19ff5/nixexprs.tar.xz"
|
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.11pre821324.61c0f5139114/nixexprs.tar.xz"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
|
@ -58,11 +58,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1754575663,
|
"lastModified": 1750964660,
|
||||||
"narHash": "sha256-afOx8AG0KYtw7mlt6s6ahBBy7eEHZwws3iCRoiuRQS4=",
|
"narHash": "sha256-YQ6EyFetjH1uy5JhdhRdPe6cuNXlYpMAQePFfZj4W7M=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "6db0fb0e9cec2e9729dc52bf4898e6c135bb8a0f",
|
"rev": "04f0fcfb1a50c63529805a798b4b5c21610ff390",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.89"
|
channel = "1.88"
|
||||||
profile = "minimal"
|
profile = "minimal"
|
||||||
components = [ "rustfmt", "clippy" ]
|
components = [ "rustfmt", "clippy" ]
|
||||||
targets = [
|
targets = [
|
||||||
|
|
|
@ -9,7 +9,12 @@ main() {
|
||||||
platform="$(uname -s)"
|
platform="$(uname -s)"
|
||||||
arch="$(uname -m)"
|
arch="$(uname -m)"
|
||||||
channel="${ZED_CHANNEL:-stable}"
|
channel="${ZED_CHANNEL:-stable}"
|
||||||
temp="$(mktemp -d "/tmp/zed-XXXXXX")"
|
# Use TMPDIR if available (for environments with non-standard temp directories)
|
||||||
|
if [ -n "${TMPDIR:-}" ] && [ -d "${TMPDIR}" ]; then
|
||||||
|
temp="$(mktemp -d "$TMPDIR/zed-XXXXXX")"
|
||||||
|
else
|
||||||
|
temp="$(mktemp -d "/tmp/zed-XXXXXX")"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$platform" = "Darwin" ]; then
|
if [ "$platform" = "Darwin" ]; then
|
||||||
platform="macos"
|
platform="macos"
|
||||||
|
|
|
@ -5,7 +5,7 @@ function export_vars_for_environment {
|
||||||
echo "Invalid environment name '${environment}'" >&2
|
echo "Invalid environment name '${environment}'" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
export $(cat $env_file)
|
export $(grep -v '^#' $env_file | grep -v '^[[:space:]]*$')
|
||||||
}
|
}
|
||||||
|
|
||||||
function target_zed_kube_cluster {
|
function target_zed_kube_cluster {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue