feat(reload): reload the active tab with Cmd/Ctrl+R
This commit is contained in:
@@ -38,6 +38,7 @@ actions!(
|
||||
OpenSettings,
|
||||
OpenTaskManager,
|
||||
Quit,
|
||||
ReloadTab,
|
||||
RestoreClosedTab,
|
||||
ResetZoom,
|
||||
SelectNextSpace,
|
||||
@@ -105,6 +106,7 @@ fn main() {
|
||||
MenuItem::action("Zoom Out", ZoomOut),
|
||||
MenuItem::action("Reset Zoom", ResetZoom),
|
||||
MenuItem::separator(),
|
||||
MenuItem::action("Reload Tab", ReloadTab),
|
||||
MenuItem::action("Close Tab", CloseCurrentTab),
|
||||
MenuItem::separator(),
|
||||
MenuItem::action("Restore Closed Tab", RestoreClosedTab),
|
||||
|
||||
@@ -177,6 +177,10 @@ impl ServoLiveClient {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn reload(&mut self, tab_id: String) -> Result<(), ServoLiveError> {
|
||||
self.request(LiveRequest::Reload { tab_id }).map(|_| ())
|
||||
}
|
||||
|
||||
pub fn close(&mut self, tab_id: String) -> Result<(), ServoLiveError> {
|
||||
self.request(LiveRequest::Close { tab_id }).map(|_| ())
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@ pub(super) enum LiveRequest {
|
||||
ready_surface_ids: Vec<u64>,
|
||||
pending_surface_ids: Vec<u64>,
|
||||
},
|
||||
Reload {
|
||||
tab_id: String,
|
||||
},
|
||||
Close {
|
||||
tab_id: String,
|
||||
},
|
||||
|
||||
@@ -119,6 +119,7 @@ impl ElyShell {
|
||||
.on_action(cx.listener(Self::on_open_new_tab))
|
||||
.on_action(cx.listener(Self::on_open_settings))
|
||||
.on_action(cx.listener(Self::on_open_task_manager))
|
||||
.on_action(cx.listener(Self::on_reload_tab))
|
||||
.on_action(cx.listener(Self::on_reset_zoom))
|
||||
.on_action(cx.listener(Self::on_restore_closed_tab))
|
||||
.on_action(cx.listener(Self::on_select_next_space))
|
||||
|
||||
@@ -2,7 +2,7 @@ use gpui::{Context, Window};
|
||||
|
||||
use crate::{
|
||||
CloseCurrentTab, DownloadCurrentPage, FocusAddressBar, FocusCommandMode, OpenDownloads,
|
||||
OpenHistory, OpenNewTab, OpenSettings, OpenTaskManager, ResetZoom, RestoreClosedTab,
|
||||
OpenHistory, OpenNewTab, OpenSettings, OpenTaskManager, ReloadTab, ResetZoom, RestoreClosedTab,
|
||||
SelectNextTab, SelectPreviousTab, ToggleFavoriteTab, TogglePinnedTab, ZoomIn, ZoomOut,
|
||||
};
|
||||
|
||||
@@ -45,6 +45,15 @@ impl ElyShell {
|
||||
self.open_new_tab(window, cx);
|
||||
}
|
||||
|
||||
pub(super) fn on_reload_tab(
|
||||
&mut self,
|
||||
_: &ReloadTab,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.reload_active_tab(window, cx);
|
||||
}
|
||||
|
||||
pub(super) fn on_open_downloads(
|
||||
&mut self,
|
||||
_: &OpenDownloads,
|
||||
|
||||
@@ -20,6 +20,21 @@ impl ElyShell {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reload the active tab: recover it to the ready state in `BrowserCore`
|
||||
/// and, when it hosts a live web surface, tell that surface's Servo
|
||||
/// sidecar to refetch the page.
|
||||
pub(super) fn reload_active_tab(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let ShellState::Ready(core) = &mut self.state else {
|
||||
return;
|
||||
};
|
||||
let Ok(tab_id) = core.reload_active_tab() else {
|
||||
return;
|
||||
};
|
||||
self.web_surfaces.reload_tab(&tab_id);
|
||||
self.sync_address_input(window, cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub(super) fn wake_discarded_tab(
|
||||
&mut self,
|
||||
tab_id: &TabId,
|
||||
|
||||
@@ -353,6 +353,10 @@ impl WebSurfaceStore {
|
||||
self.surfaces.entry(tab_id.clone()).or_insert_with(PerTabSurface::new)
|
||||
}
|
||||
|
||||
pub(super) fn reload_tab(&mut self, tab_id: &TabId) {
|
||||
self.runtime.reload_tab(tab_id);
|
||||
}
|
||||
|
||||
pub(super) fn close_surface(&mut self, tab_id: &TabId) {
|
||||
self.runtime.close_tab(tab_id);
|
||||
self.surfaces.remove(tab_id);
|
||||
|
||||
@@ -78,6 +78,15 @@ impl WebSurfaceRuntime {
|
||||
self.take_retired_permission_consumptions()
|
||||
}
|
||||
|
||||
pub(in crate::shell) fn reload_tab(&mut self, tab_id: &TabId) {
|
||||
let Some(session) = self.sessions.get(tab_id) else {
|
||||
return;
|
||||
};
|
||||
if let Some(scoped) = self.workers.get(&session.scope) {
|
||||
scoped.worker.submit_reload(tab_id.as_str().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::shell) fn close_tab(&mut self, tab_id: &TabId) {
|
||||
let Some(session) = self.sessions.remove(tab_id) else {
|
||||
return;
|
||||
|
||||
@@ -29,6 +29,11 @@ pub(super) trait LiveRuntimeClient {
|
||||
|
||||
fn poll(&mut self, tab_id: String) -> Result<Option<ServoLiveFrame>, LiveRuntimeClientError>;
|
||||
|
||||
fn reload(&mut self, tab_id: String) -> Result<(), LiveRuntimeClientError> {
|
||||
let _ = tab_id;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close(&mut self, tab_id: String) -> Result<(), LiveRuntimeClientError>;
|
||||
|
||||
fn take_permission_consumptions(&mut self) -> Vec<ServoLivePermissionGrant> {
|
||||
@@ -48,6 +53,10 @@ impl LiveRuntimeClient for ServoLiveClient {
|
||||
ServoLiveClient::poll(self, tab_id).map_err(LiveRuntimeClientError::from)
|
||||
}
|
||||
|
||||
fn reload(&mut self, tab_id: String) -> Result<(), LiveRuntimeClientError> {
|
||||
ServoLiveClient::reload(self, tab_id).map_err(LiveRuntimeClientError::from)
|
||||
}
|
||||
|
||||
fn close(&mut self, tab_id: String) -> Result<(), LiveRuntimeClientError> {
|
||||
ServoLiveClient::close(self, tab_id).map_err(LiveRuntimeClientError::from)
|
||||
}
|
||||
@@ -147,6 +156,7 @@ struct WorkerQueue {
|
||||
pending: BTreeMap<String, VecDeque<WorkerRequest>>,
|
||||
/// Round-robin tab order, with each pending tab represented once.
|
||||
ready_tabs: VecDeque<String>,
|
||||
reloads: VecDeque<String>,
|
||||
closes: VecDeque<String>,
|
||||
in_flight: bool,
|
||||
in_flight_tab: Option<String>,
|
||||
@@ -170,6 +180,7 @@ impl LiveRuntimeWorker {
|
||||
Mutex::new(WorkerQueue {
|
||||
pending: BTreeMap::new(),
|
||||
ready_tabs: VecDeque::new(),
|
||||
reloads: VecDeque::new(),
|
||||
closes: VecDeque::new(),
|
||||
in_flight: false,
|
||||
in_flight_tab: None,
|
||||
@@ -264,6 +275,21 @@ impl LiveRuntimeWorker {
|
||||
inserted
|
||||
}
|
||||
|
||||
pub(super) fn submit_reload(&self, tab_id: String) {
|
||||
let (lock, cvar) = &*self.queue;
|
||||
let mut q = match lock.lock() {
|
||||
Ok(guard) => guard,
|
||||
Err(poisoned) => poisoned.into_inner(),
|
||||
};
|
||||
if q.shutdown || q.initialization_failure.is_some() {
|
||||
return;
|
||||
}
|
||||
if !q.reloads.contains(&tab_id) {
|
||||
q.reloads.push_back(tab_id);
|
||||
}
|
||||
cvar.notify_one();
|
||||
}
|
||||
|
||||
pub(super) fn submit_close(&self, tab_id: String) {
|
||||
let (lock, cvar) = &*self.queue;
|
||||
let mut q = match lock.lock() {
|
||||
@@ -278,6 +304,7 @@ impl LiveRuntimeWorker {
|
||||
}
|
||||
q.pending.remove(&tab_id);
|
||||
q.ready_tabs.retain(|ready_tab_id| ready_tab_id != &tab_id);
|
||||
q.reloads.retain(|reload_tab_id| reload_tab_id != &tab_id);
|
||||
q.closes.push_back(tab_id);
|
||||
cvar.notify_one();
|
||||
}
|
||||
@@ -298,7 +325,8 @@ impl LiveRuntimeWorker {
|
||||
Ok(guard) => guard,
|
||||
Err(poisoned) => poisoned.into_inner(),
|
||||
};
|
||||
while !q.pending.is_empty() || !q.closes.is_empty() || q.in_flight {
|
||||
while !q.pending.is_empty() || !q.reloads.is_empty() || !q.closes.is_empty() || q.in_flight
|
||||
{
|
||||
q = match cvar.wait(q) {
|
||||
Ok(guard) => guard,
|
||||
Err(poisoned) => poisoned.into_inner(),
|
||||
@@ -336,6 +364,7 @@ fn fail_worker_initialization(
|
||||
};
|
||||
q.initialization_failure = Some(message.clone());
|
||||
q.ready_tabs.clear();
|
||||
q.reloads.clear();
|
||||
q.closes.clear();
|
||||
q.in_flight = false;
|
||||
q.in_flight_tab = None;
|
||||
@@ -368,7 +397,8 @@ fn run_worker(
|
||||
q.in_flight = false;
|
||||
q.in_flight_tab = None;
|
||||
cvar.notify_all();
|
||||
while q.pending.is_empty() && q.closes.is_empty() && !q.shutdown {
|
||||
while q.pending.is_empty() && q.reloads.is_empty() && q.closes.is_empty() && !q.shutdown
|
||||
{
|
||||
q = match cvar.wait(q) {
|
||||
Ok(guard) => guard,
|
||||
Err(poisoned) => poisoned.into_inner(),
|
||||
@@ -379,6 +409,8 @@ fn run_worker(
|
||||
}
|
||||
let next = if let Some(close_id) = q.closes.pop_front() {
|
||||
Work::Close(close_id)
|
||||
} else if let Some(reload_id) = q.reloads.pop_front() {
|
||||
Work::Reload(reload_id)
|
||||
} else {
|
||||
if q.ready_tabs.len() > 1
|
||||
&& q.ready_tabs.front() == last_dispatched_tab.as_ref()
|
||||
@@ -407,7 +439,7 @@ fn run_worker(
|
||||
};
|
||||
q.in_flight = true;
|
||||
q.in_flight_tab = match &next {
|
||||
Work::Close(_) => None,
|
||||
Work::Close(_) | Work::Reload(_) => None,
|
||||
Work::Request(request) => Some(request.tab_id().to_string()),
|
||||
};
|
||||
next
|
||||
@@ -419,6 +451,11 @@ fn run_worker(
|
||||
forward_permission_consumptions(&mut *client, &response_tx);
|
||||
false
|
||||
}
|
||||
Work::Reload(tab_id) => {
|
||||
let _ = client.reload(tab_id);
|
||||
forward_permission_consumptions(&mut *client, &response_tx);
|
||||
false
|
||||
}
|
||||
Work::Request(WorkerRequest::Ensure { generation, mut request }) => {
|
||||
let tab_id = request.tab_id.clone();
|
||||
let allow_once_grants = std::mem::take(&mut request.allow_once_grants);
|
||||
@@ -454,6 +491,7 @@ fn run_worker(
|
||||
|
||||
enum Work {
|
||||
Close(String),
|
||||
Reload(String),
|
||||
Request(WorkerRequest),
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ pub(crate) use profile::{
|
||||
|
||||
use crate::{
|
||||
CloseCurrentTab, FocusAddressBar, FocusCommandMode, OpenDownloads, OpenHistory, OpenNewTab,
|
||||
OpenPrivateWindow, OpenSettings, OpenTaskManager, Quit, ResetZoom, RestoreClosedTab,
|
||||
OpenPrivateWindow, OpenSettings, OpenTaskManager, Quit, ReloadTab, ResetZoom, RestoreClosedTab,
|
||||
SelectNextSpace, SelectNextTab, SelectPreviousSpace, SelectPreviousTab, SplitRight,
|
||||
ToggleFavoriteTab, ToggleSidebar, ZoomIn, ZoomOut,
|
||||
};
|
||||
@@ -39,6 +39,7 @@ pub(crate) enum ShortcutAction {
|
||||
OpenNewTab,
|
||||
OpenPrivateWindow,
|
||||
CloseCurrentTab,
|
||||
ReloadTab,
|
||||
RestoreClosedTab,
|
||||
SelectNextSpace,
|
||||
SelectPreviousSpace,
|
||||
@@ -65,6 +66,7 @@ impl ShortcutAction {
|
||||
Self::OpenNewTab => "New Tab",
|
||||
Self::OpenPrivateWindow => "New Private Window",
|
||||
Self::CloseCurrentTab => "Close Tab",
|
||||
Self::ReloadTab => "Reload Tab",
|
||||
Self::RestoreClosedTab => "Restore Closed Tab",
|
||||
Self::SelectNextSpace => "Next Space",
|
||||
Self::SelectPreviousSpace => "Previous Space",
|
||||
@@ -90,6 +92,7 @@ impl ShortcutAction {
|
||||
Self::OpenNewTab
|
||||
| Self::OpenPrivateWindow
|
||||
| Self::CloseCurrentTab
|
||||
| Self::ReloadTab
|
||||
| Self::RestoreClosedTab
|
||||
| Self::SelectNextSpace
|
||||
| Self::SelectPreviousSpace
|
||||
@@ -114,6 +117,7 @@ impl ShortcutAction {
|
||||
Self::OpenNewTab => Some(">new-tab"),
|
||||
Self::OpenPrivateWindow => None,
|
||||
Self::CloseCurrentTab => Some(">close-tab"),
|
||||
Self::ReloadTab => None,
|
||||
Self::RestoreClosedTab => Some(">restore-tab"),
|
||||
Self::SelectNextSpace => None,
|
||||
Self::SelectPreviousSpace => None,
|
||||
@@ -168,6 +172,7 @@ pub(crate) const SHORTCUT_ACTIONS: &[ShortcutAction] = &[
|
||||
ShortcutAction::OpenNewTab,
|
||||
ShortcutAction::OpenPrivateWindow,
|
||||
ShortcutAction::CloseCurrentTab,
|
||||
ShortcutAction::ReloadTab,
|
||||
ShortcutAction::RestoreClosedTab,
|
||||
ShortcutAction::SelectNextSpace,
|
||||
ShortcutAction::SelectPreviousSpace,
|
||||
@@ -189,6 +194,8 @@ pub(crate) const SHORTCUT_ACTIONS: &[ShortcutAction] = &[
|
||||
pub(crate) const SHORTCUT_BINDINGS: &[ShortcutBinding] = &[
|
||||
shortcut(ShortcutAction::OpenNewTab, ShortcutPlatform::Macos, "cmd-t"),
|
||||
shortcut(ShortcutAction::OpenNewTab, ShortcutPlatform::WindowsLinux, "ctrl-t"),
|
||||
shortcut(ShortcutAction::ReloadTab, ShortcutPlatform::Macos, "cmd-r"),
|
||||
shortcut(ShortcutAction::ReloadTab, ShortcutPlatform::WindowsLinux, "ctrl-r"),
|
||||
shortcut(ShortcutAction::OpenPrivateWindow, ShortcutPlatform::Macos, "cmd-shift-n"),
|
||||
shortcut(ShortcutAction::OpenPrivateWindow, ShortcutPlatform::WindowsLinux, "ctrl-shift-n"),
|
||||
shortcut(ShortcutAction::SplitRight, ShortcutPlatform::Macos, "cmd-\\"),
|
||||
@@ -278,6 +285,7 @@ pub(crate) fn key_binding_for_action(action: ShortcutAction, keystroke: &str) ->
|
||||
ShortcutAction::OpenSettings => KeyBinding::new(keystroke, OpenSettings, None),
|
||||
ShortcutAction::OpenTaskManager => KeyBinding::new(keystroke, OpenTaskManager, None),
|
||||
ShortcutAction::Quit => KeyBinding::new(keystroke, Quit, None),
|
||||
ShortcutAction::ReloadTab => KeyBinding::new(keystroke, ReloadTab, None),
|
||||
ShortcutAction::ResetZoom => KeyBinding::new(keystroke, ResetZoom, None),
|
||||
ShortcutAction::RestoreClosedTab => KeyBinding::new(keystroke, RestoreClosedTab, None),
|
||||
ShortcutAction::SelectNextSpace => KeyBinding::new(keystroke, SelectNextSpace, None),
|
||||
|
||||
Reference in New Issue
Block a user