Add remote server cross compilation (#19136)

This will allow us to compile debug builds of the remote-server for a
different architecture than the one we are developing on.

This also adds a CI step for building our remote server with minimal
dependencies.

Release Notes:

- N/A
This commit is contained in:
Mikayla Maki 2024-10-12 23:23:56 -07:00 committed by GitHub
parent f73a076a63
commit bebe24ea77
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 542 additions and 161 deletions

View file

@ -99,7 +99,10 @@ jobs:
run: cargo build -p collab run: cargo build -p collab
- name: Build other binaries and features - name: Build other binaries and features
run: cargo build --workspace --bins --all-features; cargo check -p gpui --features "macos-blade" run: |
cargo build --workspace --bins --all-features
cargo check -p gpui --features "macos-blade"
cargo build -p remote_server
linux_tests: linux_tests:
timeout-minutes: 60 timeout-minutes: 60
@ -133,6 +136,32 @@ jobs:
- name: Build Zed - name: Build Zed
run: cargo build -p zed run: cargo build -p zed
build_remote_server:
timeout-minutes: 60
name: (Linux) Build Remote Server
runs-on:
- buildjet-16vcpu-ubuntu-2204
steps:
- name: Add Rust to the PATH
run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
- name: Checkout repo
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
with:
clean: false
- name: Cache dependencies
uses: swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
cache-provider: "buildjet"
- name: Install Clang & Mold
run: ./script/remote-server && ./script/install-mold 2.34.0
- name: Build Remote Server
run: cargo build -p remote_server
# todo(windows): Actually run the tests # todo(windows): Actually run the tests
windows_tests: windows_tests:
timeout-minutes: 60 timeout-minutes: 60

1
Cargo.lock generated
View file

@ -14669,6 +14669,7 @@ dependencies = [
"winresource", "winresource",
"workspace", "workspace",
"zed_actions", "zed_actions",
"zstd",
] ]
[[package]] [[package]]

View file

@ -220,7 +220,7 @@ git = { path = "crates/git" }
git_hosting_providers = { path = "crates/git_hosting_providers" } git_hosting_providers = { path = "crates/git_hosting_providers" }
go_to_line = { path = "crates/go_to_line" } go_to_line = { path = "crates/go_to_line" }
google_ai = { path = "crates/google_ai" } google_ai = { path = "crates/google_ai" }
gpui = { path = "crates/gpui" } gpui = { path = "crates/gpui", default-features = false, features = ["http_client"]}
gpui_macros = { path = "crates/gpui_macros" } gpui_macros = { path = "crates/gpui_macros" }
headless = { path = "crates/headless" } headless = { path = "crates/headless" }
html_to_markdown = { path = "crates/html_to_markdown" } html_to_markdown = { path = "crates/html_to_markdown" }
@ -477,6 +477,7 @@ wasmtime = { version = "24", default-features = false, features = [
wasmtime-wasi = "24" wasmtime-wasi = "24"
which = "6.0.0" which = "6.0.0"
wit-component = "0.201" wit-component = "0.201"
zstd = "0.11"
[workspace.dependencies.async-stripe] [workspace.dependencies.async-stripe]
git = "https://github.com/zed-industries/async-stripe" git = "https://github.com/zed-industries/async-stripe"

2
Cross.toml Normal file
View file

@ -0,0 +1,2 @@
[build]
dockerfile = "Dockerfile-cross"

17
Dockerfile-cross Normal file
View file

@ -0,0 +1,17 @@
# syntax=docker/dockerfile:1
ARG CROSS_BASE_IMAGE
FROM ${CROSS_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/install-mold script/
RUN ./script/install-mold "2.34.0"
COPY script/remote-server script/
RUN ./script/remote-server
COPY . .

View file

@ -0,0 +1,16 @@
.git
.github
**/.gitignore
**/.gitkeep
.gitattributes
.mailmap
**/target
zed.xcworkspace
.DS_Store
compose.yml
plugins/bin
script/node_modules
styles/node_modules
crates/collab/static/styles.css
vendor/bin
assets/themes/

View file

@ -464,6 +464,7 @@ impl AutoUpdater {
smol::fs::create_dir_all(&platform_dir).await.ok(); smol::fs::create_dir_all(&platform_dir).await.ok();
let client = this.read_with(cx, |this, _| this.http_client.clone())?; let client = this.read_with(cx, |this, _| this.http_client.clone())?;
if smol::fs::metadata(&version_path).await.is_err() { if smol::fs::metadata(&version_path).await.is_err() {
log::info!("downloading zed-remote-server {os} {arch}"); log::info!("downloading zed-remote-server {os} {arch}");
download_remote_server_binary(&version_path, release, client, cx).await?; download_remote_server_binary(&version_path, release, client, cx).await?;

View file

@ -11,16 +11,53 @@ license = "Apache-2.0"
workspace = true workspace = true
[features] [features]
default = ["http_client"] default = ["http_client", "font-kit", "wayland", "x11"]
test-support = [ test-support = [
"backtrace", "backtrace",
"collections/test-support", "collections/test-support",
"rand", "rand",
"util/test-support", "util/test-support",
"http_client?/test-support", "http_client?/test-support",
"wayland",
"x11",
] ]
runtime_shaders = [] runtime_shaders = []
macos-blade = ["blade-graphics", "blade-macros", "blade-util", "bytemuck"] macos-blade = ["blade-graphics", "blade-macros", "blade-util", "bytemuck"]
wayland = [
"blade-graphics",
"blade-macros",
"blade-util",
"bytemuck",
"ashpd",
"cosmic-text",
"font-kit",
"calloop-wayland-source",
"wayland-backend",
"wayland-client",
"wayland-cursor",
"wayland-protocols",
"wayland-protocols-plasma",
"filedescriptor",
"xkbcommon",
"open",
]
x11 = [
"blade-graphics",
"blade-macros",
"blade-util",
"bytemuck",
"ashpd",
"cosmic-text",
"font-kit",
"as-raw-xcb-connection",
"x11rb",
"xkbcommon",
"xim",
"x11-clipboard",
"filedescriptor",
"open",
]
[lib] [lib]
path = "src/gpui.rs" path = "src/gpui.rs"
@ -95,7 +132,7 @@ core-foundation.workspace = true
core-foundation-sys = "0.8" core-foundation-sys = "0.8"
core-graphics = "0.23" core-graphics = "0.23"
core-text = "20.1" core-text = "20.1"
font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "40391b7" } font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "40391b7", optional = true}
foreign-types = "0.5" foreign-types = "0.5"
log.workspace = true log.workspace = true
media.workspace = true media.workspace = true
@ -105,31 +142,45 @@ objc = "0.2"
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies] [target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
pathfinder_geometry = "0.5" pathfinder_geometry = "0.5"
[target.'cfg(any(target_os = "linux", target_os = "windows"))'.dependencies]
blade-graphics.workspace = true
blade-macros.workspace = true
blade-util.workspace = true
bytemuck = "1"
flume = "0.11"
[target.'cfg(target_os = "linux")'.dependencies] [target.'cfg(target_os = "linux")'.dependencies]
as-raw-xcb-connection = "1" # Always used
ashpd.workspace = true flume = "0.11"
calloop = "0.13.0" oo7 = "0.3.0"
calloop-wayland-source = "0.3.0"
cosmic-text = { git = "https://github.com/pop-os/cosmic-text", rev = "542b20c" } # Used in both windowing options
wayland-backend = { version = "0.3.3", features = ["client_system", "dlopen"] } ashpd = { workspace = true, optional = true }
wayland-client = { version = "0.31.2" } blade-graphics = { workspace = true, optional = true }
wayland-cursor = "0.31.1" blade-macros = { workspace = true, optional = true }
blade-util = { workspace = true, optional = true }
bytemuck = { version = "1", optional = true }
cosmic-text = { git = "https://github.com/pop-os/cosmic-text", rev = "542b20c", optional = true }
font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "40391b7", features = [
"source-fontconfig-dlopen",
], optional = true }
calloop = { version = "0.13.0" }
filedescriptor = { version = "0.8.2", optional = true }
open = { version = "5.2.0", optional = true }
# Wayland
calloop-wayland-source = { version = "0.3.0", optional = true }
wayland-backend = { version = "0.3.3", features = [
"client_system",
"dlopen",
], optional = true }
wayland-client = { version = "0.31.2", optional = true }
wayland-cursor = { version = "0.31.1", optional = true }
wayland-protocols = { version = "0.31.2", features = [ wayland-protocols = { version = "0.31.2", features = [
"client", "client",
"staging", "staging",
"unstable", "unstable",
] } ], optional = true }
wayland-protocols-plasma = { version = "0.2.0", features = ["client"] } wayland-protocols-plasma = { version = "0.2.0", features = [
oo7 = "0.3.0" "client",
open = "5.2.0" ], optional = true }
filedescriptor = "0.8.2"
# X11
as-raw-xcb-connection = { version = "1", optional = true }
x11rb = { version = "0.13.0", features = [ x11rb = { version = "0.13.0", features = [
"allow-unsafe-code", "allow-unsafe-code",
"xkb", "xkb",
@ -138,21 +189,23 @@ x11rb = { version = "0.13.0", features = [
"cursor", "cursor",
"resource_manager", "resource_manager",
"sync", "sync",
] } ], optional = true }
xkbcommon = { git = "https://github.com/ConradIrwin/xkbcommon-rs", rev = "fcbb4612185cc129ceeff51d22f7fb51810a03b2", features = [ xkbcommon = { git = "https://github.com/ConradIrwin/xkbcommon-rs", rev = "fcbb4612185cc129ceeff51d22f7fb51810a03b2", features = [
"wayland", "wayland",
"x11", "x11",
] } ], optional = true }
xim = { git = "https://github.com/XDeme1/xim-rs", rev = "d50d461764c2213655cd9cf65a0ea94c70d3c4fd", features = [ xim = { git = "https://github.com/XDeme1/xim-rs", rev = "d50d461764c2213655cd9cf65a0ea94c70d3c4fd", features = [
"x11rb-xcb", "x11rb-xcb",
"x11rb-client", "x11rb-client",
] } ], optional = true }
font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "40391b7", features = [ x11-clipboard = { version = "0.9.2", optional = true }
"source-fontconfig-dlopen",
] }
x11-clipboard = "0.9.2"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
blade-util.workspace = true
bytemuck = "1"
blade-graphics.workspace = true
blade-macros.workspace = true
flume = "0.11"
rand.workspace = true rand.workspace = true
windows.workspace = true windows.workspace = true
windows-core = "0.58" windows-core = "0.58"

View file

@ -10,7 +10,11 @@ mod linux;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
mod mac; mod mac;
#[cfg(any(target_os = "linux", target_os = "windows", feature = "macos-blade"))] #[cfg(any(
all(target_os = "linux", any(feature = "x11", feature = "wayland")),
target_os = "windows",
feature = "macos-blade"
))]
mod blade; mod blade;
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
@ -26,7 +30,7 @@ use crate::{
RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams, ScaledPixels, Scene, RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams, ScaledPixels, Scene,
SharedString, Size, SvgSize, Task, TaskLabel, WindowContext, DEFAULT_WINDOW_SIZE, SharedString, Size, SvgSize, Task, TaskLabel, WindowContext, DEFAULT_WINDOW_SIZE,
}; };
use anyhow::Result; use anyhow::{anyhow, Result};
use async_task::Runnable; use async_task::Runnable;
use futures::channel::oneshot; use futures::channel::oneshot;
use image::codecs::gif::GifDecoder; use image::codecs::gif::GifDecoder;
@ -75,8 +79,12 @@ pub(crate) fn current_platform(headless: bool) -> Rc<dyn Platform> {
} }
match guess_compositor() { match guess_compositor() {
#[cfg(feature = "wayland")]
"Wayland" => Rc::new(WaylandClient::new()), "Wayland" => Rc::new(WaylandClient::new()),
#[cfg(feature = "x11")]
"X11" => Rc::new(X11Client::new()), "X11" => Rc::new(X11Client::new()),
"Headless" => Rc::new(HeadlessClient::new()), "Headless" => Rc::new(HeadlessClient::new()),
_ => unreachable!(), _ => unreachable!(),
} }
@ -90,8 +98,16 @@ pub fn guess_compositor() -> &'static str {
if std::env::var_os("ZED_HEADLESS").is_some() { if std::env::var_os("ZED_HEADLESS").is_some() {
return "Headless"; return "Headless";
} }
#[cfg(feature = "wayland")]
let wayland_display = std::env::var_os("WAYLAND_DISPLAY"); let wayland_display = std::env::var_os("WAYLAND_DISPLAY");
#[cfg(not(feature = "wayland"))]
let wayland_display: Option<std::ffi::OsString> = None;
#[cfg(feature = "x11")]
let x11_display = std::env::var_os("DISPLAY"); let x11_display = std::env::var_os("DISPLAY");
#[cfg(not(feature = "x11"))]
let x11_display: Option<std::ffi::OsString> = None;
let use_wayland = wayland_display.is_some_and(|display| !display.is_empty()); let use_wayland = wayland_display.is_some_and(|display| !display.is_empty());
let use_x11 = x11_display.is_some_and(|display| !display.is_empty()); let use_x11 = x11_display.is_some_and(|display| !display.is_empty());
@ -426,6 +442,61 @@ pub(crate) trait PlatformTextSystem: Send + Sync {
fn layout_line(&self, text: &str, font_size: Pixels, runs: &[FontRun]) -> LineLayout; fn layout_line(&self, text: &str, font_size: Pixels, runs: &[FontRun]) -> LineLayout;
} }
pub(crate) struct NoopTextSystem;
impl NoopTextSystem {
#[allow(dead_code)]
pub fn new() -> Self {
Self
}
}
impl PlatformTextSystem for NoopTextSystem {
fn add_fonts(&self, _fonts: Vec<Cow<'static, [u8]>>) -> Result<()> {
Ok(())
}
fn all_font_names(&self) -> Vec<String> {
Vec::new()
}
fn font_id(&self, descriptor: &Font) -> Result<FontId> {
Err(anyhow!("No font found for {:?}", descriptor))
}
fn font_metrics(&self, _font_id: FontId) -> FontMetrics {
unimplemented!()
}
fn typographic_bounds(&self, font_id: FontId, _glyph_id: GlyphId) -> Result<Bounds<f32>> {
Err(anyhow!("No font found for {:?}", font_id))
}
fn advance(&self, font_id: FontId, _glyph_id: GlyphId) -> Result<Size<f32>> {
Err(anyhow!("No font found for {:?}", font_id))
}
fn glyph_for_char(&self, _font_id: FontId, _ch: char) -> Option<GlyphId> {
None
}
fn glyph_raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>> {
Err(anyhow!("No font found for {:?}", params))
}
fn rasterize_glyph(
&self,
params: &RenderGlyphParams,
_raster_bounds: Bounds<DevicePixels>,
) -> Result<(Size<DevicePixels>, Vec<u8>)> {
Err(anyhow!("No font found for {:?}", params))
}
fn layout_line(&self, _text: &str, _font_size: Pixels, _runs: &[FontRun]) -> LineLayout {
unimplemented!()
}
}
#[derive(PartialEq, Eq, Hash, Clone)] #[derive(PartialEq, Eq, Hash, Clone)]
pub(crate) enum AtlasKey { pub(crate) enum AtlasKey {
Glyph(RenderGlyphParams), Glyph(RenderGlyphParams),
@ -434,6 +505,10 @@ pub(crate) enum AtlasKey {
} }
impl AtlasKey { impl AtlasKey {
#[cfg_attr(
all(target_os = "linux", not(any(feature = "x11", feature = "wayland"))),
allow(dead_code)
)]
pub(crate) fn texture_kind(&self) -> AtlasTextureKind { pub(crate) fn texture_kind(&self) -> AtlasTextureKind {
match self { match self {
AtlasKey::Glyph(params) => { AtlasKey::Glyph(params) => {
@ -494,6 +569,10 @@ pub(crate) struct AtlasTextureId {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(C)] #[repr(C)]
#[cfg_attr(
all(target_os = "linux", not(any(feature = "x11", feature = "wayland"))),
allow(dead_code)
)]
pub(crate) enum AtlasTextureKind { pub(crate) enum AtlasTextureKind {
Monochrome = 0, Monochrome = 0,
Polychrome = 1, Polychrome = 1,
@ -521,6 +600,10 @@ pub(crate) struct PlatformInputHandler {
handler: Box<dyn InputHandler>, handler: Box<dyn InputHandler>,
} }
#[cfg_attr(
all(target_os = "linux", not(any(feature = "x11", feature = "wayland"))),
allow(dead_code)
)]
impl PlatformInputHandler { impl PlatformInputHandler {
pub fn new(cx: AsyncWindowContext, handler: Box<dyn InputHandler>) -> Self { pub fn new(cx: AsyncWindowContext, handler: Box<dyn InputHandler>) -> Self {
Self { cx, handler } Self { cx, handler }
@ -728,10 +811,15 @@ pub struct WindowOptions {
/// The variables that can be configured when creating a new window /// The variables that can be configured when creating a new window
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(
all(target_os = "linux", not(any(feature = "x11", feature = "wayland"))),
allow(dead_code)
)]
pub(crate) struct WindowParams { pub(crate) struct WindowParams {
pub bounds: Bounds<Pixels>, pub bounds: Bounds<Pixels>,
/// The titlebar configuration of the window /// The titlebar configuration of the window
#[cfg_attr(feature = "wayland", allow(dead_code))]
pub titlebar: Option<TitlebarOptions>, pub titlebar: Option<TitlebarOptions>,
/// The kind of window to create /// The kind of window to create
@ -748,6 +836,7 @@ pub(crate) struct WindowParams {
#[cfg_attr(target_os = "linux", allow(dead_code))] #[cfg_attr(target_os = "linux", allow(dead_code))]
pub show: bool, pub show: bool,
#[cfg_attr(feature = "wayland", allow(dead_code))]
pub display_id: Option<DisplayId>, pub display_id: Option<DisplayId>,
pub window_min_size: Option<Size<Pixels>>, pub window_min_size: Option<Size<Pixels>>,

View file

@ -455,7 +455,7 @@ impl BladeRenderer {
} }
} }
#[cfg_attr(target_os = "macos", allow(dead_code))] #[cfg_attr(any(target_os = "macos", feature = "wayland"), allow(dead_code))]
pub fn viewport_size(&self) -> gpu::Extent { pub fn viewport_size(&self) -> gpu::Extent {
self.surface_config.size self.surface_config.size
} }

View file

@ -1,14 +1,22 @@
mod dispatcher; mod dispatcher;
mod headless; mod headless;
mod platform; mod platform;
#[cfg(any(feature = "wayland", feature = "x11"))]
mod text_system; mod text_system;
#[cfg(feature = "wayland")]
mod wayland; mod wayland;
#[cfg(feature = "x11")]
mod x11; mod x11;
#[cfg(any(feature = "wayland", feature = "x11"))]
mod xdg_desktop_portal; mod xdg_desktop_portal;
pub(crate) use dispatcher::*; pub(crate) use dispatcher::*;
pub(crate) use headless::*; pub(crate) use headless::*;
pub(crate) use platform::*; pub(crate) use platform::*;
#[cfg(any(feature = "wayland", feature = "x11"))]
pub(crate) use text_system::*; pub(crate) use text_system::*;
#[cfg(feature = "wayland")]
pub(crate) use wayland::*; pub(crate) use wayland::*;
#[cfg(feature = "x11")]
pub(crate) use x11::*; pub(crate) use x11::*;

View file

@ -19,32 +19,26 @@ use std::{
}; };
use anyhow::anyhow; use anyhow::anyhow;
use ashpd::desktop::file_chooser::{OpenFileRequest, SaveFileRequest};
use ashpd::desktop::open_uri::{OpenDirectoryRequest, OpenFileRequest as OpenUriRequest};
use ashpd::{url, ActivationToken};
use async_task::Runnable; use async_task::Runnable;
use calloop::channel::Channel; use calloop::channel::Channel;
use calloop::{EventLoop, LoopHandle, LoopSignal}; use calloop::{EventLoop, LoopHandle, LoopSignal};
use filedescriptor::FileDescriptor;
use flume::{Receiver, Sender}; use flume::{Receiver, Sender};
use futures::channel::oneshot; use futures::channel::oneshot;
use parking_lot::Mutex; use parking_lot::Mutex;
use util::ResultExt; use util::ResultExt;
use wayland_client::Connection;
use wayland_protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::Shape; #[cfg(any(feature = "wayland", feature = "x11"))]
use xkbcommon::xkb::{self, Keycode, Keysym, State}; use xkbcommon::xkb::{self, Keycode, Keysym, State};
use crate::platform::linux::wayland::WaylandClient; use crate::platform::NoopTextSystem;
use crate::{ use crate::{
px, Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CosmicTextSystem, CursorStyle, px, Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId,
DisplayId, ForegroundExecutor, Keymap, Keystroke, LinuxDispatcher, Menu, MenuItem, Modifiers, ForegroundExecutor, Keymap, Keystroke, LinuxDispatcher, Menu, MenuItem, Modifiers, OwnedMenu,
OwnedMenu, PathPromptOptions, Pixels, Platform, PlatformDisplay, PlatformInputHandler, PathPromptOptions, Pixels, Platform, PlatformDisplay, PlatformInputHandler, PlatformTextSystem,
PlatformTextSystem, PlatformWindow, Point, PromptLevel, Result, SemanticVersion, SharedString, PlatformWindow, Point, PromptLevel, Result, SemanticVersion, SharedString, Size, Task,
Size, Task, WindowAppearance, WindowOptions, WindowParams, WindowAppearance, WindowOptions, WindowParams,
}; };
use super::x11::X11Client;
pub(crate) const SCROLL_LINES: f32 = 3.0; pub(crate) const SCROLL_LINES: f32 = 3.0;
// Values match the defaults on GTK. // Values match the defaults on GTK.
@ -93,7 +87,7 @@ pub(crate) struct PlatformHandlers {
pub(crate) struct LinuxCommon { pub(crate) struct LinuxCommon {
pub(crate) background_executor: BackgroundExecutor, pub(crate) background_executor: BackgroundExecutor,
pub(crate) foreground_executor: ForegroundExecutor, pub(crate) foreground_executor: ForegroundExecutor,
pub(crate) text_system: Arc<CosmicTextSystem>, pub(crate) text_system: Arc<dyn PlatformTextSystem>,
pub(crate) appearance: WindowAppearance, pub(crate) appearance: WindowAppearance,
pub(crate) auto_hide_scrollbars: bool, pub(crate) auto_hide_scrollbars: bool,
pub(crate) callbacks: PlatformHandlers, pub(crate) callbacks: PlatformHandlers,
@ -104,7 +98,12 @@ pub(crate) struct LinuxCommon {
impl LinuxCommon { impl LinuxCommon {
pub fn new(signal: LoopSignal) -> (Self, Channel<Runnable>) { pub fn new(signal: LoopSignal) -> (Self, Channel<Runnable>) {
let (main_sender, main_receiver) = calloop::channel::channel::<Runnable>(); let (main_sender, main_receiver) = calloop::channel::channel::<Runnable>();
let text_system = Arc::new(CosmicTextSystem::new()); #[cfg(any(feature = "wayland", feature = "x11"))]
let text_system = Arc::new(crate::CosmicTextSystem::new());
#[cfg(not(any(feature = "wayland", feature = "x11")))]
let text_system = Arc::new(crate::NoopTextSystem::new());
let callbacks = PlatformHandlers::default(); let callbacks = PlatformHandlers::default();
let dispatcher = Arc::new(LinuxDispatcher::new(main_sender.clone())); let dispatcher = Arc::new(LinuxDispatcher::new(main_sender.clone()));
@ -264,6 +263,11 @@ impl<P: LinuxClient + 'static> Platform for P {
options: PathPromptOptions, options: PathPromptOptions,
) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> { ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
let (done_tx, done_rx) = oneshot::channel(); let (done_tx, done_rx) = oneshot::channel();
#[cfg(not(any(feature = "wayland", feature = "x11")))]
done_tx.send(Ok(None));
#[cfg(any(feature = "wayland", feature = "x11"))]
self.foreground_executor() self.foreground_executor()
.spawn(async move { .spawn(async move {
let title = if options.directories { let title = if options.directories {
@ -272,7 +276,7 @@ impl<P: LinuxClient + 'static> Platform for P {
"Open File" "Open File"
}; };
let request = match OpenFileRequest::default() let request = match ashpd::desktop::file_chooser::OpenFileRequest::default()
.modal(true) .modal(true)
.title(title) .title(title)
.multiple(options.multiple) .multiple(options.multiple)
@ -310,10 +314,17 @@ impl<P: LinuxClient + 'static> Platform for P {
fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Result<Option<PathBuf>>> { fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Result<Option<PathBuf>>> {
let (done_tx, done_rx) = oneshot::channel(); let (done_tx, done_rx) = oneshot::channel();
let directory = directory.to_owned();
#[cfg(not(any(feature = "wayland", feature = "x11")))]
done_tx.send(Ok(None));
#[cfg(any(feature = "wayland", feature = "x11"))]
self.foreground_executor() self.foreground_executor()
.spawn(async move { .spawn({
let request = match SaveFileRequest::default() let directory = directory.to_owned();
async move {
let request = match ashpd::desktop::file_chooser::SaveFileRequest::default()
.modal(true) .modal(true)
.title("Save File") .title("Save File")
.current_folder(directory) .current_folder(directory)
@ -324,7 +335,9 @@ impl<P: LinuxClient + 'static> Platform for P {
Ok(request) => request, Ok(request) => request,
Err(err) => { Err(err) => {
let result = match err { let result = match err {
ashpd::Error::PortalNotFound(_) => anyhow!(FILE_PICKER_PORTAL_MISSING), ashpd::Error::PortalNotFound(_) => {
anyhow!(FILE_PICKER_PORTAL_MISSING)
}
err => err.into(), err => err.into(),
}; };
done_tx.send(Err(result)); done_tx.send(Err(result));
@ -341,6 +354,7 @@ impl<P: LinuxClient + 'static> Platform for P {
Err(e) => Err(e.into()), Err(e) => Err(e.into()),
}; };
done_tx.send(result); done_tx.send(result);
}
}) })
.detach(); .detach();
@ -518,16 +532,17 @@ impl<P: LinuxClient + 'static> Platform for P {
fn add_recent_document(&self, _path: &Path) {} fn add_recent_document(&self, _path: &Path) {}
} }
#[cfg(any(feature = "wayland", feature = "x11"))]
pub(super) fn open_uri_internal( pub(super) fn open_uri_internal(
executor: BackgroundExecutor, executor: BackgroundExecutor,
uri: &str, uri: &str,
activation_token: Option<String>, activation_token: Option<String>,
) { ) {
if let Some(uri) = url::Url::parse(uri).log_err() { if let Some(uri) = ashpd::url::Url::parse(uri).log_err() {
executor executor
.spawn(async move { .spawn(async move {
match OpenUriRequest::default() match ashpd::desktop::open_uri::OpenFileRequest::default()
.activation_token(activation_token.clone().map(ActivationToken::from)) .activation_token(activation_token.clone().map(ashpd::ActivationToken::from))
.send_uri(&uri) .send_uri(&uri)
.await .await
{ {
@ -551,6 +566,7 @@ pub(super) fn open_uri_internal(
} }
} }
#[cfg(any(feature = "x11", feature = "wayland"))]
pub(super) fn reveal_path_internal( pub(super) fn reveal_path_internal(
executor: BackgroundExecutor, executor: BackgroundExecutor,
path: PathBuf, path: PathBuf,
@ -559,8 +575,8 @@ pub(super) fn reveal_path_internal(
executor executor
.spawn(async move { .spawn(async move {
if let Some(dir) = File::open(path.clone()).log_err() { if let Some(dir) = File::open(path.clone()).log_err() {
match OpenDirectoryRequest::default() match ashpd::desktop::open_uri::OpenDirectoryRequest::default()
.activation_token(activation_token.map(ActivationToken::from)) .activation_token(activation_token.map(ashpd::ActivationToken::from))
.send(&dir.as_fd()) .send(&dir.as_fd())
.await .await
{ {
@ -582,6 +598,7 @@ pub(super) fn is_within_click_distance(a: Point<Pixels>, b: Point<Pixels>) -> bo
diff.x.abs() <= DOUBLE_CLICK_DISTANCE && diff.y.abs() <= DOUBLE_CLICK_DISTANCE diff.x.abs() <= DOUBLE_CLICK_DISTANCE && diff.y.abs() <= DOUBLE_CLICK_DISTANCE
} }
#[cfg(any(feature = "wayland", feature = "x11"))]
pub(super) fn get_xkb_compose_state(cx: &xkb::Context) -> Option<xkb::compose::State> { pub(super) fn get_xkb_compose_state(cx: &xkb::Context) -> Option<xkb::compose::State> {
let mut locales = Vec::default(); let mut locales = Vec::default();
if let Some(locale) = std::env::var_os("LC_CTYPE") { if let Some(locale) = std::env::var_os("LC_CTYPE") {
@ -603,7 +620,8 @@ pub(super) fn get_xkb_compose_state(cx: &xkb::Context) -> Option<xkb::compose::S
state state
} }
pub(super) unsafe fn read_fd(mut fd: FileDescriptor) -> Result<Vec<u8>> { #[cfg(any(feature = "wayland", feature = "x11"))]
pub(super) unsafe fn read_fd(mut fd: filedescriptor::FileDescriptor) -> Result<Vec<u8>> {
let mut file = File::from_raw_fd(fd.as_raw_fd()); let mut file = File::from_raw_fd(fd.as_raw_fd());
let mut buffer = Vec::new(); let mut buffer = Vec::new();
file.read_to_end(&mut buffer)?; file.read_to_end(&mut buffer)?;
@ -611,32 +629,6 @@ pub(super) unsafe fn read_fd(mut fd: FileDescriptor) -> Result<Vec<u8>> {
} }
impl CursorStyle { impl CursorStyle {
pub(super) fn to_shape(&self) -> Shape {
match self {
CursorStyle::Arrow => Shape::Default,
CursorStyle::IBeam => Shape::Text,
CursorStyle::Crosshair => Shape::Crosshair,
CursorStyle::ClosedHand => Shape::Grabbing,
CursorStyle::OpenHand => Shape::Grab,
CursorStyle::PointingHand => Shape::Pointer,
CursorStyle::ResizeLeft => Shape::WResize,
CursorStyle::ResizeRight => Shape::EResize,
CursorStyle::ResizeLeftRight => Shape::EwResize,
CursorStyle::ResizeUp => Shape::NResize,
CursorStyle::ResizeDown => Shape::SResize,
CursorStyle::ResizeUpDown => Shape::NsResize,
CursorStyle::ResizeUpLeftDownRight => Shape::NwseResize,
CursorStyle::ResizeUpRightDownLeft => Shape::NeswResize,
CursorStyle::ResizeColumn => Shape::ColResize,
CursorStyle::ResizeRow => Shape::RowResize,
CursorStyle::IBeamCursorForVerticalLayout => Shape::VerticalText,
CursorStyle::OperationNotAllowed => Shape::NotAllowed,
CursorStyle::DragLink => Shape::Alias,
CursorStyle::DragCopy => Shape::Copy,
CursorStyle::ContextualMenu => Shape::ContextMenu,
}
}
pub(super) fn to_icon_name(&self) -> String { pub(super) fn to_icon_name(&self) -> String {
// Based on cursor names from https://gitlab.gnome.org/GNOME/adwaita-icon-theme (GNOME) // Based on cursor names from https://gitlab.gnome.org/GNOME/adwaita-icon-theme (GNOME)
// and https://github.com/KDE/breeze (KDE). Both of them seem to be also derived from // and https://github.com/KDE/breeze (KDE). Both of them seem to be also derived from
@ -668,6 +660,7 @@ impl CursorStyle {
} }
} }
#[cfg(any(feature = "wayland", feature = "x11"))]
impl Keystroke { impl Keystroke {
pub(super) fn from_xkb(state: &State, modifiers: Modifiers, keycode: Keycode) -> Self { pub(super) fn from_xkb(state: &State, modifiers: Modifiers, keycode: Keycode) -> Self {
let mut modifiers = modifiers; let mut modifiers = modifiers;
@ -813,6 +806,7 @@ impl Keystroke {
} }
} }
#[cfg(any(feature = "wayland", feature = "x11"))]
impl Modifiers { impl Modifiers {
pub(super) fn from_xkb(keymap_state: &State) -> Self { pub(super) fn from_xkb(keymap_state: &State) -> Self {
let shift = keymap_state.mod_name_is_active(xkb::MOD_NAME_SHIFT, xkb::STATE_MODS_EFFECTIVE); let shift = keymap_state.mod_name_is_active(xkb::MOD_NAME_SHIFT, xkb::STATE_MODS_EFFECTIVE);

View file

@ -6,3 +6,35 @@ mod serial;
mod window; mod window;
pub(crate) use client::*; pub(crate) use client::*;
use wayland_protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::Shape;
use crate::CursorStyle;
impl CursorStyle {
pub(super) fn to_shape(&self) -> Shape {
match self {
CursorStyle::Arrow => Shape::Default,
CursorStyle::IBeam => Shape::Text,
CursorStyle::Crosshair => Shape::Crosshair,
CursorStyle::ClosedHand => Shape::Grabbing,
CursorStyle::OpenHand => Shape::Grab,
CursorStyle::PointingHand => Shape::Pointer,
CursorStyle::ResizeLeft => Shape::WResize,
CursorStyle::ResizeRight => Shape::EResize,
CursorStyle::ResizeLeftRight => Shape::EwResize,
CursorStyle::ResizeUp => Shape::NResize,
CursorStyle::ResizeDown => Shape::SResize,
CursorStyle::ResizeUpDown => Shape::NsResize,
CursorStyle::ResizeUpLeftDownRight => Shape::NwseResize,
CursorStyle::ResizeUpRightDownLeft => Shape::NeswResize,
CursorStyle::ResizeColumn => Shape::ColResize,
CursorStyle::ResizeRow => Shape::RowResize,
CursorStyle::IBeamCursorForVerticalLayout => Shape::VerticalText,
CursorStyle::OperationNotAllowed => Shape::NotAllowed,
CursorStyle::DragLink => Shape::Alias,
CursorStyle::DragCopy => Shape::Copy,
CursorStyle::ContextualMenu => Shape::ContextMenu,
}
}
}

View file

@ -1421,10 +1421,12 @@ impl LinuxClient for X11Client {
} }
fn open_uri(&self, uri: &str) { fn open_uri(&self, uri: &str) {
#[cfg(any(feature = "wayland", feature = "x11"))]
open_uri_internal(self.background_executor(), uri, None); open_uri_internal(self.background_executor(), uri, None);
} }
fn reveal_path(&self, path: PathBuf) { fn reveal_path(&self, path: PathBuf) {
#[cfg(any(feature = "x11", feature = "wayland"))]
reveal_path_internal(self.background_executor(), path, None); reveal_path_internal(self.background_executor(), path, None);
} }

View file

@ -11,7 +11,9 @@ use crate::{BackgroundExecutor, WindowAppearance};
pub enum Event { pub enum Event {
WindowAppearance(WindowAppearance), WindowAppearance(WindowAppearance),
#[cfg_attr(feature = "x11", allow(dead_code))]
CursorTheme(String), CursorTheme(String),
#[cfg_attr(feature = "x11", allow(dead_code))]
CursorSize(u32), CursorSize(u32),
} }

View file

@ -17,9 +17,14 @@ use metal_renderer as renderer;
use crate::platform::blade as renderer; use crate::platform::blade as renderer;
mod attributed_string; mod attributed_string;
#[cfg(feature = "font-kit")]
mod open_type; mod open_type;
mod platform;
#[cfg(feature = "font-kit")]
mod text_system; mod text_system;
mod platform;
mod window; mod window;
mod window_appearance; mod window_appearance;
@ -39,9 +44,11 @@ pub(crate) use dispatcher::*;
pub(crate) use display::*; pub(crate) use display::*;
pub(crate) use display_link::*; pub(crate) use display_link::*;
pub(crate) use platform::*; pub(crate) use platform::*;
pub(crate) use text_system::*;
pub(crate) use window::*; pub(crate) use window::*;
#[cfg(feature = "font-kit")]
pub(crate) use text_system::*;
trait BoolExt { trait BoolExt {
fn to_objc(self) -> BOOL; fn to_objc(self) -> BOOL;
} }

View file

@ -6,9 +6,9 @@ use super::{
use crate::{ use crate::{
hash, Action, AnyWindowHandle, BackgroundExecutor, ClipboardEntry, ClipboardItem, hash, Action, AnyWindowHandle, BackgroundExecutor, ClipboardEntry, ClipboardItem,
ClipboardString, CursorStyle, ForegroundExecutor, Image, ImageFormat, Keymap, MacDispatcher, ClipboardString, CursorStyle, ForegroundExecutor, Image, ImageFormat, Keymap, MacDispatcher,
MacDisplay, MacTextSystem, MacWindow, Menu, MenuItem, PathPromptOptions, Platform, MacDisplay, MacWindow, Menu, MenuItem, PathPromptOptions, Platform, PlatformDisplay,
PlatformDisplay, PlatformTextSystem, PlatformWindow, Result, SemanticVersion, Task, PlatformTextSystem, PlatformWindow, Result, SemanticVersion, Task, WindowAppearance,
WindowAppearance, WindowParams, WindowParams,
}; };
use anyhow::anyhow; use anyhow::anyhow;
use block::ConcreteBlock; use block::ConcreteBlock;
@ -145,7 +145,7 @@ pub(crate) struct MacPlatform(Mutex<MacPlatformState>);
pub(crate) struct MacPlatformState { pub(crate) struct MacPlatformState {
background_executor: BackgroundExecutor, background_executor: BackgroundExecutor,
foreground_executor: ForegroundExecutor, foreground_executor: ForegroundExecutor,
text_system: Arc<MacTextSystem>, text_system: Arc<dyn PlatformTextSystem>,
renderer_context: renderer::Context, renderer_context: renderer::Context,
headless: bool, headless: bool,
pasteboard: id, pasteboard: id,
@ -171,11 +171,18 @@ impl Default for MacPlatform {
impl MacPlatform { impl MacPlatform {
pub(crate) fn new(headless: bool) -> Self { pub(crate) fn new(headless: bool) -> Self {
let dispatcher = Arc::new(MacDispatcher::new()); let dispatcher = Arc::new(MacDispatcher::new());
#[cfg(feature = "font-kit")]
let text_system = Arc::new(crate::MacTextSystem::new());
#[cfg(not(feature = "font-kit"))]
let text_system = Arc::new(crate::NoopTextSystem::new());
Self(Mutex::new(MacPlatformState { Self(Mutex::new(MacPlatformState {
background_executor: BackgroundExecutor::new(dispatcher.clone()),
headless, headless,
text_system,
background_executor: BackgroundExecutor::new(dispatcher.clone()),
foreground_executor: ForegroundExecutor::new(dispatcher), foreground_executor: ForegroundExecutor::new(dispatcher),
text_system: Arc::new(MacTextSystem::new()),
renderer_context: renderer::Context::default(), renderer_context: renderer::Context::default(),
pasteboard: unsafe { NSPasteboard::generalPasteboard(nil) }, pasteboard: unsafe { NSPasteboard::generalPasteboard(nil) },
text_hash_pasteboard_type: unsafe { ns_string("zed-text-hash") }, text_hash_pasteboard_type: unsafe { ns_string("zed-text-hash") },

View file

@ -40,6 +40,10 @@ impl Scene {
self.surfaces.clear(); self.surfaces.clear();
} }
#[cfg_attr(
all(target_os = "linux", not(any(feature = "x11", feature = "wayland"))),
allow(dead_code)
)]
pub fn paths(&self) -> &[Path<ScaledPixels>] { pub fn paths(&self) -> &[Path<ScaledPixels>] {
&self.paths &self.paths
} }
@ -130,6 +134,10 @@ impl Scene {
self.surfaces.sort(); self.surfaces.sort();
} }
#[cfg_attr(
all(target_os = "linux", not(any(feature = "x11", feature = "wayland"))),
allow(dead_code)
)]
pub(crate) fn batches(&self) -> impl Iterator<Item = PrimitiveBatch> { pub(crate) fn batches(&self) -> impl Iterator<Item = PrimitiveBatch> {
BatchIterator { BatchIterator {
shadows: &self.shadows, shadows: &self.shadows,
@ -158,6 +166,10 @@ impl Scene {
} }
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Default)] #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
#[cfg_attr(
all(target_os = "linux", not(any(feature = "x11", feature = "wayland"))),
allow(dead_code)
)]
pub(crate) enum PrimitiveKind { pub(crate) enum PrimitiveKind {
Shadow, Shadow,
#[default] #[default]
@ -212,6 +224,10 @@ impl Primitive {
} }
} }
#[cfg_attr(
all(target_os = "linux", not(any(feature = "x11", feature = "wayland"))),
allow(dead_code)
)]
struct BatchIterator<'a> { struct BatchIterator<'a> {
shadows: &'a [Shadow], shadows: &'a [Shadow],
shadows_start: usize, shadows_start: usize,
@ -398,6 +414,10 @@ impl<'a> Iterator for BatchIterator<'a> {
} }
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(
all(target_os = "linux", not(any(feature = "x11", feature = "wayland"))),
allow(dead_code)
)]
pub(crate) enum PrimitiveBatch<'a> { pub(crate) enum PrimitiveBatch<'a> {
Shadows(&'a [Shadow]), Shadows(&'a [Shadow]),
Quads(&'a [Quad]), Quads(&'a [Quad]),

View file

@ -390,40 +390,11 @@ impl SshClientDelegate {
// In dev mode, build the remote server binary from source // In dev mode, build the remote server binary from source
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
if release_channel == ReleaseChannel::Dev if release_channel == ReleaseChannel::Dev {
&& platform.arch == std::env::consts::ARCH let result = self.build_local(cx, platform, version).await?;
&& platform.os == std::env::consts::OS // Fall through to a remote binary if we're not able to compile a local binary
{ if let Some(result) = result {
use smol::process::{Command, Stdio}; return Ok(result);
self.update_status(Some("building remote server binary from source"), cx);
log::info!("building remote server binary from source");
run_cmd(Command::new("cargo").args([
"build",
"--package",
"remote_server",
"--target-dir",
"target/remote_server",
]))
.await?;
// run_cmd(Command::new("strip").args(["target/remote_server/debug/remote_server"]))
// .await?;
run_cmd(Command::new("gzip").args([
"-9",
"-f",
"target/remote_server/debug/remote_server",
]))
.await?;
let path = std::env::current_dir()?.join("target/remote_server/debug/remote_server.gz");
return Ok((path, version));
async fn run_cmd(command: &mut Command) -> Result<()> {
let output = command.stderr(Stdio::inherit()).output().await?;
if !output.status.success() {
Err(anyhow::anyhow!("failed to run command: {:?}", command))?;
}
Ok(())
} }
} }
@ -446,6 +417,105 @@ impl SshClientDelegate {
Ok((binary_path, version)) Ok((binary_path, version))
} }
#[cfg(debug_assertions)]
async fn build_local(
&self,
cx: &mut AsyncAppContext,
platform: SshPlatform,
version: SemanticVersion,
) -> Result<Option<(PathBuf, SemanticVersion)>> {
use smol::process::{Command, Stdio};
async fn run_cmd(command: &mut Command) -> Result<()> {
let output = command.stderr(Stdio::inherit()).output().await?;
if !output.status.success() {
Err(anyhow::anyhow!("failed to run command: {:?}", command))?;
}
Ok(())
}
if platform.arch == std::env::consts::ARCH && platform.os == std::env::consts::OS {
self.update_status(Some("Building remote server binary from source"), cx);
log::info!("building remote server binary from source");
run_cmd(Command::new("cargo").args([
"build",
"--package",
"remote_server",
"--target-dir",
"target/remote_server",
]))
.await?;
self.update_status(Some("Compressing binary"), cx);
run_cmd(Command::new("gzip").args([
"-9",
"-f",
"target/remote_server/debug/remote_server",
]))
.await?;
let path = std::env::current_dir()?.join("target/remote_server/debug/remote_server.gz");
return Ok(Some((path, version)));
} else if let Some(triple) = platform.triple() {
smol::fs::create_dir_all("target/remote-server").await?;
self.update_status(Some("Installing cross.rs"), cx);
log::info!("installing cross");
run_cmd(Command::new("cargo").args([
"install",
"cross",
"--git",
"https://github.com/cross-rs/cross",
]))
.await?;
self.update_status(
Some(&format!(
"Building remote server binary from source for {}",
&triple
)),
cx,
);
log::info!("building remote server binary from source for {}", &triple);
run_cmd(
Command::new("cross")
.args([
"build",
"--package",
"remote_server",
"--target-dir",
"target/remote_server",
"--target",
&triple,
])
.env(
"CROSS_CONTAINER_OPTS",
"--mount type=bind,src=./target,dst=/app/target",
),
)
.await?;
self.update_status(Some("Compressing binary"), cx);
run_cmd(Command::new("gzip").args([
"-9",
"-f",
&format!("target/remote_server/{}/debug/remote_server", triple),
]))
.await?;
let path = std::env::current_dir()?.join(format!(
"target/remote_server/{}/debug/remote_server.gz",
triple
));
return Ok(Some((path, version)));
} else {
return Ok(None);
}
}
} }
pub fn connect_over_ssh( pub fn connect_over_ssh(

View file

@ -118,6 +118,20 @@ pub struct SshPlatform {
pub arch: &'static str, pub arch: &'static str,
} }
impl SshPlatform {
pub fn triple(&self) -> Option<String> {
Some(format!(
"{}-{}",
self.arch,
match self.os {
"linux" => "unknown-linux-gnu",
"macos" => "apple-darwin",
_ => return None,
}
))
}
}
pub trait SshClientDelegate: Send + Sync { pub trait SshClientDelegate: Send + Sync {
fn ask_password( fn ask_password(
&self, &self,

View file

@ -35,10 +35,7 @@ sha2.workspace = true
strum.workspace = true strum.workspace = true
tracing = { version = "0.1.34", features = ["log"] } tracing = { version = "0.1.34", features = ["log"] }
util.workspace = true util.workspace = true
zstd = "0.11" zstd.workspace = true
[target.'cfg(target_os = "linux")'.dependencies]
zstd = { version = "0.11", features = [ "pkg-config" ] }
[dev-dependencies] [dev-dependencies]
collections = { workspace = true, features = ["test-support"] } collections = { workspace = true, features = ["test-support"] }

View file

@ -51,7 +51,7 @@ futures.workspace = true
git.workspace = true git.workspace = true
git_hosting_providers.workspace = true git_hosting_providers.workspace = true
go_to_line.workspace = true go_to_line.workspace = true
gpui.workspace = true gpui = { workspace = true, features = ["wayland", "x11", "font-kit"] }
headless.workspace = true headless.workspace = true
http_client.workspace = true http_client.workspace = true
image_viewer.workspace = true image_viewer.workspace = true
@ -125,6 +125,8 @@ winresource = "0.1"
[target.'cfg(target_os = "linux")'.dependencies] [target.'cfg(target_os = "linux")'.dependencies]
ashpd.workspace = true ashpd.workspace = true
# We don't use zstd in the zed crate, but we want to add this feature when compiling a desktop build of Zed
zstd = { workspace = true, features = [ "pkg-config" ] }
[dev-dependencies] [dev-dependencies]
call = { workspace = true, features = ["test-support"] } call = { workspace = true, features = ["test-support"] }
@ -169,4 +171,4 @@ osx_info_plist_exts = ["resources/info/*"]
osx_url_schemes = ["zed"] osx_url_schemes = ["zed"]
[package.metadata.cargo-machete] [package.metadata.cargo-machete]
ignored = ["profiling"] ignored = ["profiling", "zstd"]

17
script/remote-server Executable file
View file

@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -xeuo pipefail
# 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
deps=(
clang
)
$maysudo apt-get update
$maysudo apt-get install -y "${deps[@]}"
exit 0