merged with main
This commit is contained in:
commit
c141519dba
9 changed files with 172 additions and 71 deletions
29
Cargo.lock
generated
29
Cargo.lock
generated
|
@ -992,7 +992,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05"
|
checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata 0.3.2",
|
"regex-automata 0.3.3",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1976,7 +1976,6 @@ checksum = "aeb0fef7046022a1e2ad67a004978f0e3cacb9e3123dc62ce768f92197b771dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
"libnghttp2-sys",
|
|
||||||
"libz-sys",
|
"libz-sys",
|
||||||
"openssl-sys",
|
"openssl-sys",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
|
@ -2942,11 +2941,11 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "globset"
|
name = "globset"
|
||||||
version = "0.4.10"
|
version = "0.4.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc"
|
checksum = "1391ab1f92ffcc08911957149833e682aa3fe252b9f45f966d2ef972274c97df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick 0.7.20",
|
"aho-corasick 1.0.2",
|
||||||
"bstr",
|
"bstr",
|
||||||
"fnv",
|
"fnv",
|
||||||
"log",
|
"log",
|
||||||
|
@ -3881,16 +3880,6 @@ version = "0.2.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
|
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]]
|
[[package]]
|
||||||
name = "libsqlite3-sys"
|
name = "libsqlite3-sys"
|
||||||
version = "0.24.2"
|
version = "0.24.2"
|
||||||
|
@ -5733,7 +5722,7 @@ checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick 1.0.2",
|
"aho-corasick 1.0.2",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata 0.3.2",
|
"regex-automata 0.3.3",
|
||||||
"regex-syntax 0.7.4",
|
"regex-syntax 0.7.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -5748,9 +5737,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-automata"
|
name = "regex-automata"
|
||||||
version = "0.3.2"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf"
|
checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick 1.0.2",
|
"aho-corasick 1.0.2",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
@ -6542,9 +6531,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.100"
|
version = "1.0.102"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c"
|
checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.0.0",
|
"indexmap 2.0.0",
|
||||||
"itoa 1.0.8",
|
"itoa 1.0.8",
|
||||||
|
|
|
@ -83,7 +83,8 @@ env_logger = { version = "0.9" }
|
||||||
futures = { version = "0.3" }
|
futures = { version = "0.3" }
|
||||||
globset = { version = "0.4" }
|
globset = { version = "0.4" }
|
||||||
indoc = "1"
|
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" }
|
lazy_static = { version = "1.4.0" }
|
||||||
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
|
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
|
||||||
ordered-float = { version = "2.1.1" }
|
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
|
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
|
git submodule update --init --recursive
|
||||||
```
|
```
|
||||||
|
|
||||||
* Set up a local `zed` database and seed it with some initial users:
|
* 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.
|
Then delete that token.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -39,6 +39,9 @@ pub trait GitRepository: Send {
|
||||||
fn change_branch(&self, _: &str) -> Result<()> {
|
fn change_branch(&self, _: &str) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
fn create_branch(&self, _: &str) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for dyn GitRepository {
|
impl std::fmt::Debug for dyn GitRepository {
|
||||||
|
@ -152,6 +155,12 @@ impl GitRepository for LibGitRepository {
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
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> {
|
fn read_status(status: git2::Status) -> Option<GitFileStatus> {
|
||||||
|
|
|
@ -134,7 +134,7 @@ impl PickerDelegate for RecentProjectsDelegate {
|
||||||
let combined_string = location
|
let combined_string = location
|
||||||
.paths()
|
.paths()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|path| path.to_string_lossy().to_owned())
|
.map(|path| util::paths::compact(&path).to_string_lossy().into_owned())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("");
|
.join("");
|
||||||
StringMatchCandidate::new(id, combined_string)
|
StringMatchCandidate::new(id, combined_string)
|
||||||
|
|
|
@ -586,7 +586,7 @@ pub struct Picker {
|
||||||
pub no_matches: ContainedLabel,
|
pub no_matches: ContainedLabel,
|
||||||
pub item: Toggleable<Interactive<ContainedLabel>>,
|
pub item: Toggleable<Interactive<ContainedLabel>>,
|
||||||
pub header: ContainedLabel,
|
pub header: ContainedLabel,
|
||||||
pub footer: ContainedLabel,
|
pub footer: Interactive<ContainedLabel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
|
#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{anyhow, bail, Result};
|
||||||
use fuzzy::{StringMatch, StringMatchCandidate};
|
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 picker::{Picker, PickerDelegate, PickerEvent};
|
||||||
use std::{ops::Not, sync::Arc};
|
use std::{ops::Not, sync::Arc};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
@ -24,6 +29,7 @@ pub fn build_branch_list(
|
||||||
workspace,
|
workspace,
|
||||||
selected_index: 0,
|
selected_index: 0,
|
||||||
last_query: String::default(),
|
last_query: String::default(),
|
||||||
|
branch_name_trailoff_after: 29,
|
||||||
},
|
},
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -46,6 +52,8 @@ fn toggle(
|
||||||
workspace,
|
workspace,
|
||||||
selected_index: 0,
|
selected_index: 0,
|
||||||
last_query: String::default(),
|
last_query: String::default(),
|
||||||
|
/// Modal branch picker has a longer trailoff than a popover one.
|
||||||
|
branch_name_trailoff_after: 70,
|
||||||
},
|
},
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -63,8 +71,18 @@ pub struct BranchListDelegate {
|
||||||
workspace: ViewHandle<Workspace>,
|
workspace: ViewHandle<Workspace>,
|
||||||
selected_index: usize,
|
selected_index: usize,
|
||||||
last_query: String,
|
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 {
|
impl PickerDelegate for BranchListDelegate {
|
||||||
fn placeholder_text(&self) -> Arc<str> {
|
fn placeholder_text(&self) -> Arc<str> {
|
||||||
"Select branch...".into()
|
"Select branch...".into()
|
||||||
|
@ -166,40 +184,39 @@ impl PickerDelegate for BranchListDelegate {
|
||||||
let current_pick = self.selected_index();
|
let current_pick = self.selected_index();
|
||||||
let current_pick = self.matches[current_pick].string.clone();
|
let current_pick = self.matches[current_pick].string.clone();
|
||||||
cx.spawn(|picker, mut cx| async move {
|
cx.spawn(|picker, mut cx| async move {
|
||||||
picker.update(&mut cx, |this, cx| {
|
picker
|
||||||
let project = this.delegate().workspace.read(cx).project().read(cx);
|
.update(&mut cx, |this, cx| {
|
||||||
let mut cwd = project
|
let project = this.delegate().workspace.read(cx).project().read(cx);
|
||||||
.visible_worktrees(cx)
|
let mut cwd = project
|
||||||
.next()
|
.visible_worktrees(cx)
|
||||||
.ok_or_else(|| anyhow!("There are no visisible worktrees."))?
|
.next()
|
||||||
.read(cx)
|
.ok_or_else(|| anyhow!("There are no visisible worktrees."))?
|
||||||
.abs_path()
|
.read(cx)
|
||||||
.to_path_buf();
|
.abs_path()
|
||||||
cwd.push(".git");
|
.to_path_buf();
|
||||||
let status = project
|
cwd.push(".git");
|
||||||
.fs()
|
let status = project
|
||||||
.open_repo(&cwd)
|
.fs()
|
||||||
.ok_or_else(|| anyhow!("Could not open repository at path `{}`", cwd.as_os_str().to_string_lossy()))?
|
.open_repo(&cwd)
|
||||||
.lock()
|
.ok_or_else(|| {
|
||||||
.change_branch(¤t_pick);
|
anyhow!(
|
||||||
if status.is_err() {
|
"Could not open repository at path `{}`",
|
||||||
const GIT_CHECKOUT_FAILURE_ID: usize = 2048;
|
cwd.as_os_str().to_string_lossy()
|
||||||
this.delegate().workspace.update(cx, |model, ctx| {
|
)
|
||||||
model.show_toast(
|
})?
|
||||||
Toast::new(
|
.lock()
|
||||||
GIT_CHECKOUT_FAILURE_ID,
|
.change_branch(¤t_pick);
|
||||||
format!("Failed to checkout branch '{current_pick}', check for conflicts or unstashed files"),
|
if status.is_err() {
|
||||||
),
|
this.delegate().display_error_toast(format!("Failed to checkout branch '{current_pick}', check for conflicts or unstashed files"), cx);
|
||||||
ctx,
|
status?;
|
||||||
)
|
}
|
||||||
});
|
cx.emit(PickerEvent::Dismiss);
|
||||||
status?;
|
|
||||||
}
|
|
||||||
cx.emit(PickerEvent::Dismiss);
|
|
||||||
|
|
||||||
Ok::<(), anyhow::Error>(())
|
Ok::<(), anyhow::Error>(())
|
||||||
}).log_err();
|
})
|
||||||
}).detach();
|
.log_err();
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) {
|
fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) {
|
||||||
|
@ -213,15 +230,15 @@ impl PickerDelegate for BranchListDelegate {
|
||||||
selected: bool,
|
selected: bool,
|
||||||
cx: &gpui::AppContext,
|
cx: &gpui::AppContext,
|
||||||
) -> AnyElement<Picker<Self>> {
|
) -> AnyElement<Picker<Self>> {
|
||||||
const DISPLAYED_MATCH_LEN: usize = 29;
|
|
||||||
let theme = &theme::current(cx);
|
let theme = &theme::current(cx);
|
||||||
let hit = &self.matches[ix];
|
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
|
let highlights = hit
|
||||||
.positions
|
.positions
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
.filter(|index| index < &DISPLAYED_MATCH_LEN)
|
.filter(|index| index < &self.branch_name_trailoff_after)
|
||||||
.collect();
|
.collect();
|
||||||
let style = theme.picker.item.in_state(selected).style_for(mouse_state);
|
let style = theme.picker.item.in_state(selected).style_for(mouse_state);
|
||||||
Flex::row()
|
Flex::row()
|
||||||
|
@ -265,4 +282,61 @@ impl PickerDelegate for BranchListDelegate {
|
||||||
};
|
};
|
||||||
Some(label.into_any())
|
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,
|
right: 8,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
footer: {
|
footer: interactive({
|
||||||
text: text(theme.lowest, "sans", "variant", { size: "xs" }),
|
base: {
|
||||||
margin: {
|
text: text(theme.lowest, "sans", "base", { size: "xs" }),
|
||||||
top: 1,
|
padding: {
|
||||||
left: 8,
|
bottom: 4,
|
||||||
right: 8,
|
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: {
|
base: {
|
||||||
corner_radius: 6,
|
corner_radius: 6,
|
||||||
height: button_height,
|
height: button_height,
|
||||||
width: online ? 37 : 24,
|
width: 20,
|
||||||
padding: {
|
padding: {
|
||||||
top: 2,
|
top: 2,
|
||||||
bottom: 2,
|
bottom: 2,
|
||||||
|
@ -153,6 +153,7 @@ function user_menu() {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user_menu_button_online: build_button({ online: true }),
|
user_menu_button_online: build_button({ online: true }),
|
||||||
user_menu_button_offline: build_button({ online: false }),
|
user_menu_button_offline: build_button({ online: false }),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue