Compare commits

...

19 Commits

Author SHA1 Message Date
Peter Tripp
49db2122c6 zed 0.154.4 2024-10-01 10:22:04 -04:00
Peter Tripp
2bdb395267 Support More Linux (#18480)
- Add `script/build-docker`
- Add `script/install-cmake`
- Add `script/install-mold`
- Improve `script/linux` 
  - Add missing dependencies: `jq`, `git`, `tar`, `gzip` as required.
  - Add check for mold
  - Fix Redhat 8.x derivatives (RHEL, Centos, Almalinux, Rocky, Oracle, Amazon)
  - Fix perl libs to be Fedora only
  - Install the best `libstdc++` available on apt distros
  - ArchLinux: run `pacman -Syu` to update repos before installing. 
  - Should work on Raspbian (untested) 

This make it possible to test builds on other distros using docker:
```
./script/build-docker amazonlinux:2023
```
2024-10-01 10:21:26 -04:00
Peter Tripp
b34d42aed3 ci: Use BuildJet Ubuntu 20.04 runners for better glibc compatibility (#18442)
Use BuildJet Ubuntu 20.04 runners.
- Linux arm64 unchanged (glibc >= 2.35)
- Linux x64 glibc requirement becomes to >= 2.31 (from glibc >= 2.35).

Note: Ubuntu 20.04 repo cmake (3.16.3) is normally too old to build Zed, but `ubuntu-2004` [includes cmake
3.30.3](https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2004-Readme.md#tools).
2024-10-01 10:21:11 -04:00
Kirill Bulatov
e9a529bf34 zed 0.154.3 2024-09-27 23:04:41 +03:00
Kirill Bulatov
85a44705e7 Install cargo-edito without extra features (#18457)
https://github.com/killercup/cargo-edit/pull/907 removed the feature
from the crate

Release Notes:

- N/A
2024-09-27 22:42:57 +03:00
Conrad Irwin
8b57259669 Avoid unwrap in file finder (#18374)
Release Notes:

- Fixed a (rare) panic in file finder

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2024-09-27 10:37:42 +03:00
Peter Tripp
25e2e9c672 zed 0.154.2 2024-09-25 17:39:51 -04:00
Sebastijan Kelnerič
b2ee628360 Implement grapheme support for supermaven completions (#18279)
Closes [#18278](https://github.com/zed-industries/zed/issues/18278)

Release Notes:

- Fixed a panic when graphemes are included in supermaven completions
2024-09-25 17:39:02 -04:00
Thorsten Ball
3ea89a1f9c client: Remove unused fs dependency (#18324)
CI bot notified me about that in
https://github.com/zed-industries/zed/pull/18323


Release Notes:

- N/A
2024-09-25 13:04:25 -04:00
Joseph T Lyons
752f6a7c33 v0.154.x stable 2024-09-25 11:02:25 -04:00
Max Brunsfeld
1e2fcfb386 Fix unnecessarily-specific struct pattern in rust outline query (#18297)
Fixes https://github.com/zed-industries/zed/issues/18294

Release Notes:

- Fixed a recent regression where tuple and unit structs were omitted
from the outline view in Rust (#18294).
2024-09-24 12:19:53 -07:00
Thorsten Ball
3ef8491fcb zed 0.154.1 2024-09-24 15:12:29 +02:00
Thorsten Ball
ce3a6350e6 project search: Fix search results not being highlighted (#18273)
Closes #18254
Closes #18219
Closes #17690

This fixes the project search not highlighting all results.

The problem was relatively simple, even though it took a while to find
it: we inserted multiple excerpts concurrently and the order in the
multi-buffer ended up being wrong. Sorting the resulting `match_ranges`
fixed the problem, but as it turns out, we can do a better job by moving
the concurrency into the method on the MultiBuffer.

Performance is the same, but now the problem is fixed.

Release Notes:

- Fixed search results in project-wide search not being highlighted
consistently and navigation sometimes being broken (#18254, #18219,

---------

Co-authored-by: Bennet <bennet@zed.dev>
2024-09-24 15:07:20 +02:00
Joseph T. Lyons
15931d1b77 Bump release_notes to v2 endpoint (#18108)
Partially addresses https://github.com/zed-industries/zed/issues/17527

<img width="1608" alt="SCR-20240919-rcik"
src="https://github.com/user-attachments/assets/25057731-7da6-4b36-b51b-021c67e8736b">

Release Notes:

- Enhanced the `auto update: view release notes locally` feature to
display release notes for each patch version associated with the
installed minor version.
2024-09-24 09:02:19 -04:00
Joseph T. Lyons
2a5925c235 Fix bug where copying from assistant panel appends extra newline to clipboard (#18090)
Closes https://github.com/zed-industries/zed/issues/17661

Release Notes:

- Fixed a bug where copying from the assistant panel appended an
additional newline to the end of the clipboard contents.
2024-09-24 09:02:08 -04:00
Kirill Bulatov
153fb9eab8 Properly use default search options in the buffer search bar (#18271)
Only replace current search options if the search was dismissed and the
new options are different from the default ones.

Follow-up of https://github.com/zed-industries/zed/pull/17179
Closes https://github.com/zed-industries/zed/issues/18166


Release Notes:

- Fixed buffer search options toggling unexpectedly on redeploys
([#18166](https://github.com/zed-industries/zed/issues/18166))
2024-09-24 15:39:45 +03:00
Thorsten Ball
2330f0d2f9 vtsls: Move all default configuration to workspace_configuration (#18259)
This fixes https://github.com/zed-industries/zed/issues/18014 by fixing
the regression that was introduced in
https://github.com/zed-industries/zed/pull/17757.

In short: after digging into the `vtsls` code, it looks like it
essentially doesn't need any `initialization_options`, it's all
workspace configuration, since it tries to use the built-in settings
from VS Code.

I tested the completions, the inlay hints, the max memory - all of it
now works after moving to `workspace_configuration`.

Closes #18014.

Release Notes:

- Fixed `vtsls` being initialized the wrong way, which would mean the
wrong options were used to enable completions or inlay hints.
2024-09-24 14:35:40 +02:00
gcp-cherry-pick-bot[bot]
76b7c1df43 editor: Improve rewrapping when working with comments at different indentation levels (cherry-pick #18146) (#18147)
Cherry-picked editor: Improve rewrapping when working with comments at
different indentation levels (#18146)

This PR improves the `editor::Rewrap` command when working with comments
that were not all at the same indentation level.

We now use a heuristic of finding the most common indentation level for
each line, using the deepest indent in the event of a tie.

It also removes an `.unwrap()` that would previously lead to a panic in
this case. Instead of unwrapping we now log an error to the logs and
skip rewrapping for that selection.

Release Notes:

- Improved the behavior of `editor: rewrap` when working with a
selection that contained comments at different indentation levels.

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
2024-09-20 11:55:27 -04:00
Joseph T Lyons
a0a1b1c69b v0.154.x preview 2024-09-19 11:02:30 -04:00
29 changed files with 816 additions and 240 deletions

View File

@@ -41,7 +41,7 @@ jobs:
exit 1
;;
esac
which cargo-set-version > /dev/null || cargo install cargo-edit --features vendored-openssl
which cargo-set-version > /dev/null || cargo install cargo-edit
output=$(cargo set-version -p zed --bump patch 2>&1 | sed 's/.* //')
git commit -am "Bump to $output for @$GITHUB_ACTOR" --author "Zed Bot <hi@zed.dev>"
git tag v${output}${tag_suffix}

View File

@@ -271,7 +271,7 @@ jobs:
timeout-minutes: 60
name: Create a Linux bundle
runs-on:
- buildjet-16vcpu-ubuntu-2204
- buildjet-16vcpu-ubuntu-2004
if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
needs: [linux_tests]
env:
@@ -284,7 +284,7 @@ jobs:
clean: false
- name: Install Linux dependencies
run: ./script/linux
run: ./script/linux && ./script/install-mold 2.34.0
- name: Determine version and release channel
if: ${{ startsWith(github.ref, 'refs/tags/v') }}

View File

@@ -97,7 +97,7 @@ jobs:
name: Create a Linux *.tar.gz bundle for x86
if: github.repository_owner == 'zed-industries'
runs-on:
- buildjet-16vcpu-ubuntu-2204
- buildjet-16vcpu-ubuntu-2004
needs: tests
env:
DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
@@ -114,7 +114,7 @@ jobs:
run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
- name: Install Linux dependencies
run: ./script/linux
run: ./script/linux && ./script/install-mold 2.34.0
- name: Limit target directory size
run: script/clear-target-dir-if-larger-than 100

4
Cargo.lock generated
View File

@@ -2408,7 +2408,6 @@ dependencies = [
"cocoa 0.26.0",
"collections",
"feature_flags",
"fs",
"futures 0.3.30",
"gpui",
"http_client",
@@ -10994,6 +10993,7 @@ dependencies = [
"text",
"theme",
"ui",
"unicode-segmentation",
"util",
"windows 0.58.0",
]
@@ -14375,7 +14375,7 @@ dependencies = [
[[package]]
name = "zed"
version = "0.154.0"
version = "0.154.4"
dependencies = [
"activity_indicator",
"anyhow",

26
Dockerfile-distros Normal file
View File

@@ -0,0 +1,26 @@
# syntax=docker/dockerfile:1
ARG BASE_IMAGE
FROM ${BASE_IMAGE}
WORKDIR /app
ARG TZ=Etc/UTC \
LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
DEBIAN_FRONTEND=noninteractive
ENV CARGO_TERM_COLOR=always
COPY script/linux script/
RUN ./script/linux
COPY script/install-mold script/install-cmake script/
RUN ./script/install-mold "2.34.0"
RUN ./script/install-cmake "3.30.4"
COPY . .
# When debugging, make these into individual RUN statements.
# Cleanup to avoid saving big layers we aren't going to use.
RUN . "$HOME/.cargo/env" \
&& cargo fetch \
&& cargo build \
&& cargo run -- --help \
&& cargo clean --quiet

View File

@@ -0,0 +1,2 @@
**/target
**/node_modules

View File

@@ -3533,7 +3533,9 @@ impl ContextEditor {
for chunk in context.buffer().read(cx).text_for_range(range) {
text.push_str(chunk);
}
text.push('\n');
if message.offset_range.end < selection.range().end {
text.push('\n');
}
}
}
}

View File

@@ -268,7 +268,7 @@ fn view_release_notes_locally(workspace: &mut Workspace, cx: &mut ViewContext<Wo
let client = client::Client::global(cx).http_client();
let url = client.build_url(&format!(
"/api/release_notes/{}/{}",
"/api/release_notes/v2/{}/{}",
release_channel.dev_name(),
version
));

View File

@@ -23,7 +23,6 @@ chrono = { workspace = true, features = ["serde"] }
clock.workspace = true
collections.workspace = true
feature_flags.workspace = true
fs.workspace = true
futures.workspace = true
gpui.workspace = true
http_client.workspace = true

View File

@@ -6743,9 +6743,31 @@ impl Editor {
}
}
let row = selection.head().row;
let indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
let indent_end = Point::new(row, indent_size.len);
// Since not all lines in the selection may be at the same indent
// level, choose the indent size that is the most common between all
// of the lines.
//
// If there is a tie, we use the deepest indent.
let (indent_size, indent_end) = {
let mut indent_size_occurrences = HashMap::default();
let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
for row in start_row..=end_row {
let indent = buffer.indent_size_for_line(MultiBufferRow(row));
rows_by_indent_size.entry(indent).or_default().push(row);
*indent_size_occurrences.entry(indent).or_insert(0) += 1;
}
let indent_size = indent_size_occurrences
.into_iter()
.max_by_key(|(indent, count)| (*count, indent.len))
.map(|(indent, _)| indent)
.unwrap_or_default();
let row = rows_by_indent_size[&indent_size][0];
let indent_end = Point::new(row, indent_size.len);
(indent_size, indent_end)
};
let mut line_prefix = indent_size.chars().collect::<String>();
@@ -6795,10 +6817,22 @@ impl Editor {
let start = Point::new(start_row, 0);
let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
let selection_text = buffer.text_for_range(start..end).collect::<String>();
let unwrapped_text = selection_text
let Some(lines_without_prefixes) = selection_text
.lines()
.map(|line| line.strip_prefix(&line_prefix).unwrap())
.join(" ");
.map(|line| {
line.strip_prefix(&line_prefix)
.or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
.ok_or_else(|| {
anyhow!("line did not start with prefix {line_prefix:?}: {line:?}")
})
})
.collect::<Result<Vec<_>, _>>()
.log_err()
else {
continue;
};
let unwrapped_text = lines_without_prefixes.join(" ");
let wrap_column = buffer
.settings_at(Point::new(start_row, 0), cx)
.preferred_line_length as usize;

View File

@@ -4249,6 +4249,80 @@ async fn test_rewrap(cx: &mut TestAppContext) {
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
cx.assert_editor_state(wrapped_text);
}
// Test rewrapping unaligned comments in a selection.
{
let language = Arc::new(Language::new(
LanguageConfig {
line_comments: vec!["// ".into(), "/// ".into()],
..LanguageConfig::default()
},
Some(tree_sitter_rust::LANGUAGE.into()),
));
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
let unwrapped_text = indoc! {"
fn foo() {
if true {
« // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae.
// Praesent semper egestas tellus id dignissim.ˇ»
do_something();
} else {
//
}
}
"};
let wrapped_text = indoc! {"
fn foo() {
if true {
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
// mollis elit purus, a ornare lacus gravida vitae. Praesent semper
// egestas tellus id dignissim.ˇ
do_something();
} else {
//
}
}
"};
cx.set_state(unwrapped_text);
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
cx.assert_editor_state(wrapped_text);
let unwrapped_text = indoc! {"
fn foo() {
if true {
«ˇ // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae.
// Praesent semper egestas tellus id dignissim.»
do_something();
} else {
//
}
}
"};
let wrapped_text = indoc! {"
fn foo() {
if true {
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
// mollis elit purus, a ornare lacus gravida vitae. Praesent semper
// egestas tellus id dignissim.ˇ
do_something();
} else {
//
}
}
"};
cx.set_state(unwrapped_text);
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
cx.assert_editor_state(wrapped_text);
}
}
#[gpui::test]

View File

@@ -386,7 +386,7 @@ fn matching_history_items<'a>(
.chars(),
),
};
candidates_paths.insert(Arc::clone(&found_path.project.path), found_path);
candidates_paths.insert(&found_path.project, found_path);
Some((found_path.project.worktree_id, candidate))
})
.fold(
@@ -411,17 +411,21 @@ fn matching_history_items<'a>(
max_results,
)
.into_iter()
.map(|path_match| {
let (_, found_path) = candidates_paths
.remove_entry(&path_match.path)
.expect("candidate info not found");
(
Arc::clone(&path_match.path),
Match::History {
path: found_path.clone(),
panel_match: Some(ProjectPanelOrdMatch(path_match)),
},
)
.filter_map(|path_match| {
candidates_paths
.remove_entry(&ProjectPath {
worktree_id: WorktreeId::from_usize(path_match.worktree_id),
path: Arc::clone(&path_match.path),
})
.map(|(_, found_path)| {
(
Arc::clone(&path_match.path),
Match::History {
path: found_path.clone(),
panel_match: Some(ProjectPanelOrdMatch(path_match)),
},
)
})
}),
);
}

View File

@@ -144,7 +144,7 @@ pub struct BufferSnapshot {
/// The kind and amount of indentation in a particular line. For now,
/// assumes that indentation is all the same character.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub struct IndentSize {
/// The number of bytes that comprise the indentation.
pub len: u32,
@@ -153,7 +153,7 @@ pub struct IndentSize {
}
/// A whitespace character that's used for indentation.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub enum IndentKind {
/// An ASCII space character.
#[default]

View File

@@ -4,8 +4,7 @@
(struct_item
(visibility_modifier)? @context
"struct" @context
name: (_) @name
body: (_ "{" @open (_)* "}" @close)) @item
name: (_) @name) @item
(enum_item
(visibility_modifier)? @context

View File

@@ -6,14 +6,14 @@ use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
use lsp::{CodeActionKind, LanguageServerBinary};
use node_runtime::NodeRuntime;
use project::{lsp_store::language_server_settings, project_settings::BinarySettings};
use serde_json::{json, Value};
use serde_json::Value;
use std::{
any::Any,
ffi::OsString,
path::{Path, PathBuf},
sync::Arc,
};
use util::{maybe, ResultExt};
use util::{maybe, merge_json_value_into, ResultExt};
fn typescript_server_binary_arguments(server_path: &Path) -> Vec<OsString> {
vec![server_path.into(), "--stdio".into()]
@@ -212,11 +212,12 @@ impl LspAdapter for VtslsLspAdapter {
})
}
async fn initialization_options(
async fn workspace_configuration(
self: Arc<Self>,
adapter: &Arc<dyn LspAdapterDelegate>,
) -> Result<Option<serde_json::Value>> {
let tsdk_path = Self::tsdk_path(adapter).await;
delegate: &Arc<dyn LspAdapterDelegate>,
cx: &mut AsyncAppContext,
) -> Result<Value> {
let tsdk_path = Self::tsdk_path(delegate).await;
let config = serde_json::json!({
"tsdk": tsdk_path,
"suggest": {
@@ -243,10 +244,13 @@ impl LspAdapter for VtslsLspAdapter {
"enumMemberValues": {
"enabled": true
}
}
},
"tsserver": {
"maxTsServerMemory": 8092
},
});
Ok(Some(json!({
let mut default_workspace_configuration = serde_json::json!({
"typescript": config,
"javascript": config,
"vtsls": {
@@ -258,33 +262,18 @@ impl LspAdapter for VtslsLspAdapter {
},
"autoUseWorkspaceTsdk": true
}
})))
}
});
async fn workspace_configuration(
self: Arc<Self>,
delegate: &Arc<dyn LspAdapterDelegate>,
cx: &mut AsyncAppContext,
) -> Result<Value> {
let override_options = cx.update(|cx| {
language_server_settings(delegate.as_ref(), SERVER_NAME, cx)
.and_then(|s| s.settings.clone())
})?;
if let Some(options) = override_options {
return Ok(options);
if let Some(override_options) = override_options {
merge_json_value_into(override_options, &mut default_workspace_configuration)
}
let config = serde_json::json!({
"tsserver": {
"maxTsServerMemory": 8092
},
});
Ok(serde_json::json!({
"typescript": config,
"javascript": config
}))
Ok(default_workspace_configuration)
}
fn language_ids(&self) -> HashMap<String, String> {

View File

@@ -6,7 +6,7 @@ use clock::ReplicaId;
use collections::{BTreeMap, Bound, HashMap, HashSet};
use futures::{channel::mpsc, SinkExt};
use git::diff::DiffHunk;
use gpui::{AppContext, EntityId, EventEmitter, Model, ModelContext};
use gpui::{AppContext, EntityId, EventEmitter, Model, ModelContext, Task};
use itertools::Itertools;
use language::{
language_settings::{language_settings, LanguageSettings},
@@ -1106,64 +1106,24 @@ impl MultiBuffer {
}
}
pub fn stream_excerpts_with_context_lines(
pub fn forget_transaction(
&mut self,
buffer: Model<Buffer>,
ranges: Vec<Range<text::Anchor>>,
context_line_count: u32,
transaction_id: TransactionId,
cx: &mut ModelContext<Self>,
) -> mpsc::Receiver<Range<Anchor>> {
let (buffer_id, buffer_snapshot) =
buffer.update(cx, |buffer, _| (buffer.remote_id(), buffer.snapshot()));
let (mut tx, rx) = mpsc::channel(256);
cx.spawn(move |this, mut cx| async move {
let mut excerpt_ranges = Vec::new();
let mut range_counts = Vec::new();
cx.background_executor()
.scoped(|scope| {
scope.spawn(async {
let (ranges, counts) =
build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
excerpt_ranges = ranges;
range_counts = counts;
) {
if let Some(buffer) = self.as_singleton() {
buffer.update(cx, |buffer, _| {
buffer.forget_transaction(transaction_id);
});
} else if let Some(transaction) = self.history.forget(transaction_id) {
for (buffer_id, buffer_transaction_id) in transaction.buffer_transactions {
if let Some(state) = self.buffers.borrow_mut().get_mut(&buffer_id) {
state.buffer.update(cx, |buffer, _| {
buffer.forget_transaction(buffer_transaction_id);
});
})
.await;
let mut ranges = ranges.into_iter();
let mut range_counts = range_counts.into_iter();
for excerpt_ranges in excerpt_ranges.chunks(100) {
let excerpt_ids = match this.update(&mut cx, |this, cx| {
this.push_excerpts(buffer.clone(), excerpt_ranges.iter().cloned(), cx)
}) {
Ok(excerpt_ids) => excerpt_ids,
Err(_) => return,
};
for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.by_ref())
{
for range in ranges.by_ref().take(range_count) {
let start = Anchor {
buffer_id: Some(buffer_id),
excerpt_id,
text_anchor: range.start,
};
let end = Anchor {
buffer_id: Some(buffer_id),
excerpt_id,
text_anchor: range.end,
};
if tx.send(start..end).await.is_err() {
break;
}
}
}
}
})
.detach();
rx
}
}
pub fn push_excerpts<O>(
@@ -1215,6 +1175,91 @@ impl MultiBuffer {
anchor_ranges
}
pub fn push_multiple_excerpts_with_context_lines(
&mut self,
buffers_with_ranges: Vec<(Model<Buffer>, Vec<Range<text::Anchor>>)>,
context_line_count: u32,
cx: &mut ModelContext<Self>,
) -> Task<Vec<Range<Anchor>>> {
use futures::StreamExt;
let (excerpt_ranges_tx, mut excerpt_ranges_rx) = mpsc::channel(256);
let mut buffer_ids = Vec::with_capacity(buffers_with_ranges.len());
for (buffer, ranges) in buffers_with_ranges {
let (buffer_id, buffer_snapshot) =
buffer.update(cx, |buffer, _| (buffer.remote_id(), buffer.snapshot()));
buffer_ids.push(buffer_id);
cx.background_executor()
.spawn({
let mut excerpt_ranges_tx = excerpt_ranges_tx.clone();
async move {
let (excerpt_ranges, counts) =
build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
excerpt_ranges_tx
.send((buffer_id, buffer.clone(), ranges, excerpt_ranges, counts))
.await
.ok();
}
})
.detach()
}
cx.spawn(move |this, mut cx| async move {
let mut results_by_buffer_id = HashMap::default();
while let Some((buffer_id, buffer, ranges, excerpt_ranges, range_counts)) =
excerpt_ranges_rx.next().await
{
results_by_buffer_id
.insert(buffer_id, (buffer, ranges, excerpt_ranges, range_counts));
}
let mut multi_buffer_ranges = Vec::default();
'outer: for buffer_id in buffer_ids {
let Some((buffer, ranges, excerpt_ranges, range_counts)) =
results_by_buffer_id.remove(&buffer_id)
else {
continue;
};
let mut ranges = ranges.into_iter();
let mut range_counts = range_counts.into_iter();
for excerpt_ranges in excerpt_ranges.chunks(100) {
let excerpt_ids = match this.update(&mut cx, |this, cx| {
this.push_excerpts(buffer.clone(), excerpt_ranges.iter().cloned(), cx)
}) {
Ok(excerpt_ids) => excerpt_ids,
Err(_) => continue 'outer,
};
for (excerpt_id, range_count) in
excerpt_ids.into_iter().zip(range_counts.by_ref())
{
for range in ranges.by_ref().take(range_count) {
let start = Anchor {
buffer_id: Some(buffer_id),
excerpt_id,
text_anchor: range.start,
};
let end = Anchor {
buffer_id: Some(buffer_id),
excerpt_id,
text_anchor: range.end,
};
multi_buffer_ranges.push(start..end);
}
}
}
}
multi_buffer_ranges
})
}
pub fn insert_excerpts_after<O>(
&mut self,
prev_excerpt_id: ExcerptId,
@@ -4967,7 +5012,6 @@ where
#[cfg(test)]
mod tests {
use super::*;
use futures::StreamExt;
use gpui::{AppContext, Context, TestAppContext};
use language::{Buffer, Rope};
use parking_lot::RwLock;
@@ -5518,41 +5562,67 @@ mod tests {
);
}
#[gpui::test]
async fn test_stream_excerpts_with_context_lines(cx: &mut TestAppContext) {
let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
let snapshot = buffer.read(cx);
let ranges = vec![
snapshot.anchor_before(Point::new(3, 2))..snapshot.anchor_before(Point::new(4, 2)),
snapshot.anchor_before(Point::new(7, 1))..snapshot.anchor_before(Point::new(7, 3)),
snapshot.anchor_before(Point::new(15, 0))
..snapshot.anchor_before(Point::new(15, 0)),
];
multibuffer.stream_excerpts_with_context_lines(buffer.clone(), ranges, 2, cx)
});
#[gpui::test(iterations = 100)]
async fn test_push_multiple_excerpts_with_context_lines(cx: &mut TestAppContext) {
let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(15, 4, 'a'), cx));
let snapshot_1 = buffer_1.update(cx, |buffer, _| buffer.snapshot());
let snapshot_2 = buffer_2.update(cx, |buffer, _| buffer.snapshot());
let ranges_1 = vec![
snapshot_1.anchor_before(Point::new(3, 2))..snapshot_1.anchor_before(Point::new(4, 2)),
snapshot_1.anchor_before(Point::new(7, 1))..snapshot_1.anchor_before(Point::new(7, 3)),
snapshot_1.anchor_before(Point::new(15, 0))
..snapshot_1.anchor_before(Point::new(15, 0)),
];
let ranges_2 = vec![
snapshot_2.anchor_before(Point::new(2, 1))..snapshot_2.anchor_before(Point::new(3, 1)),
snapshot_2.anchor_before(Point::new(10, 0))
..snapshot_2.anchor_before(Point::new(10, 2)),
];
let anchor_ranges = anchor_ranges.collect::<Vec<_>>().await;
let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let anchor_ranges = multibuffer
.update(cx, |multibuffer, cx| {
multibuffer.push_multiple_excerpts_with_context_lines(
vec![(buffer_1.clone(), ranges_1), (buffer_2.clone(), ranges_2)],
2,
cx,
)
})
.await;
let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx));
assert_eq!(
snapshot.text(),
concat!(
"bbb\n", //
"bbb\n", // buffer_1
"ccc\n", //
"ddd\n", //
"eee\n", //
"ddd\n", // <-- excerpt 1
"eee\n", // <-- excerpt 1
"fff\n", //
"ggg\n", //
"hhh\n", //
"hhh\n", // <-- excerpt 2
"iii\n", //
"jjj\n", //
//
"nnn\n", //
"ooo\n", //
"ppp\n", //
"ppp\n", // <-- excerpt 3
"qqq\n", //
"rrr", //
"rrr\n", //
//
"aaaa\n", // buffer 2
"bbbb\n", //
"cccc\n", // <-- excerpt 4
"dddd\n", // <-- excerpt 4
"eeee\n", //
"ffff\n", //
//
"iiii\n", //
"jjjj\n", //
"kkkk\n", // <-- excerpt 5
"llll\n", //
"mmmm", //
)
);
@@ -5564,7 +5634,9 @@ mod tests {
vec![
Point::new(2, 2)..Point::new(3, 2),
Point::new(6, 1)..Point::new(6, 3),
Point::new(11, 0)..Point::new(11, 0)
Point::new(11, 0)..Point::new(11, 0),
Point::new(16, 1)..Point::new(17, 1),
Point::new(22, 0)..Point::new(22, 2)
]
);
}

View File

@@ -87,6 +87,7 @@ pub struct BufferSearchBar {
pending_search: Option<Task<()>>,
search_options: SearchOptions,
default_options: SearchOptions,
configured_options: SearchOptions,
query_contains_error: bool,
dismissed: bool,
search_history: SearchHistory,
@@ -517,6 +518,7 @@ impl BufferSearchBar {
active_match_index: None,
searchable_items_with_matches: Default::default(),
default_options: search_options,
configured_options: search_options,
search_options,
pending_search: None,
query_contains_error: false,
@@ -605,10 +607,11 @@ impl BufferSearchBar {
return false;
};
self.default_options = SearchOptions::from_settings(&EditorSettings::get_global(cx).search);
if self.default_options != self.search_options {
self.search_options = self.default_options;
self.configured_options =
SearchOptions::from_settings(&EditorSettings::get_global(cx).search);
if self.dismissed && self.configured_options != self.default_options {
self.search_options = self.configured_options;
self.default_options = self.configured_options;
}
self.dismissed = false;
@@ -627,6 +630,7 @@ impl BufferSearchBar {
.map(SearchableItemHandle::supported_options)
.unwrap_or_default()
}
pub fn search_suggested(&mut self, cx: &mut ViewContext<Self>) {
let search = self
.query_suggestion(cx)
@@ -1195,10 +1199,11 @@ mod tests {
use std::ops::Range;
use super::*;
use editor::{display_map::DisplayRow, DisplayPoint, Editor, MultiBuffer};
use gpui::{Context, Hsla, TestAppContext, VisualTestContext};
use editor::{display_map::DisplayRow, DisplayPoint, Editor, MultiBuffer, SearchSettings};
use gpui::{Context, Hsla, TestAppContext, UpdateGlobal, VisualTestContext};
use language::{Buffer, Point};
use project::Project;
use settings::SettingsStore;
use smol::stream::StreamExt as _;
use unindent::Unindent as _;
@@ -2320,4 +2325,119 @@ mod tests {
assert!(display_points_of(editor.all_text_background_highlights(cx)).is_empty(),);
});
}
#[gpui::test]
async fn test_search_options_changes(cx: &mut TestAppContext) {
let (_editor, search_bar, cx) = init_test(cx);
update_search_settings(
SearchSettings {
whole_word: false,
case_sensitive: false,
include_ignored: false,
regex: false,
},
cx,
);
let deploy = Deploy {
focus: true,
replace_enabled: false,
selection_search_enabled: true,
};
search_bar.update(cx, |search_bar, cx| {
assert_eq!(
search_bar.search_options,
SearchOptions::NONE,
"Should have no search options enabled by default"
);
search_bar.toggle_search_option(SearchOptions::WHOLE_WORD, cx);
assert_eq!(
search_bar.search_options,
SearchOptions::WHOLE_WORD,
"Should enable the option toggled"
);
assert!(
!search_bar.dismissed,
"Search bar should be present and visible"
);
search_bar.deploy(&deploy, cx);
assert_eq!(
search_bar.configured_options,
SearchOptions::NONE,
"Should have configured search options matching the settings"
);
assert_eq!(
search_bar.search_options,
SearchOptions::WHOLE_WORD,
"After (re)deploying, the option should still be enabled"
);
search_bar.dismiss(&Dismiss, cx);
search_bar.deploy(&deploy, cx);
assert_eq!(
search_bar.search_options,
SearchOptions::NONE,
"After hiding and showing the search bar, default options should be used"
);
search_bar.toggle_search_option(SearchOptions::REGEX, cx);
search_bar.toggle_search_option(SearchOptions::WHOLE_WORD, cx);
assert_eq!(
search_bar.search_options,
SearchOptions::REGEX | SearchOptions::WHOLE_WORD,
"Should enable the options toggled"
);
assert!(
!search_bar.dismissed,
"Search bar should be present and visible"
);
});
update_search_settings(
SearchSettings {
whole_word: false,
case_sensitive: true,
include_ignored: false,
regex: false,
},
cx,
);
search_bar.update(cx, |search_bar, cx| {
assert_eq!(
search_bar.search_options,
SearchOptions::REGEX | SearchOptions::WHOLE_WORD,
"Should have no search options enabled by default"
);
search_bar.deploy(&deploy, cx);
assert_eq!(
search_bar.configured_options,
SearchOptions::CASE_SENSITIVE,
"Should have configured search options matching the settings"
);
assert_eq!(
search_bar.search_options,
SearchOptions::REGEX | SearchOptions::WHOLE_WORD,
"Toggling a non-dismissed search bar with custom options should not change the default options"
);
search_bar.dismiss(&Dismiss, cx);
search_bar.deploy(&deploy, cx);
assert_eq!(
search_bar.search_options,
SearchOptions::CASE_SENSITIVE,
"After hiding and showing the search bar, default options should be used"
);
});
}
fn update_search_settings(search_settings: SearchSettings, cx: &mut TestAppContext) {
cx.update(|cx| {
SettingsStore::update_global(cx, |store, cx| {
store.update_user_settings::<EditorSettings>(cx, |settings| {
settings.search = Some(search_settings);
});
});
});
}
}

View File

@@ -264,54 +264,35 @@ impl ProjectSearch {
let mut limit_reached = false;
while let Some(results) = matches.next().await {
let tasks = results
.into_iter()
.map(|result| {
let this = this.clone();
cx.spawn(|mut cx| async move {
match result {
project::search::SearchResult::Buffer { buffer, ranges } => {
let mut match_ranges_rx =
this.update(&mut cx, |this, cx| {
this.excerpts.update(cx, |excerpts, cx| {
excerpts.stream_excerpts_with_context_lines(
buffer,
ranges,
editor::DEFAULT_MULTIBUFFER_CONTEXT,
cx,
)
})
})?;
let mut match_ranges = vec![];
while let Some(range) = match_ranges_rx.next().await {
match_ranges.push(range);
}
anyhow::Ok((match_ranges, false))
}
project::search::SearchResult::LimitReached => {
anyhow::Ok((vec![], true))
}
}
})
})
.collect::<Vec<_>>();
let result_ranges = futures::future::join_all(tasks).await;
let mut combined_ranges = vec![];
for (ranges, result_limit_reached) in result_ranges.into_iter().flatten() {
combined_ranges.extend(ranges);
if result_limit_reached {
limit_reached = result_limit_reached;
let mut buffers_with_ranges = Vec::with_capacity(results.len());
for result in results {
match result {
project::search::SearchResult::Buffer { buffer, ranges } => {
buffers_with_ranges.push((buffer, ranges));
}
project::search::SearchResult::LimitReached => {
limit_reached = true;
}
}
}
let match_ranges = this
.update(&mut cx, |this, cx| {
this.excerpts.update(cx, |excerpts, cx| {
excerpts.push_multiple_excerpts_with_context_lines(
buffers_with_ranges,
editor::DEFAULT_MULTIBUFFER_CONTEXT,
cx,
)
})
})
.ok()?
.await;
this.update(&mut cx, |this, cx| {
if !combined_ranges.is_empty() {
this.no_results = Some(false);
this.match_ranges.extend(combined_ranges);
cx.notify();
}
this.no_results = Some(false);
this.match_ranges.extend(match_ranges);
cx.notify();
})
.ok()?;
}

View File

@@ -29,6 +29,7 @@ supermaven_api.workspace = true
smol.workspace = true
text.workspace = true
ui.workspace = true
unicode-segmentation.workspace = true
util.workspace = true
[target.'cfg(target_os = "windows")'.dependencies]

View File

@@ -12,6 +12,7 @@ use std::{
time::Duration,
};
use text::{ToOffset, ToPoint};
use unicode_segmentation::UnicodeSegmentation;
pub const DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);
@@ -54,33 +55,34 @@ fn completion_state_from_diff(
) -> CompletionProposal {
let buffer_text = snapshot
.text_for_range(delete_range.clone())
.collect::<String>()
.chars()
.collect::<Vec<char>>();
.collect::<String>();
let mut inlays: Vec<InlayProposal> = Vec::new();
let completion = completion_text.chars().collect::<Vec<char>>();
let completion_graphemes: Vec<&str> = completion_text.graphemes(true).collect();
let buffer_graphemes: Vec<&str> = buffer_text.graphemes(true).collect();
let mut offset = position.to_offset(&snapshot);
let mut i = 0;
let mut j = 0;
while i < completion.len() && j < buffer_text.len() {
while i < completion_graphemes.len() && j < buffer_graphemes.len() {
// find the next instance of the buffer text in the completion text.
let k = completion[i..].iter().position(|c| *c == buffer_text[j]);
let k = completion_graphemes[i..]
.iter()
.position(|c| *c == buffer_graphemes[j]);
match k {
Some(k) => {
if k != 0 {
// the range from the current position to item is an inlay.
inlays.push(InlayProposal::Suggestion(
snapshot.anchor_after(offset),
completion_text[i..i + k].into(),
completion_graphemes[i..i + k].join("").into(),
));
}
i += k + 1;
j += 1;
offset.add_assign(1);
offset.add_assign(buffer_graphemes[j - 1].len());
}
None => {
// there are no more matching completions, so drop the remaining
@@ -90,11 +92,11 @@ fn completion_state_from_diff(
}
}
if j == buffer_text.len() && i < completion.len() {
if j == buffer_graphemes.len() && i < completion_graphemes.len() {
// there is leftover completion text, so drop it as an inlay.
inlays.push(InlayProposal::Suggestion(
snapshot.anchor_after(offset),
completion_text[i..completion_text.len()].into(),
completion_graphemes[i..].join("").into(),
));
}

View File

@@ -2,7 +2,7 @@
description = "The fast, collaborative code editor."
edition = "2021"
name = "zed"
version = "0.154.0"
version = "0.154.4"
publish = false
license = "GPL-3.0-or-later"
authors = ["Zed Team <hi@zed.dev>"]

View File

@@ -1 +1 @@
dev
stable

View File

@@ -35,6 +35,12 @@ Clone down the [Zed repository](https://github.com/zed-industries/zed).
brew install cmake
```
- (Optional) Install `mold` to speed up link times
```sh
brew install mold
```
## Backend Dependencies
If you are developing collaborative features of Zed, you'll need to install the dependencies of zed's `collab` server:

View File

@@ -68,29 +68,95 @@ Prettier will also be used for TypeScript files by default. To disable this:
Zed sets the following initialization options to make the language server send back inlay hints
(that is, when Zed has inlay hints enabled in the settings).
You can override these settings in your configuration file:
You can override these settings in your Zed settings file.
When using `typescript-language-server`:
```json
"lsp": {
"$LANGUAGE_SERVER_NAME": {
"initialization_options": {
"preferences": {
"includeInlayParameterNameHints": "all",
"includeInlayParameterNameHintsWhenArgumentMatchesName": true,
"includeInlayFunctionParameterTypeHints": true,
"includeInlayVariableTypeHints": true,
"includeInlayVariableTypeHintsWhenTypeMatchesName": true,
"includeInlayPropertyDeclarationTypeHints": true,
"includeInlayFunctionLikeReturnTypeHints": true,
"includeInlayEnumMemberValueHints": true,
}
{
"lsp": {
"typescript-language-server": {
"initialization_options": {
"preferences": {
"includeInlayParameterNameHints": "all",
"includeInlayParameterNameHintsWhenArgumentMatchesName": true,
"includeInlayFunctionParameterTypeHints": true,
"includeInlayVariableTypeHints": true,
"includeInlayVariableTypeHintsWhenTypeMatchesName": true,
"includeInlayPropertyDeclarationTypeHints": true,
"includeInlayFunctionLikeReturnTypeHints": true,
"includeInlayEnumMemberValueHints": true
}
}
}
}
```
See [typescript-language-server inlayhints documentation](https://github.com/typescript-language-server/typescript-language-server?tab=readme-ov-file#inlay-hints-textdocumentinlayhint) for more information.
When using `vtsls`:
```json
{
"lsp": {
"vtsls": {
"settings": {
// For JavaScript:
"javascript": {
"inlayHints": {
"parameterNames": {
"enabled": "all",
"suppressWhenArgumentMatchesName": false
},
"parameterTypes": {
"enabled": true
},
"variableTypes": {
"enabled": true,
"suppressWhenTypeMatchesName": true
},
"propertyDeclarationTypes": {
"enabled": true
},
"functionLikeReturnTypes": {
"enabled": true
},
"enumMemberValues": {
"enabled": true
}
}
},
// For TypeScript:
"typescript": {
"inlayHints": {
"parameterNames": {
"enabled": "all",
"suppressWhenArgumentMatchesName": false
},
"parameterTypes": {
"enabled": true
},
"variableTypes": {
"enabled": true,
"suppressWhenTypeMatchesName": true
},
"propertyDeclarationTypes": {
"enabled": true
},
"functionLikeReturnTypes": {
"enabled": true
},
"enumMemberValues": {
"enabled": true
}
}
}
}
}
}
}
```
## See also
- [Zed Yarn documentation](./yarn.md) for a walkthrough of configuring your project to use Yarn.

25
script/build-docker Executable file
View File

@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Use a docker BASE_IMAGE to test building Zed.
# e.g: ./script/bundle-docker ubuntu:20.04
#
# Increasing resources available to podman may speed this up:
# podman machine stop
# podman machine set --memory 16384 --cpus 8 --disk-size 200
# podman machine start
set -euo pipefail
BASE_IMAGE=${BASE_IMAGE:-${1:-}}
if [ -z "$BASE_IMAGE" ]; then
echo "Usage: $0 BASE_IMAGE" >&2
exit 1
fi
export DOCKER_BUILDKIT=1
cd "$(dirname "$0")/.."
podman build . \
-f Dockerfile-distros \
-t many \
--build-arg BASE_IMAGE="$BASE_IMAGE"

77
script/install-cmake Executable file
View File

@@ -0,0 +1,77 @@
#!/usr/bin/env bash
#
# This script installs an up-to-date version of CMake.
#
# For MacOS use Homebrew to install the latest version.
#
# For Ubuntu use the official KitWare Apt repository with backports.
# See: https://apt.kitware.com/
#
# For other systems (RHEL 8.x, 9.x, AmazonLinux, SUSE, Fedora, Arch, etc)
# use the official CMake installer script from KitWare.
#
# Note this is similar to how GitHub Actions runners install cmake:
# https://github.com/actions/runner-images/blob/main/images/ubuntu/scripts/build/install-cmake.sh
#
# Upstream: 3.30.4 (2024-09-27)
set -euo pipefail
if [[ "$(uname -s)" == "darwin" ]]; then
brew --version >/dev/null \
|| echo "Error: Homebrew is required to install cmake on MacOS." && exit 1
echo "Installing cmake via Homebrew (can't pin to old versions)."
brew install cmake
exit 0
elif [ "$(uname -s)" != "Linux" ]; then
echo "Error: This script is intended for MacOS/Linux systems only."
exit 1
elif [ -z "${1:-}" ]; then
echo "Usage: $0 [3.30.4]"
exit 1
fi
CMAKE_VERSION="${CMAKE_VERSION:-${1:-3.30.4}}"
if [ "$(whoami)" = root ]; then SUDO=; else SUDO="$(command -v sudo || command -v doas || true)"; fi
if cmake --version | grep -q "$CMAKE_VERSION"; then
echo "CMake $CMAKE_VERSION is already installed."
exit 0
elif [ -e /usr/local/bin/cmake ]; then
echo "Warning: existing cmake found at /usr/local/bin/cmake. Skipping installation."
exit 0
elif [ -e /etc/apt/sources.list.d/kitware.list ]; then
echo "Warning: existing KitWare repository found. Skipping installation."
exit 0
elif [ -e /etc/lsb-release ] && grep -qP 'DISTRIB_ID=Ubuntu' /etc/lsb-release; then
curl -fsSL https://apt.kitware.com/keys/kitware-archive-latest.asc \
| $SUDO gpg --dearmor - \
| $SUDO tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" \
| $SUDO tee /etc/apt/sources.list.d/kitware.list >/dev/null
$SUDO apt-get update
$SUDO apt-get install -y kitware-archive-keyring cmake==$CMAKE_VERSION
else
arch="$(uname -m)"
if [ "$arch" != "x86_64" ] && [ "$arch" != "aarch64" ]; then
echo "Error. Only x86_64 and aarch64 are supported."
exit 1
fi
tempdir=$(mktemp -d)
pushd "$tempdir"
CMAKE_REPO="https://github.com/Kitware/CMake"
CMAKE_INSTALLER="cmake-$CMAKE_VERSION-linux-$arch.sh"
curl -fsSL --output cmake-$CMAKE_VERSION-SHA-256.txt \
"$CMAKE_REPO/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-SHA-256.txt"
curl -fsSL --output $CMAKE_INSTALLER \
"$CMAKE_REPO/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-linux-$arch.sh"
# workaround for old versions of sha256sum not having --ignore-missing
grep -F "cmake-$CMAKE_VERSION-linux-$arch.sh" "cmake-$CMAKE_VERSION-SHA-256.txt" \
| sha256sum -c \
| grep -qP "^${CMAKE_INSTALLER}: OK"
chmod +x cmake-$CMAKE_VERSION-linux-$arch.sh
$SUDO ./cmake-$CMAKE_VERSION-linux-$arch.sh --prefix=/usr/local --skip-license
popd
rm -rf "$tempdir"
fi

37
script/install-mold Executable file
View File

@@ -0,0 +1,37 @@
#!/usr/bin/env bash
# Install `mold` official binaries from GitHub Releases.
#
# Adapted from the official rui314/setup-mold@v1 action to:
# * use environment variables instead of action inputs
# * remove make-default support
# * use curl instead of wget
# * support doas for sudo
# * support redhat systems
# See: https://github.com/rui314/setup-mold/blob/main/action.yml
set -euo pipefail
MOLD_VERSION="${MOLD_VERSION:-${1:-}}"
if [ "$(uname -s)" != "Linux" ]; then
echo "Error: This script is intended for Linux systems only."
exit 1
elif [ -z "$MOLD_VERSION" ]; then
echo "Usage: $0 2.34.0"
exit 1
elif [ -e /usr/local/bin/mold ]; then
echo "Warning: existing mold found at /usr/local/bin/mold. Skipping installation."
exit 0
fi
if [ "$(whoami)" = root ]; then SUDO=; else SUDO="$(command -v sudo || command -v doas || true)"; fi
MOLD_REPO="${MOLD_REPO:-https://github.com/rui314/mold}"
MOLD_URL="${MOLD_URL:-$MOLD_REPO}/releases/download/v$MOLD_VERSION/mold-$MOLD_VERSION-$(uname -m)-linux.tar.gz"
echo "Downloading from $MOLD_URL"
curl -fsSL --output - "$MOLD_URL" \
| $SUDO tar -C /usr/local --strip-components=1 --no-overwrite-dir -xzf -
# Note this binary depends on the system libatomic.so.1 which is usually
# provided as a dependency of gcc so it should be available on most systems.

View File

@@ -12,7 +12,7 @@ if [[ -n $(git status --short --untracked-files=no) ]]; then
exit 1
fi
which cargo-set-version > /dev/null || cargo install cargo-edit --features vendored-openssl
which cargo-set-version > /dev/null || cargo install cargo-edit
which jq > /dev/null || brew install jq
cargo set-version --package $package --bump $version_increment
cargo check --quiet

View File

@@ -1,15 +1,25 @@
#!/usr/bin/env bash
set -ex
set -xeuo pipefail
# install the wasm toolchain
which rustup > /dev/null 2>&1 || curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
# if root or if sudo/unavailable, define an empty variable
if [ "$(id -u)" -eq 0 ]
then maysudo=''
else maysudo="$(command -v sudo || command -v doas || true)"
fi
# if sudo is not installed, define an empty alias
maysudo=$(command -v sudo || command -v doas || true)
function finalize {
# after packages install (curl, etc), get the rust toolchain
which rustup > /dev/null 2>&1 || curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
# verify the mold situation
if ! command -v mold >/dev/null 2>&1; then
echo "Warning: Mold binaries are unavailable on your system." >&2
echo " Builds will be slower without mold. Try: scripts/install-mold" >&2
fi
echo "Finished installing Linux dependencies with script/linux"
}
# Ubuntu, Debian, etc.
# https://packages.ubuntu.com/
# Ubuntu, Debian, Mint, Kali, Pop!_OS, Raspbian, etc.
apt=$(command -v apt-get || true)
if [[ -n $apt ]]; then
deps=(
@@ -20,55 +30,95 @@ if [[ -n $apt ]]; then
libwayland-dev
libxkbcommon-x11-dev
libssl-dev
libstdc++-12-dev
libzstd-dev
libvulkan1
libgit2-dev
make
cmake
clang
mold
jq
git
curl
gettext-base
elfutils
libsqlite3-dev
)
if (grep -qP 'PRETTY_NAME="(.+24\.04)' /etc/os-release); then
deps+=( mold libstdc++-14-dev )
elif (grep -qP 'PRETTY_NAME="((Debian|Raspbian).+12|.+22\.04)' /etc/os-release); then
deps+=( mold libstdc++-12-dev )
elif (grep -qP 'PRETTY_NAME="((Debian|Raspbian).+11|.+20\.04)' /etc/os-release); then
deps+=( libstdc++-10-dev )
fi
$maysudo "$apt" update
$maysudo "$apt" install -y "${deps[@]}"
finalize
exit 0
fi
# Fedora, CentOS, RHEL, etc.
# https://packages.fedoraproject.org/
# Fedora, CentOS, RHEL, Alma, Amazon 2023, Oracle, etc.
dnf=$(command -v dnf || true)
if [[ -n $dnf ]]; then
# Old Redhat (yum only): Amazon Linux 2, Oracle Linux 7, etc.
yum=$(command -v yum || true)
if [[ -n $dnf ]] || [[ -n $yum ]]; then
pkg_cmd="${dnf:-${yum}}"
deps=(
gcc
g++
clang
cmake
mold
alsa-lib-devel
fontconfig-devel
wayland-devel
libxkbcommon-x11-devel
openssl-devel
libzstd-devel
# Perl dependencies are needed for openssl-sys crate see https://docs.rs/openssl/latest/openssl/
perl-FindBin
perl-IPC-Cmd
perl-File-Compare
perl-File-Copy
vulkan-loader
sqlite-devel
jq
git
tar
)
# libxkbcommon-x11-devel is in the crb repo on RHEL and CentOS, not needed for Fedora
if ! grep -q "Fedora" /etc/redhat-release; then
$maysudo "$dnf" config-manager --set-enabled crb
# perl used for building openssl-sys crate. See: https://docs.rs/openssl/latest/openssl/
if grep -qP '^ID="(fedora)' /etc/os-release; then
deps+=(
perl-FindBin
perl-IPC-Cmd
perl-File-Compare
perl-File-Copy
mold
)
elif grep grep -qP '^ID="(rhel|rocky|alma|centos|ol)' /etc/os-release; then
deps+=( perl-interpreter )
fi
$maysudo "$dnf" install -y "${deps[@]}"
# gcc-c++ is g++ on RHEL8 and 8.x clones
if grep -qP '^ID="(rhel|rocky|alma|centos|ol)' /etc/os-release \
&& grep -qP '^VERSION_ID="8' /etc/os-release; then
deps+=( gcc-c++ )
else
deps+=( g++ )
fi
# libxkbcommon-x11-devel is in a non-default repo on RHEL 8.x/9.x (except on AmazonLinux)
if grep -qP '^VERSION_ID="(8|9)' && grep -qP '^ID="(rhel|rocky|centos|alma|ol)' /etc/os-release; then
$maysudo dnf install -y 'dnf-command(config-manager)'
if grep -qP '^PRETTY_NAME="(AlmaLinux 8|Rocky Linux 8)' /etc/os-release; then
$maysudo dnf config-manager --set-enabled powertools
elif grep -qP '^PRETTY_NAME="((AlmaLinux|Rocky|CentOS Stream) 9|Red Hat.+(8|9))' /etc/os-release; then
$maysudo dnf config-manager --set-enabled crb
elif grep -qP '^PRETTY_NAME="Oracle Linux Server 8' /etc/os-release; then
$maysudo dnf config-manager --set-enabled ol8_codeready_builder
elif grep -qP '^PRETTY_NAME="Oracle Linux Server 9' /etc/os-release; then
$maysudo dnf config-manager --set-enabled ol9_codeready_builder
else
echo "Unexpected distro" && grep 'PRETTY_NAME' /etc/os-release && exit 1
fi
fi
$maysudo $pkg_cmd install -y "${deps[@]}"
finalize
exit 0
fi
@@ -89,10 +139,14 @@ if [[ -n $zyp ]]; then
openssl-devel
libzstd-devel
libvulkan1
mold
sqlite3-devel
jq
git
tar
gzip
)
$maysudo "$zyp" install -y "${deps[@]}"
finalize
exit 0
fi
@@ -115,8 +169,10 @@ if [[ -n $pacman ]]; then
mold
sqlite
jq
git
)
$maysudo "$pacman" -S --needed --noconfirm "${deps[@]}"
$maysudo "$pacman" -Syu --needed --noconfirm "${deps[@]}"
finalize
exit 0
fi
@@ -143,6 +199,7 @@ if [[ -n $xbps ]]; then
sqlite-devel
)
$maysudo "$xbps" -Syu "${deps[@]}"
finalize
exit 0
fi
@@ -152,6 +209,7 @@ emerge=$(command -v emerge || true)
if [[ -n $emerge ]]; then
deps=(
app-arch/zstd
app-misc/jq
dev-libs/openssl
dev-libs/wayland
dev-util/cmake
@@ -164,7 +222,9 @@ if [[ -n $emerge ]]; then
dev-db/sqlite
)
$maysudo "$emerge" -u "${deps[@]}"
finalize
exit 0
fi
echo "Unsupported Linux distribution in script/linux"
exit 1