Skip to content

Commit e24e9b5

Browse files
Optionally restore last session on start
Closes: #534 This patch adds a config option to restore closed sessions on start. So, if a user had three tabs opened, all three tabs would be restored when Files is launched again. Updates ------- * Searches and mounts aren't serialized anymore. I'm not sure if it makes sense to do so, but likely a user would raise an issue if they want it.
1 parent 2b4a14d commit e24e9b5

File tree

5 files changed

+111
-36
lines changed

5 files changed

+111
-36
lines changed

i18n/en/cosmic_files.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ match-desktop = Match desktop
197197
dark = Dark
198198
light = Light
199199
200+
### Session
201+
session = Session
202+
restore-session = Restore previous session on start
203+
200204
# Context menu
201205
add-to-sidebar = Add to sidebar
202206
compress = Compress

src/app.rs

+79-25
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ use wayland_client::{protocol::wl_output::WlOutput, Proxy};
5858

5959
use crate::{
6060
clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste},
61-
config::{AppTheme, Config, DesktopConfig, Favorite, IconSizes, TabConfig},
61+
config::{AppTheme, Config, DesktopConfig, Favorite, IconSizes, SessionConfig, TabConfig},
6262
fl, home_dir,
6363
key_bind::key_binds,
6464
localize::LANGUAGE_SORTER,
@@ -69,7 +69,7 @@ use crate::{
6969
tab::{self, HeadingOptions, ItemMetadata, Location, Tab, HOVER_DURATION},
7070
};
7171

72-
#[derive(Clone, Debug)]
72+
#[derive(Clone, Copy, Debug, PartialEq)]
7373
pub enum Mode {
7474
App,
7575
Desktop,
@@ -303,9 +303,11 @@ pub enum Message {
303303
Rename(Option<Entity>),
304304
ReplaceResult(ReplaceResult),
305305
RestoreFromTrash(Option<Entity>),
306+
SaveSession,
306307
SearchActivate,
307308
SearchClear,
308309
SearchInput(String),
310+
SessionConfig(SessionConfig),
309311
SystemThemeModeChange(cosmic_theme::ThemeMode),
310312
TabActivate(Entity),
311313
TabNext,
@@ -1179,27 +1181,43 @@ impl App {
11791181

11801182
fn settings(&self) -> Element<Message> {
11811183
// TODO: Should dialog be updated here too?
1182-
widget::settings::view_column(vec![widget::settings::section()
1183-
.title(fl!("appearance"))
1184-
.add({
1185-
let app_theme_selected = match self.config.app_theme {
1186-
AppTheme::Dark => 1,
1187-
AppTheme::Light => 2,
1188-
AppTheme::System => 0,
1189-
};
1190-
widget::settings::item::builder(fl!("theme")).control(widget::dropdown(
1191-
&self.app_themes,
1192-
Some(app_theme_selected),
1193-
move |index| {
1194-
Message::AppTheme(match index {
1195-
1 => AppTheme::Dark,
1196-
2 => AppTheme::Light,
1197-
_ => AppTheme::System,
1198-
})
1199-
},
1200-
))
1201-
})
1202-
.into()])
1184+
widget::settings::view_column(vec![
1185+
widget::settings::section()
1186+
.title(fl!("appearance"))
1187+
.add({
1188+
let app_theme_selected = match self.config.app_theme {
1189+
AppTheme::Dark => 1,
1190+
AppTheme::Light => 2,
1191+
AppTheme::System => 0,
1192+
};
1193+
widget::settings::item::builder(fl!("theme")).control(widget::dropdown(
1194+
&self.app_themes,
1195+
Some(app_theme_selected),
1196+
move |index| {
1197+
Message::AppTheme(match index {
1198+
1 => AppTheme::Dark,
1199+
2 => AppTheme::Light,
1200+
_ => AppTheme::System,
1201+
})
1202+
},
1203+
))
1204+
})
1205+
.into(),
1206+
widget::settings::section()
1207+
.title(fl!("session"))
1208+
.add(
1209+
widget::settings::item::builder(fl!("restore-session")).toggler(
1210+
self.config.session.restore,
1211+
move |restore| {
1212+
Message::SessionConfig(SessionConfig {
1213+
restore,
1214+
..Default::default()
1215+
})
1216+
},
1217+
),
1218+
)
1219+
.into(),
1220+
])
12031221
.into()
12041222
}
12051223
}
@@ -2355,6 +2373,35 @@ impl Application for App {
23552373
self.operation(Operation::Restore { paths });
23562374
}
23572375
}
2376+
Message::SaveSession => {
2377+
if self.config.session.restore && self.mode == Mode::App {
2378+
let session = SessionConfig {
2379+
tabs: Some(
2380+
self.tab_model
2381+
.iter()
2382+
.filter_map(|entity| {
2383+
match self
2384+
.tab_model
2385+
.data::<Tab>(entity)
2386+
.map(|tab| &tab.location)
2387+
{
2388+
// Location's serialization implementation skips variants
2389+
// such as mounts
2390+
// However, we'd still clone all Locations here only for
2391+
// some to be skipped, so it's best to avoid the clone
2392+
loc @ Location::Path(_)
2393+
| Location::Recents
2394+
| Location::Trash => Some(loc.clone()),
2395+
_ => None,
2396+
}
2397+
})
2398+
.collect(),
2399+
),
2400+
..self.config.session
2401+
};
2402+
config_set!(session, session);
2403+
}
2404+
}
23582405
Message::SearchActivate => {
23592406
return if self.search_get().is_none() {
23602407
self.search_set(Some(String::new()))
@@ -2368,6 +2415,9 @@ impl Application for App {
23682415
Message::SearchInput(input) => {
23692416
return self.search_set(Some(input));
23702417
}
2418+
Message::SessionConfig(session) => {
2419+
config_set!(session, session);
2420+
}
23712421
Message::SystemThemeModeChange(_theme_mode) => {
23722422
return self.update_config();
23732423
}
@@ -2435,9 +2485,12 @@ impl Application for App {
24352485
// Remove item
24362486
self.tab_model.remove(entity);
24372487

2438-
// If that was the last tab, close window
2488+
// If that was the last tab, close window and serialize empty session if necessary
24392489
if self.tab_model.iter().next().is_none() {
2440-
return window::close(window::Id::MAIN);
2490+
return Command::batch([
2491+
self.update(Message::SaveSession),
2492+
window::close(window::Id::MAIN),
2493+
]);
24412494
}
24422495

24432496
return Command::batch([self.update_title(), self.update_watcher()]);
@@ -2698,6 +2751,7 @@ impl Application for App {
26982751
if let Some(window_id) = self.window_id_opt.take() {
26992752
return Command::batch([
27002753
window::close(window_id),
2754+
self.update(Message::SaveSession),
27012755
Command::perform(async move { message::app(Message::MaybeExit) }, |x| x),
27022756
]);
27032757
}

src/config.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ use cosmic::{
99
};
1010
use serde::{Deserialize, Serialize};
1111

12-
use crate::{app::App, tab::View};
12+
use crate::{
13+
app::App,
14+
tab::{Location, View},
15+
};
1316

1417
pub const CONFIG_VERSION: u64 = 1;
1518

@@ -97,6 +100,7 @@ pub struct Config {
97100
pub favorites: Vec<Favorite>,
98101
pub show_details: bool,
99102
pub tab: TabConfig,
103+
pub session: SessionConfig,
100104
}
101105

102106
impl Config {
@@ -144,6 +148,7 @@ impl Default for Config {
144148
],
145149
show_details: false,
146150
tab: TabConfig::default(),
151+
session: SessionConfig::default(),
147152
}
148153
}
149154
}
@@ -229,3 +234,9 @@ impl IconSizes {
229234
percent!(self.grid, ICON_SIZE_GRID) as _
230235
}
231236
}
237+
238+
#[derive(Clone, Debug, Default, PartialEq, Eq, CosmicConfigEntry, Deserialize, Serialize)]
239+
pub struct SessionConfig {
240+
pub restore: bool,
241+
pub tabs: Option<Vec<Location>>,
242+
}

src/lib.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -96,22 +96,25 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
9696

9797
localize::localize();
9898

99-
let (config_handler, config) = Config::load();
99+
let (config_handler, mut config) = Config::load();
100100

101101
let mut locations = Vec::new();
102102
for arg in env::args().skip(1) {
103-
let location = if &arg == "--trash" {
104-
Location::Trash
105-
} else {
106-
match fs::canonicalize(&arg) {
107-
Ok(absolute) => Location::Path(absolute),
103+
match &*arg {
104+
"--trash" => locations.push(Location::Trash),
105+
// Override session regardless of config
106+
"--no-session" => _ = config.session.tabs.take(),
107+
path => match fs::canonicalize(path) {
108+
Ok(absolute) => locations.push(Location::Path(absolute)),
108109
Err(err) => {
109110
log::warn!("failed to canonicalize {:?}: {}", arg, err);
110111
continue;
111112
}
112-
}
113-
};
114-
locations.push(location);
113+
}
114+
}
115+
}
116+
if let Some(session) = config.session.restore.then(|| config.session.tabs.take()).flatten() {
117+
locations.extend(session);
115118
}
116119

117120
let mut settings = Settings::default();

src/tab.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -861,12 +861,15 @@ pub fn scan_desktop(
861861
items
862862
}
863863

864-
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
864+
#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
865865
pub enum Location {
866+
#[serde(skip)]
866867
Desktop(PathBuf, String, DesktopConfig),
868+
#[serde(skip)]
867869
Network(String, String),
868870
Path(PathBuf),
869871
Recents,
872+
#[serde(skip)]
870873
Search(PathBuf, String, bool, Instant),
871874
Trash,
872875
}

0 commit comments

Comments
 (0)