mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-18 18:08:07 +03:00
linux: Implement local time zone support (#14610)
I decided to remove the GPUI APIs since `chrono` already provides this functionality, and is already been used for this purpose in other parts of the code (e.g. [here](80402a6840/crates/zed/src/main.rs (L756)
) or [here](80402a6840/crates/ui/src/utils/format_distance.rs (L258)
)) These usages end up calling the `time_format` crate, which takes in a `UtcOffset`. It's probably cleaner to rewrite the crate to take in `chrono` types, but that would require rewriting most of the code there. Release Notes: - linux: Use local time zone in chat and Git blame
This commit is contained in:
parent
22a2cc6950
commit
013c9f0420
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -2564,6 +2564,7 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"call",
|
"call",
|
||||||
"channel",
|
"channel",
|
||||||
|
"chrono",
|
||||||
"client",
|
"client",
|
||||||
"collections",
|
"collections",
|
||||||
"db",
|
"db",
|
||||||
@ -3593,6 +3594,7 @@ dependencies = [
|
|||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assets",
|
"assets",
|
||||||
|
"chrono",
|
||||||
"client",
|
"client",
|
||||||
"clock",
|
"clock",
|
||||||
"collections",
|
"collections",
|
||||||
|
@ -457,7 +457,6 @@ features = [
|
|||||||
"Win32_System_SystemInformation",
|
"Win32_System_SystemInformation",
|
||||||
"Win32_System_SystemServices",
|
"Win32_System_SystemServices",
|
||||||
"Win32_System_Threading",
|
"Win32_System_Threading",
|
||||||
"Win32_System_Time",
|
|
||||||
"Win32_System_WinRT",
|
"Win32_System_WinRT",
|
||||||
"Win32_UI_Controls",
|
"Win32_UI_Controls",
|
||||||
"Win32_UI_HiDpi",
|
"Win32_UI_HiDpi",
|
||||||
|
@ -32,6 +32,7 @@ test-support = [
|
|||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
call.workspace = true
|
call.workspace = true
|
||||||
channel.workspace = true
|
channel.workspace = true
|
||||||
|
chrono.workspace = true
|
||||||
client.workspace = true
|
client.workspace = true
|
||||||
collections.workspace = true
|
collections.workspace = true
|
||||||
db.workspace = true
|
db.workspace = true
|
||||||
|
@ -111,6 +111,7 @@ impl ChatPanel {
|
|||||||
this.is_scrolled_to_bottom = !event.is_scrolled;
|
this.is_scrolled_to_bottom = !event.is_scrolled;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
let local_offset = chrono::Local::now().offset().local_minus_utc();
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
fs,
|
fs,
|
||||||
client,
|
client,
|
||||||
@ -120,7 +121,7 @@ impl ChatPanel {
|
|||||||
active_chat: Default::default(),
|
active_chat: Default::default(),
|
||||||
pending_serialization: Task::ready(None),
|
pending_serialization: Task::ready(None),
|
||||||
message_editor: input_editor,
|
message_editor: input_editor,
|
||||||
local_timezone: cx.local_timezone(),
|
local_timezone: UtcOffset::from_whole_seconds(local_offset).unwrap(),
|
||||||
subscriptions: Vec::new(),
|
subscriptions: Vec::new(),
|
||||||
is_scrolled_to_bottom: true,
|
is_scrolled_to_bottom: true,
|
||||||
active: false,
|
active: false,
|
||||||
|
@ -127,11 +127,12 @@ impl NotificationPanel {
|
|||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let local_offset = chrono::Local::now().offset().local_minus_utc();
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
fs,
|
fs,
|
||||||
client,
|
client,
|
||||||
user_store,
|
user_store,
|
||||||
local_timezone: cx.local_timezone(),
|
local_timezone: UtcOffset::from_whole_seconds(local_offset).unwrap(),
|
||||||
channel_store: ChannelStore::global(cx),
|
channel_store: ChannelStore::global(cx),
|
||||||
notification_store: NotificationStore::global(cx),
|
notification_store: NotificationStore::global(cx),
|
||||||
notification_list,
|
notification_list,
|
||||||
|
@ -31,6 +31,7 @@ test-support = [
|
|||||||
aho-corasick = "1.1"
|
aho-corasick = "1.1"
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
assets.workspace = true
|
assets.workspace = true
|
||||||
|
chrono.workspace = true
|
||||||
client.workspace = true
|
client.workspace = true
|
||||||
clock.workspace = true
|
clock.workspace = true
|
||||||
collections.workspace = true
|
collections.workspace = true
|
||||||
|
@ -8,6 +8,7 @@ use gpui::{
|
|||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use theme::{ActiveTheme, ThemeSettings};
|
use theme::{ActiveTheme, ThemeSettings};
|
||||||
|
use time::UtcOffset;
|
||||||
use ui::{
|
use ui::{
|
||||||
div, h_flex, tooltip_container, v_flex, Avatar, Button, ButtonStyle, Clickable as _, Color,
|
div, h_flex, tooltip_container, v_flex, Avatar, Button, ButtonStyle, Clickable as _, Color,
|
||||||
FluentBuilder, Icon, IconName, IconPosition, InteractiveElement as _, IntoElement,
|
FluentBuilder, Icon, IconName, IconPosition, InteractiveElement as _, IntoElement,
|
||||||
@ -129,7 +130,7 @@ impl Render for BlameEntryTooltip {
|
|||||||
let author_email = self.blame_entry.author_mail.clone();
|
let author_email = self.blame_entry.author_mail.clone();
|
||||||
|
|
||||||
let short_commit_id = self.blame_entry.sha.display_short();
|
let short_commit_id = self.blame_entry.sha.display_short();
|
||||||
let absolute_timestamp = blame_entry_absolute_timestamp(&self.blame_entry, cx);
|
let absolute_timestamp = blame_entry_absolute_timestamp(&self.blame_entry);
|
||||||
|
|
||||||
let message = self
|
let message = self
|
||||||
.details
|
.details
|
||||||
@ -247,30 +248,25 @@ impl Render for BlameEntryTooltip {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blame_entry_timestamp(
|
fn blame_entry_timestamp(blame_entry: &BlameEntry, format: time_format::TimestampFormat) -> String {
|
||||||
blame_entry: &BlameEntry,
|
|
||||||
format: time_format::TimestampFormat,
|
|
||||||
cx: &WindowContext,
|
|
||||||
) -> String {
|
|
||||||
match blame_entry.author_offset_date_time() {
|
match blame_entry.author_offset_date_time() {
|
||||||
Ok(timestamp) => time_format::format_localized_timestamp(
|
Ok(timestamp) => {
|
||||||
timestamp,
|
let local = chrono::Local::now().offset().local_minus_utc();
|
||||||
time::OffsetDateTime::now_utc(),
|
time_format::format_localized_timestamp(
|
||||||
cx.local_timezone(),
|
timestamp,
|
||||||
format,
|
time::OffsetDateTime::now_utc(),
|
||||||
),
|
UtcOffset::from_whole_seconds(local).unwrap(),
|
||||||
|
format,
|
||||||
|
)
|
||||||
|
}
|
||||||
Err(_) => "Error parsing date".to_string(),
|
Err(_) => "Error parsing date".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blame_entry_relative_timestamp(blame_entry: &BlameEntry, cx: &WindowContext) -> String {
|
pub fn blame_entry_relative_timestamp(blame_entry: &BlameEntry) -> String {
|
||||||
blame_entry_timestamp(blame_entry, time_format::TimestampFormat::Relative, cx)
|
blame_entry_timestamp(blame_entry, time_format::TimestampFormat::Relative)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blame_entry_absolute_timestamp(blame_entry: &BlameEntry, cx: &WindowContext) -> String {
|
fn blame_entry_absolute_timestamp(blame_entry: &BlameEntry) -> String {
|
||||||
blame_entry_timestamp(
|
blame_entry_timestamp(blame_entry, time_format::TimestampFormat::MediumAbsolute)
|
||||||
blame_entry,
|
|
||||||
time_format::TimestampFormat::MediumAbsolute,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
@ -3923,7 +3923,7 @@ fn render_inline_blame_entry(
|
|||||||
workspace: Option<WeakView<Workspace>>,
|
workspace: Option<WeakView<Workspace>>,
|
||||||
cx: &mut WindowContext<'_>,
|
cx: &mut WindowContext<'_>,
|
||||||
) -> AnyElement {
|
) -> AnyElement {
|
||||||
let relative_timestamp = blame_entry_relative_timestamp(&blame_entry, cx);
|
let relative_timestamp = blame_entry_relative_timestamp(&blame_entry);
|
||||||
|
|
||||||
let author = blame_entry.author.as_deref().unwrap_or_default();
|
let author = blame_entry.author.as_deref().unwrap_or_default();
|
||||||
let text = format!("{}, {}", author, relative_timestamp);
|
let text = format!("{}, {}", author, relative_timestamp);
|
||||||
@ -3969,7 +3969,7 @@ fn render_blame_entry(
|
|||||||
};
|
};
|
||||||
last_used_color.replace((sha_color, blame_entry.sha));
|
last_used_color.replace((sha_color, blame_entry.sha));
|
||||||
|
|
||||||
let relative_timestamp = blame_entry_relative_timestamp(&blame_entry, cx);
|
let relative_timestamp = blame_entry_relative_timestamp(&blame_entry);
|
||||||
|
|
||||||
let short_commit_id = blame_entry.sha.display_short();
|
let short_commit_id = blame_entry.sha.display_short();
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ use derive_more::{Deref, DerefMut};
|
|||||||
use futures::{channel::oneshot, future::LocalBoxFuture, Future};
|
use futures::{channel::oneshot, future::LocalBoxFuture, Future};
|
||||||
use slotmap::SlotMap;
|
use slotmap::SlotMap;
|
||||||
use smol::future::FutureExt;
|
use smol::future::FutureExt;
|
||||||
use time::UtcOffset;
|
|
||||||
|
|
||||||
pub use async_context::*;
|
pub use async_context::*;
|
||||||
use collections::{FxHashMap, FxHashSet, VecDeque};
|
use collections::{FxHashMap, FxHashSet, VecDeque};
|
||||||
@ -647,11 +646,6 @@ impl AppContext {
|
|||||||
self.platform.restart(binary_path)
|
self.platform.restart(binary_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the local timezone at the platform level.
|
|
||||||
pub fn local_timezone(&self) -> UtcOffset {
|
|
||||||
self.platform.local_timezone()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates the http client assigned to GPUI
|
/// Updates the http client assigned to GPUI
|
||||||
pub fn update_http_client(&mut self, new_client: Arc<dyn HttpClient>) {
|
pub fn update_http_client(&mut self, new_client: Arc<dyn HttpClient>) {
|
||||||
self.http_client = new_client;
|
self.http_client = new_client;
|
||||||
|
@ -60,7 +60,6 @@ pub(crate) use mac::*;
|
|||||||
pub use semantic_version::SemanticVersion;
|
pub use semantic_version::SemanticVersion;
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
pub(crate) use test::*;
|
pub(crate) use test::*;
|
||||||
use time::UtcOffset;
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub(crate) use windows::*;
|
pub(crate) use windows::*;
|
||||||
|
|
||||||
@ -159,7 +158,6 @@ pub(crate) trait Platform: 'static {
|
|||||||
""
|
""
|
||||||
}
|
}
|
||||||
fn app_path(&self) -> Result<PathBuf>;
|
fn app_path(&self) -> Result<PathBuf>;
|
||||||
fn local_timezone(&self) -> UtcOffset;
|
|
||||||
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf>;
|
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf>;
|
||||||
|
|
||||||
fn set_cursor_style(&self, style: CursorStyle);
|
fn set_cursor_style(&self, style: CursorStyle);
|
||||||
|
@ -30,7 +30,6 @@ 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 time::UtcOffset;
|
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use wayland_client::Connection;
|
use wayland_client::Connection;
|
||||||
use wayland_protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::Shape;
|
use wayland_protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::Shape;
|
||||||
@ -397,10 +396,6 @@ impl<P: LinuxClient + 'static> Platform for P {
|
|||||||
|
|
||||||
fn set_dock_menu(&self, menu: Vec<MenuItem>, keymap: &Keymap) {}
|
fn set_dock_menu(&self, menu: Vec<MenuItem>, keymap: &Keymap) {}
|
||||||
|
|
||||||
fn local_timezone(&self) -> UtcOffset {
|
|
||||||
UtcOffset::UTC
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
|
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
|
||||||
Err(anyhow::Error::msg(
|
Err(anyhow::Error::msg(
|
||||||
"Platform<LinuxPlatform>::path_for_auxiliary_executable is not implemented yet",
|
"Platform<LinuxPlatform>::path_for_auxiliary_executable is not implemented yet",
|
||||||
|
@ -49,7 +49,6 @@ use std::{
|
|||||||
slice, str,
|
slice, str,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use time::UtcOffset;
|
|
||||||
|
|
||||||
use super::renderer;
|
use super::renderer;
|
||||||
|
|
||||||
@ -760,14 +759,6 @@ impl Platform for MacPlatform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_timezone(&self) -> UtcOffset {
|
|
||||||
unsafe {
|
|
||||||
let local_timezone: id = msg_send![class!(NSTimeZone), localTimeZone];
|
|
||||||
let seconds_from_gmt: NSInteger = msg_send![local_timezone, secondsFromGMT];
|
|
||||||
UtcOffset::from_whole_seconds(seconds_from_gmt.try_into().unwrap()).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
|
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let bundle: id = NSBundle::mainBundle();
|
let bundle: id = NSBundle::mainBundle();
|
||||||
|
@ -257,10 +257,6 @@ impl Platform for TestPlatform {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_timezone(&self) -> time::UtcOffset {
|
|
||||||
time::UtcOffset::UTC
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path_for_auxiliary_executable(&self, _name: &str) -> Result<std::path::PathBuf> {
|
fn path_for_auxiliary_executable(&self, _name: &str) -> Result<std::path::PathBuf> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@ use futures::channel::oneshot::{self, Receiver};
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use time::UtcOffset;
|
|
||||||
use windows::{
|
use windows::{
|
||||||
core::*,
|
core::*,
|
||||||
Win32::{
|
Win32::{
|
||||||
@ -35,7 +34,6 @@ use windows::{
|
|||||||
Ole::*,
|
Ole::*,
|
||||||
SystemInformation::*,
|
SystemInformation::*,
|
||||||
Threading::*,
|
Threading::*,
|
||||||
Time::*,
|
|
||||||
},
|
},
|
||||||
UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},
|
UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},
|
||||||
},
|
},
|
||||||
@ -482,25 +480,6 @@ impl Platform for WindowsPlatform {
|
|||||||
Ok(std::env::current_exe()?)
|
Ok(std::env::current_exe()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_timezone(&self) -> UtcOffset {
|
|
||||||
let mut info = unsafe { std::mem::zeroed() };
|
|
||||||
let ret = unsafe { GetTimeZoneInformation(&mut info) };
|
|
||||||
if ret == TIME_ZONE_ID_INVALID {
|
|
||||||
log::error!(
|
|
||||||
"Unable to get local timezone: {}",
|
|
||||||
std::io::Error::last_os_error()
|
|
||||||
);
|
|
||||||
return UtcOffset::UTC;
|
|
||||||
}
|
|
||||||
// Windows treat offset as:
|
|
||||||
// UTC = localtime + offset
|
|
||||||
// so we add a minus here
|
|
||||||
let hours = -info.Bias / 60;
|
|
||||||
let minutes = -info.Bias % 60;
|
|
||||||
|
|
||||||
UtcOffset::from_hms(hours as _, minutes as _, 0).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo(windows)
|
// todo(windows)
|
||||||
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
|
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
|
||||||
Err(anyhow!("not yet implemented"))
|
Err(anyhow!("not yet implemented"))
|
||||||
|
Loading…
Reference in New Issue
Block a user