This can block the main thread too much otherwise Release Notes: - N/A *or* Added/Fixed/Improved ...
Unified · Split
| @@ -2010,7 +2010,7 @@ impl App { · 2009 unmodified lines | ||
| 2010 | 2010 | &self, |
| 2011 | 2011 | menus: Vec<MenuItem>, |
| 2012 | 2012 | entries: Vec<SmallVec<[PathBuf; 2]>>, |
| 2013 | − ) -> Vec<SmallVec<[PathBuf; 2]>> { | |
| 2013 | + ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> { | |
| 2014 | 2014 | self.platform.update_jump_list(menus, entries) |
| 2015 | 2015 | } |
| 2016 | 2016 | |
| @@ -254,8 +254,8 @@ pub(crate) trait Platform: 'static { · 253 unmodified lines | ||
| 254 | 254 | &self, |
| 255 | 255 | _menus: Vec<MenuItem>, |
| 256 | 256 | _entries: Vec<SmallVec<[PathBuf; 2]>>, |
| 257 | − ) -> Vec<SmallVec<[PathBuf; 2]>> { | |
| 258 | − Vec::new() | |
| 257 | + ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> { | |
| 258 | + Task::ready(Vec::new()) | |
| 259 | 259 | } |
| 260 | 260 | fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>); |
| 261 | 261 | fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>); |
| @@ -1,4 +1,4 @@ | ||
| 1 | −use std::path::PathBuf; | |
| 1 | +use std::{path::PathBuf, sync::Arc}; | |
| 2 | 2 | |
| 3 | 3 | use itertools::Itertools; |
| 4 | 4 | use smallvec::SmallVec; |
| @@ -20,25 +20,25 @@ use windows::{ · 15 unmodified lines | ||
| 20 | 20 | core::{GUID, HSTRING, Interface}, |
| 21 | 21 | }; |
| 22 | 22 | |
| 23 | −use crate::{Action, MenuItem}; | |
| 23 | +use crate::{Action, MenuItem, SharedString}; | |
| 24 | 24 | |
| 25 | 25 | pub(crate) struct JumpList { |
| 26 | 26 | pub(crate) dock_menus: Vec<DockMenuItem>, |
| 27 | − pub(crate) recent_workspaces: Vec<SmallVec<[PathBuf; 2]>>, | |
| 27 | + pub(crate) recent_workspaces: Arc<[SmallVec<[PathBuf; 2]>]>, | |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | 30 | impl JumpList { |
| 31 | 31 | pub(crate) fn new() -> Self { |
| 32 | 32 | Self { |
| 33 | − dock_menus: Vec::new(), | |
| 34 | − recent_workspaces: Vec::new(), | |
| 33 | + dock_menus: Vec::default(), | |
| 34 | + recent_workspaces: Arc::default(), | |
| 35 | 35 | } |
| 36 | 36 | } |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | 39 | pub(crate) struct DockMenuItem { |
| 40 | − pub(crate) name: String, | |
| 41 | − pub(crate) description: String, | |
| 40 | + pub(crate) name: SharedString, | |
| 41 | + pub(crate) description: SharedString, | |
| 42 | 42 | pub(crate) action: Box<dyn Action>, |
| 43 | 43 | } |
| 44 | 44 | |
| @@ -46,11 +46,11 @@ impl DockMenuItem { · 1 unmodified line | ||
| 46 | 46 | pub(crate) fn new(item: MenuItem) -> anyhow::Result<Self> { |
| 47 | 47 | match item { |
| 48 | 48 | MenuItem::Action { name, action, .. } => Ok(Self { |
| 49 | − name: name.clone().into(), | |
| 49 | + name: name.clone(), | |
| 50 | 50 | description: if name == "New Window" { |
| 51 | − "Opens a new window".to_string() | |
| 51 | + "Opens a new window".into() | |
| 52 | 52 | } else { |
| 53 | − name.into() | |
| 53 | + name | |
| 54 | 54 | }, |
| 55 | 55 | action, |
| 56 | 56 | }), |
| @@ -62,11 +62,12 @@ impl DockMenuItem { · 5 unmodified lines | ||
| 62 | 62 | // This code is based on the example from Microsoft: |
| 63 | 63 | // https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/winui/shell/appshellintegration/RecipePropertyHandler/RecipePropertyHandler.cpp |
| 64 | 64 | pub(crate) fn update_jump_list( |
| 65 | − jump_list: &JumpList, | |
| 65 | + recent_workspaces: &[SmallVec<[PathBuf; 2]>], | |
| 66 | + dock_menus: &[(SharedString, SharedString)], | |
| 66 | 67 | ) -> anyhow::Result<Vec<SmallVec<[PathBuf; 2]>>> { |
| 67 | 68 | let (list, removed) = create_destination_list()?; |
| 68 | − add_recent_folders(&list, &jump_list.recent_workspaces, removed.as_ref())?; | |
| 69 | − add_dock_menu(&list, &jump_list.dock_menus)?; | |
| 69 | + add_recent_folders(&list, recent_workspaces, removed.as_ref())?; | |
| 70 | + add_dock_menu(&list, dock_menus)?; | |
| 70 | 71 | unsafe { list.CommitList() }?; |
| 71 | 72 | Ok(removed) |
| 72 | 73 | } |
| @@ -110,14 +111,17 @@ fn create_destination_list() -> anyhow::Result<(ICustomDestinationList, Vec<Smal · 37 unmodified lines | ||
| 110 | 111 | Ok((list, removed)) |
| 111 | 112 | } |
| 112 | 113 | |
| 113 | −fn add_dock_menu(list: &ICustomDestinationList, dock_menus: &[DockMenuItem]) -> anyhow::Result<()> { | |
| 114 | +fn add_dock_menu( | |
| 115 | + list: &ICustomDestinationList, | |
| 116 | + dock_menus: &[(SharedString, SharedString)], | |
| 117 | +) -> anyhow::Result<()> { | |
| 114 | 118 | unsafe { |
| 115 | 119 | let tasks: IObjectCollection = |
| 116 | 120 | CoCreateInstance(&EnumerableObjectCollection, None, CLSCTX_INPROC_SERVER)?; |
| 117 | − for (idx, dock_menu) in dock_menus.iter().enumerate() { | |
| 121 | + for (idx, (name, description)) in dock_menus.iter().enumerate() { | |
| 118 | 122 | let argument = HSTRING::from(format!("--dock-action {}", idx)); |
| 119 | − let description = HSTRING::from(dock_menu.description.as_str()); | |
| 120 | − let display = dock_menu.name.as_str(); | |
| 123 | + let description = HSTRING::from(description.as_str()); | |
| 124 | + let display = name.as_str(); | |
| 121 | 125 | let task = create_shell_link(argument, description, None, display)?; |
| 122 | 126 | tasks.AddObject(&task)?; |
| 123 | 127 | } |
| @@ -240,14 +240,25 @@ impl WindowsPlatform { · 239 unmodified lines | ||
| 240 | 240 | } |
| 241 | 241 | }); |
| 242 | 242 | self.inner.state.jump_list.borrow_mut().dock_menus = actions; |
| 243 | − update_jump_list(&self.inner.state.jump_list.borrow()).log_err(); | |
| 243 | + let borrow = self.inner.state.jump_list.borrow(); | |
| 244 | + let dock_menus = borrow | |
| 245 | + .dock_menus | |
| 246 | + .iter() | |
| 247 | + .map(|menu| (menu.name.clone(), menu.description.clone())) | |
| 248 | + .collect::<Vec<_>>(); | |
| 249 | + let recent_workspaces = borrow.recent_workspaces.clone(); | |
| 250 | + self.background_executor | |
| 251 | + .spawn(async move { | |
| 252 | + update_jump_list(&recent_workspaces, &dock_menus).log_err(); | |
| 253 | + }) | |
| 254 | + .detach(); | |
| 244 | 255 | } |
| 245 | 256 | |
| 246 | 257 | fn update_jump_list( |
| 247 | 258 | &self, |
| 248 | 259 | menus: Vec<MenuItem>, |
| 249 | 260 | entries: Vec<SmallVec<[PathBuf; 2]>>, |
| 250 | − ) -> Vec<SmallVec<[PathBuf; 2]>> { | |
| 261 | + ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> { | |
| 251 | 262 | let mut actions = Vec::new(); |
| 252 | 263 | menus.into_iter().for_each(|menu| { |
| 253 | 264 | if let Some(dock_menu) = DockMenuItem::new(menu).log_err() { |
| @@ -256,8 +267,18 @@ impl WindowsPlatform { · 2 unmodified lines | ||
| 256 | 267 | }); |
| 257 | 268 | let mut jump_list = self.inner.state.jump_list.borrow_mut(); |
| 258 | 269 | jump_list.dock_menus = actions; |
| 259 | − jump_list.recent_workspaces = entries; | |
| 260 | − update_jump_list(&jump_list).log_err().unwrap_or_default() | |
| 270 | + jump_list.recent_workspaces = entries.into(); | |
| 271 | + let dock_menus = jump_list | |
| 272 | + .dock_menus | |
| 273 | + .iter() | |
| 274 | + .map(|menu| (menu.name.clone(), menu.description.clone())) | |
| 275 | + .collect::<Vec<_>>(); | |
| 276 | + let recent_workspaces = jump_list.recent_workspaces.clone(); | |
| 277 | + self.background_executor.spawn(async move { | |
| 278 | + update_jump_list(&recent_workspaces, &dock_menus) | |
| 279 | + .log_err() | |
| 280 | + .unwrap_or_default() | |
| 281 | + }) | |
| 261 | 282 | } |
| 262 | 283 | |
| 263 | 284 | fn find_current_active_window(&self) -> Option<HWND> { |
| @@ -760,7 +781,7 @@ impl Platform for WindowsPlatform { · 496 unmodified lines | ||
| 760 | 781 | &self, |
| 761 | 782 | menus: Vec<MenuItem>, |
| 762 | 783 | entries: Vec<SmallVec<[PathBuf; 2]>>, |
| 763 | − ) -> Vec<SmallVec<[PathBuf; 2]>> { | |
| 784 | + ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> { | |
| 764 | 785 | self.update_jump_list(menus, entries) |
| 765 | 786 | } |
| 766 | 787 | } |
| @@ -2,7 +2,7 @@ use std::path::PathBuf; · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | use gpui::{AppContext, Entity, Global, MenuItem}; |
| 4 | 4 | use smallvec::SmallVec; |
| 5 | −use ui::App; | |
| 5 | +use ui::{App, Context}; | |
| 6 | 6 | use util::{ResultExt, paths::PathExt}; |
| 7 | 7 | |
| 8 | 8 | use crate::{ |
| @@ -71,7 +71,12 @@ impl HistoryManager { · 62 unmodified lines | ||
| 71 | 71 | cx.set_global(GlobalHistoryManager(history_manager)); |
| 72 | 72 | } |
| 73 | 73 | |
| 74 | − pub fn update_history(&mut self, id: WorkspaceId, entry: HistoryManagerEntry, cx: &App) { | |
| 74 | + pub fn update_history( | |
| 75 | + &mut self, | |
| 76 | + id: WorkspaceId, | |
| 77 | + entry: HistoryManagerEntry, | |
| 78 | + cx: &mut Context<'_, HistoryManager>, | |
| 79 | + ) { | |
| 75 | 80 | if let Some(pos) = self.history.iter().position(|e| e.id == id) { |
| 76 | 81 | self.history.remove(pos); |
| 77 | 82 | } |
| @@ -79,7 +84,7 @@ impl HistoryManager { · 1 unmodified line | ||
| 79 | 84 | self.update_jump_list(cx); |
| 80 | 85 | } |
| 81 | 86 | |
| 82 | − pub fn delete_history(&mut self, id: WorkspaceId, cx: &App) { | |
| 87 | + pub fn delete_history(&mut self, id: WorkspaceId, cx: &mut Context<'_, HistoryManager>) { | |
| 83 | 88 | let Some(pos) = self.history.iter().position(|e| e.id == id) else { |
| 84 | 89 | return; |
| 85 | 90 | }; |
| @@ -87,7 +92,7 @@ impl HistoryManager { · 1 unmodified line | ||
| 87 | 92 | self.update_jump_list(cx); |
| 88 | 93 | } |
| 89 | 94 | |
| 90 | − fn update_jump_list(&mut self, cx: &App) { | |
| 95 | + fn update_jump_list(&mut self, cx: &mut Context<'_, HistoryManager>) { | |
| 91 | 96 | let menus = vec![MenuItem::action("New Window", NewWindow)]; |
| 92 | 97 | let entries = self |
| 93 | 98 | .history |
| @@ -96,29 +101,25 @@ impl HistoryManager { · 2 unmodified lines | ||
| 96 | 101 | .map(|entry| entry.path.clone()) |
| 97 | 102 | .collect::<Vec<_>>(); |
| 98 | 103 | let user_removed = cx.update_jump_list(menus, entries); |
| 99 | − self.remove_user_removed_workspaces(user_removed, cx); | |
| 100 | − } | |
| 101 | − | |
| 102 | − pub fn remove_user_removed_workspaces( | |
| 103 | − &mut self, | |
| 104 | − user_removed: Vec<SmallVec<[PathBuf; 2]>>, | |
| 105 | − cx: &App, | |
| 106 | − ) { | |
| 107 | − if user_removed.is_empty() { | |
| 108 | − return; | |
| 109 | − } | |
| 110 | − let mut deleted_ids = Vec::new(); | |
| 111 | − for idx in (0..self.history.len()).rev() { | |
| 112 | − if let Some(entry) = self.history.get(idx) | |
| 113 | − && user_removed.contains(&entry.path) | |
| 114 | − { | |
| 115 | − deleted_ids.push(entry.id); | |
| 116 | − self.history.remove(idx); | |
| 104 | + cx.spawn(async move |this, cx| { | |
| 105 | + let user_removed = user_removed.await; | |
| 106 | + if user_removed.is_empty() { | |
| 107 | + return; | |
| 117 | 108 | } |
| 118 | − } | |
| 119 | − cx.spawn(async move |_| { | |
| 120 | − for id in deleted_ids.iter() { | |
| 121 | − WORKSPACE_DB.delete_workspace_by_id(*id).await.log_err(); | |
| 109 | + let mut deleted_ids = Vec::new(); | |
| 110 | + if let Ok(()) = this.update(cx, |this, _| { | |
| 111 | + for idx in (0..this.history.len()).rev() { | |
| 112 | + if let Some(entry) = this.history.get(idx) | |
| 113 | + && user_removed.contains(&entry.path) | |
| 114 | + { | |
| 115 | + deleted_ids.push(entry.id); | |
| 116 | + this.history.remove(idx); | |
| 117 | + } | |
| 118 | + } | |
| 119 | + }) { | |
| 120 | + for id in deleted_ids.iter() { | |
| 121 | + WORKSPACE_DB.delete_workspace_by_id(*id).await.log_err(); | |
| 122 | + } | |
| 122 | 123 | } |
| 123 | 124 | }) |
| 124 | 125 | .detach(); |