Detailed changes
@@ -992,7 +992,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05"
dependencies = [
"memchr",
- "regex-automata 0.3.2",
+ "regex-automata 0.3.3",
"serde",
]
@@ -1976,7 +1976,6 @@ checksum = "aeb0fef7046022a1e2ad67a004978f0e3cacb9e3123dc62ce768f92197b771dc"
dependencies = [
"cc",
"libc",
- "libnghttp2-sys",
"libz-sys",
"openssl-sys",
"pkg-config",
@@ -2942,11 +2941,11 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "globset"
-version = "0.4.10"
+version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc"
+checksum = "1391ab1f92ffcc08911957149833e682aa3fe252b9f45f966d2ef972274c97df"
dependencies = [
- "aho-corasick 0.7.20",
+ "aho-corasick 1.0.2",
"bstr",
"fnv",
"log",
@@ -3881,16 +3880,6 @@ version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
-[[package]]
-name = "libnghttp2-sys"
-version = "0.1.7+1.45.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57ed28aba195b38d5ff02b9170cbff627e336a20925e43b4945390401c5dc93f"
-dependencies = [
- "cc",
- "libc",
-]
-
[[package]]
name = "libsqlite3-sys"
version = "0.24.2"
@@ -5733,7 +5722,7 @@ checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575"
dependencies = [
"aho-corasick 1.0.2",
"memchr",
- "regex-automata 0.3.2",
+ "regex-automata 0.3.3",
"regex-syntax 0.7.4",
]
@@ -5748,9 +5737,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.3.2"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf"
+checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310"
dependencies = [
"aho-corasick 1.0.2",
"memchr",
@@ -6542,9 +6531,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.100"
+version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c"
+checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed"
dependencies = [
"indexmap 2.0.0",
"itoa 1.0.8",
@@ -83,7 +83,8 @@ env_logger = { version = "0.9" }
futures = { version = "0.3" }
globset = { version = "0.4" }
indoc = "1"
-isahc = "1.7.2"
+# We explicitly disable a http2 support in isahc.
+isahc = { version = "1.7.2", default-features = false, features = ["static-curl", "text-decoding"] }
lazy_static = { version = "1.4.0" }
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
ordered-float = { version = "2.1.1" }
@@ -23,15 +23,16 @@ Welcome to Zed, a lightning-fast, collaborative code editor that makes your drea
git clone https://github.com/zed-industries/zed.dev
```
-* Initialize submodules
+* Return to Zed project directory and Initialize submodules
```
+ cd zed
git submodule update --init --recursive
```
* Set up a local `zed` database and seed it with some initial users:
- Create a personal GitHub token to run `script/bootstrap` once successfully: the token needs to have an access to private repositories for the script to work (`repo` OAuth scope).
+ [Create a personal GitHub token](https://github.com/settings/tokens/new) to run `script/bootstrap` once successfully: the token needs to have an access to private repositories for the script to work (`repo` OAuth scope).
Then delete that token.
```
@@ -39,6 +39,9 @@ pub trait GitRepository: Send {
fn change_branch(&self, _: &str) -> Result<()> {
Ok(())
}
+ fn create_branch(&self, _: &str) -> Result<()> {
+ Ok(())
+ }
}
impl std::fmt::Debug for dyn GitRepository {
@@ -152,6 +155,12 @@ impl GitRepository for LibGitRepository {
)?;
Ok(())
}
+ fn create_branch(&self, name: &str) -> Result<()> {
+ let current_commit = self.head()?.peel_to_commit()?;
+ self.branch(name, ¤t_commit, false)?;
+
+ Ok(())
+ }
}
fn read_status(status: git2::Status) -> Option<GitFileStatus> {
@@ -134,7 +134,7 @@ impl PickerDelegate for RecentProjectsDelegate {
let combined_string = location
.paths()
.iter()
- .map(|path| path.to_string_lossy().to_owned())
+ .map(|path| util::paths::compact(&path).to_string_lossy().into_owned())
.collect::<Vec<_>>()
.join("");
StringMatchCandidate::new(id, combined_string)
@@ -586,7 +586,7 @@ pub struct Picker {
pub no_matches: ContainedLabel,
pub item: Toggleable<Interactive<ContainedLabel>>,
pub header: ContainedLabel,
- pub footer: ContainedLabel,
+ pub footer: Interactive<ContainedLabel>,
}
#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
@@ -1,6 +1,11 @@
use anyhow::{anyhow, bail, Result};
use fuzzy::{StringMatch, StringMatchCandidate};
-use gpui::{actions, elements::*, AppContext, MouseState, Task, ViewContext, ViewHandle};
+use gpui::{
+ actions,
+ elements::*,
+ platform::{CursorStyle, MouseButton},
+ AppContext, MouseState, Task, ViewContext, ViewHandle,
+};
use picker::{Picker, PickerDelegate, PickerEvent};
use std::{ops::Not, sync::Arc};
use util::ResultExt;
@@ -24,6 +29,7 @@ pub fn build_branch_list(
workspace,
selected_index: 0,
last_query: String::default(),
+ branch_name_trailoff_after: 29,
},
cx,
)
@@ -46,6 +52,8 @@ fn toggle(
workspace,
selected_index: 0,
last_query: String::default(),
+ /// Modal branch picker has a longer trailoff than a popover one.
+ branch_name_trailoff_after: 70,
},
cx,
)
@@ -63,8 +71,18 @@ pub struct BranchListDelegate {
workspace: ViewHandle<Workspace>,
selected_index: usize,
last_query: String,
+ /// Max length of branch name before we truncate it and add a trailing `...`.
+ branch_name_trailoff_after: usize,
}
+impl BranchListDelegate {
+ fn display_error_toast(&self, message: String, cx: &mut ViewContext<BranchList>) {
+ const GIT_CHECKOUT_FAILURE_ID: usize = 2048;
+ self.workspace.update(cx, |model, ctx| {
+ model.show_toast(Toast::new(GIT_CHECKOUT_FAILURE_ID, message), ctx)
+ });
+ }
+}
impl PickerDelegate for BranchListDelegate {
fn placeholder_text(&self) -> Arc<str> {
"Select branch...".into()
@@ -166,40 +184,39 @@ impl PickerDelegate for BranchListDelegate {
let current_pick = self.selected_index();
let current_pick = self.matches[current_pick].string.clone();
cx.spawn(|picker, mut cx| async move {
- picker.update(&mut cx, |this, cx| {
- let project = this.delegate().workspace.read(cx).project().read(cx);
- let mut cwd = project
- .visible_worktrees(cx)
- .next()
- .ok_or_else(|| anyhow!("There are no visisible worktrees."))?
- .read(cx)
- .abs_path()
- .to_path_buf();
- cwd.push(".git");
- let status = project
- .fs()
- .open_repo(&cwd)
- .ok_or_else(|| anyhow!("Could not open repository at path `{}`", cwd.as_os_str().to_string_lossy()))?
- .lock()
- .change_branch(¤t_pick);
- if status.is_err() {
- const GIT_CHECKOUT_FAILURE_ID: usize = 2048;
- this.delegate().workspace.update(cx, |model, ctx| {
- model.show_toast(
- Toast::new(
- GIT_CHECKOUT_FAILURE_ID,
- format!("Failed to checkout branch '{current_pick}', check for conflicts or unstashed files"),
- ),
- ctx,
- )
- });
- status?;
- }
- cx.emit(PickerEvent::Dismiss);
+ picker
+ .update(&mut cx, |this, cx| {
+ let project = this.delegate().workspace.read(cx).project().read(cx);
+ let mut cwd = project
+ .visible_worktrees(cx)
+ .next()
+ .ok_or_else(|| anyhow!("There are no visisible worktrees."))?
+ .read(cx)
+ .abs_path()
+ .to_path_buf();
+ cwd.push(".git");
+ let status = project
+ .fs()
+ .open_repo(&cwd)
+ .ok_or_else(|| {
+ anyhow!(
+ "Could not open repository at path `{}`",
+ cwd.as_os_str().to_string_lossy()
+ )
+ })?
+ .lock()
+ .change_branch(¤t_pick);
+ if status.is_err() {
+ this.delegate().display_error_toast(format!("Failed to checkout branch '{current_pick}', check for conflicts or unstashed files"), cx);
+ status?;
+ }
+ cx.emit(PickerEvent::Dismiss);
- Ok::<(), anyhow::Error>(())
- }).log_err();
- }).detach();
+ Ok::<(), anyhow::Error>(())
+ })
+ .log_err();
+ })
+ .detach();
}
fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) {
@@ -213,15 +230,15 @@ impl PickerDelegate for BranchListDelegate {
selected: bool,
cx: &gpui::AppContext,
) -> AnyElement<Picker<Self>> {
- const DISPLAYED_MATCH_LEN: usize = 29;
let theme = &theme::current(cx);
let hit = &self.matches[ix];
- let shortened_branch_name = util::truncate_and_trailoff(&hit.string, DISPLAYED_MATCH_LEN);
+ let shortened_branch_name =
+ util::truncate_and_trailoff(&hit.string, self.branch_name_trailoff_after);
let highlights = hit
.positions
.iter()
.copied()
- .filter(|index| index < &DISPLAYED_MATCH_LEN)
+ .filter(|index| index < &self.branch_name_trailoff_after)
.collect();
let style = theme.picker.item.in_state(selected).style_for(mouse_state);
Flex::row()
@@ -265,4 +282,61 @@ impl PickerDelegate for BranchListDelegate {
};
Some(label.into_any())
}
+ fn render_footer(
+ &self,
+ cx: &mut ViewContext<Picker<Self>>,
+ ) -> Option<AnyElement<Picker<Self>>> {
+ if !self.last_query.is_empty() {
+ let theme = &theme::current(cx);
+ let style = theme.picker.footer.clone();
+ enum BranchCreateButton {}
+ Some(
+ Flex::row().with_child(MouseEventHandler::<BranchCreateButton, _>::new(0, cx, |state, _| {
+ let style = style.style_for(state);
+ Label::new("Create branch", style.label.clone())
+ .contained()
+ .with_style(style.container)
+ })
+ .with_cursor_style(CursorStyle::PointingHand)
+ .on_down(MouseButton::Left, |_, _, cx| {
+ cx.spawn(|picker, mut cx| async move {
+ picker.update(&mut cx, |this, cx| {
+ let project = this.delegate().workspace.read(cx).project().read(cx);
+ let current_pick = &this.delegate().last_query;
+ let mut cwd = project
+ .visible_worktrees(cx)
+ .next()
+ .ok_or_else(|| anyhow!("There are no visisible worktrees."))?
+ .read(cx)
+ .abs_path()
+ .to_path_buf();
+ cwd.push(".git");
+ let repo = project
+ .fs()
+ .open_repo(&cwd)
+ .ok_or_else(|| anyhow!("Could not open repository at path `{}`", cwd.as_os_str().to_string_lossy()))?;
+ let repo = repo
+ .lock();
+ let status = repo
+ .create_branch(¤t_pick);
+ if status.is_err() {
+ this.delegate().display_error_toast(format!("Failed to create branch '{current_pick}', check for conflicts or unstashed files"), cx);
+ status?;
+ }
+ let status = repo.change_branch(¤t_pick);
+ if status.is_err() {
+ this.delegate().display_error_toast(format!("Failed to chec branch '{current_pick}', check for conflicts or unstashed files"), cx);
+ status?;
+ }
+ cx.emit(PickerEvent::Dismiss);
+ Ok::<(), anyhow::Error>(())
+ })
+ }).detach();
+ })).aligned().right()
+ .into_any(),
+ )
+ } else {
+ None
+ }
+ }
}
@@ -119,14 +119,40 @@ export default function picker(): any {
right: 8,
},
},
- footer: {
- text: text(theme.lowest, "sans", "variant", { size: "xs" }),
- margin: {
- top: 1,
- left: 8,
- right: 8,
+ footer: interactive({
+ base: {
+ text: text(theme.lowest, "sans", "base", { size: "xs" }),
+ padding: {
+ bottom: 4,
+ left: 12,
+ right: 12,
+ top: 4,
+ },
+ margin: {
+ top: 1,
+ left: 4,
+ right: 4,
+ },
+ corner_radius: 8,
+ background: with_opacity(
+ background(theme.lowest, "active"),
+ 0.5
+ ),
},
-
- }
+ state: {
+ hovered: {
+ background: with_opacity(
+ background(theme.lowest, "hovered"),
+ 0.5
+ ),
+ },
+ clicked: {
+ background: with_opacity(
+ background(theme.lowest, "pressed"),
+ 0.5
+ ),
+ },
+ }
+ }),
}
}
@@ -84,7 +84,7 @@ function user_menu() {
base: {
corner_radius: 6,
height: button_height,
- width: online ? 37 : 24,
+ width: 20,
padding: {
top: 2,
bottom: 2,
@@ -153,6 +153,7 @@ function user_menu() {
},
}
}
+
return {
user_menu_button_online: build_button({ online: true }),
user_menu_button_offline: build_button({ online: false }),