Move recents to state

This commit is contained in:
Jeremy Soller 2024-02-23 09:55:31 -07:00
parent 00419fd797
commit e0b7339b35
No known key found for this signature in database
GPG key ID: D02FD439211AF56F
3 changed files with 96 additions and 27 deletions

View file

@ -35,9 +35,6 @@ pub struct Config {
pub font_size: u16,
pub highlight_current_line: bool,
pub line_numbers: bool,
//TODO: move to state?
pub recent_files: VecDeque<PathBuf>,
pub recent_projects: VecDeque<PathBuf>,
pub syntax_theme_dark: String,
pub syntax_theme_light: String,
pub tab_width: u16,
@ -54,8 +51,6 @@ impl Default for Config {
font_size: 14,
highlight_current_line: true,
line_numbers: true,
recent_files: VecDeque::new(),
recent_projects: VecDeque::new(),
syntax_theme_dark: "COSMIC Dark".to_string(),
syntax_theme_light: "COSMIC Light".to_string(),
tab_width: 4,
@ -83,3 +78,18 @@ impl Config {
}
}
}
#[derive(Clone, CosmicConfigEntry, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ConfigState {
pub recent_files: VecDeque<PathBuf>,
pub recent_projects: VecDeque<PathBuf>,
}
impl Default for ConfigState {
fn default() -> Self {
Self {
recent_files: VecDeque::new(),
recent_projects: VecDeque::new(),
}
}
}

View file

@ -31,7 +31,7 @@ use std::{
};
use tokio::time;
use config::{AppTheme, Config, CONFIG_VERSION};
use config::{AppTheme, Config, ConfigState, CONFIG_VERSION};
mod config;
use git::{GitDiff, GitDiffLine, GitRepository, GitStatus, GitStatusKind};
@ -146,6 +146,23 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
};
let (config_state_handler, config_state) =
match cosmic_config::Config::new_state(App::APP_ID, CONFIG_VERSION) {
Ok(config_state_handler) => {
let config_state = ConfigState::get_entry(&config_state_handler).unwrap_or_else(
|(errs, config_state)| {
log::info!("errors loading config_state: {:?}", errs);
config_state
},
);
(Some(config_state_handler), config_state)
}
Err(err) => {
log::error!("failed to create config_state handler: {}", err);
(None, ConfigState::default())
}
};
let mut settings = Settings::default();
settings = settings.theme(config.app_theme.theme());
settings = settings.size_limits(Limits::NONE.min_width(360.0).min_height(180.0));
@ -153,6 +170,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let flags = Flags {
config_handler,
config,
config_state_handler,
config_state,
};
cosmic::app::run::<App>(settings, flags)?;
@ -256,6 +275,8 @@ impl Action {
pub struct Flags {
config_handler: Option<cosmic_config::Config>,
config: Config,
config_state_handler: Option<cosmic_config::Config>,
config_state: ConfigState,
}
#[derive(Debug)]
@ -280,6 +301,7 @@ impl PartialEq for WatcherWrapper {
pub enum Message {
AppTheme(AppTheme),
Config(Config),
ConfigState(ConfigState),
CloseFile,
CloseProject(usize),
Copy,
@ -377,6 +399,8 @@ pub struct App {
tab_model: segmented_button::SingleSelectModel,
config_handler: Option<cosmic_config::Config>,
config: Config,
config_state_handler: Option<cosmic_config::Config>,
config_state: ConfigState,
key_binds: HashMap<KeyBind, Action>,
app_themes: Vec<String>,
font_names: Vec<String>,
@ -488,10 +512,12 @@ impl App {
self.projects.push((name.to_string(), path.to_path_buf()));
// Add to recent projects, ensuring only one entry
self.config.recent_projects.retain(|x| x != path);
self.config.recent_projects.push_front(path.to_path_buf());
self.config.recent_projects.truncate(10);
self.save_config_no_update();
self.config_state.recent_projects.retain(|x| x != path);
self.config_state
.recent_projects
.push_front(path.to_path_buf());
self.config_state.recent_projects.truncate(10);
self.save_config_state();
}
_ => {
log::error!("failed to open project {:?}: not a directory", path);
@ -546,10 +572,12 @@ impl App {
}
// Add to recent files, ensuring only one entry
self.config.recent_files.retain(|x| x != &canonical);
self.config.recent_files.push_front(canonical.to_path_buf());
self.config.recent_files.truncate(10);
self.save_config_no_update();
self.config_state.recent_files.retain(|x| x != &canonical);
self.config_state
.recent_files
.push_front(canonical.to_path_buf());
self.config_state.recent_files.truncate(10);
self.save_config_state();
let mut tab = EditorTab::new(&self.config);
tab.open(canonical);
@ -583,16 +611,20 @@ impl App {
}
fn save_config(&mut self) -> Command<Message> {
self.save_config_no_update();
self.update_config()
}
fn save_config_no_update(&mut self) {
if let Some(ref config_handler) = self.config_handler {
if let Err(err) = self.config.write_entry(config_handler) {
log::error!("failed to save config: {}", err);
}
}
self.update_config()
}
fn save_config_state(&mut self) {
if let Some(ref config_state_handler) = self.config_state_handler {
if let Err(err) = self.config_state.write_entry(config_state_handler) {
log::error!("failed to save config_state: {}", err);
}
}
}
fn update_focus(&self) -> Command<Message> {
@ -1129,6 +1161,8 @@ impl Application for App {
tab_model: segmented_button::Model::builder().build(),
config_handler: flags.config_handler,
config: flags.config,
config_state_handler: flags.config_state_handler,
config_state: flags.config_state,
key_binds: key_binds(),
app_themes,
font_names,
@ -1305,6 +1339,12 @@ impl Application for App {
return self.update_config();
}
}
Message::ConfigState(config_state) => {
if config_state != self.config_state {
log::info!("update config state");
self.config_state = config_state;
}
}
Message::CloseFile => {
return self.update(Message::TabClose(self.tab_model.active()));
}
@ -1629,13 +1669,13 @@ impl Application for App {
}
}
Message::OpenRecentFile(index) => {
if let Some(path) = self.config.recent_files.get(index).cloned() {
if let Some(path) = self.config_state.recent_files.get(index).cloned() {
self.open_tab(Some(path));
return self.update_tab();
}
}
Message::OpenRecentProject(index) => {
if let Some(path) = self.config.recent_projects.get(index).cloned() {
if let Some(path) = self.config_state.recent_projects.get(index).cloned() {
self.open_project(path);
}
}
@ -2088,7 +2128,12 @@ impl Application for App {
}
fn header_start(&self) -> Vec<Element<Message>> {
vec![menu_bar(&self.config, &self.key_binds, &self.projects)]
vec![menu_bar(
&self.config,
&self.config_state,
&self.key_binds,
&self.projects,
)]
}
fn view(&self) -> Element<Message> {
@ -2349,6 +2394,7 @@ impl Application for App {
fn subscription(&self) -> subscription::Subscription<Message> {
struct WatcherSubscription;
struct ConfigSubscription;
struct ConfigStateSubscription;
struct ThemeSubscription;
subscription::Subscription::batch([
@ -2435,6 +2481,18 @@ impl Application for App {
Message::Config(update.config)
}),
cosmic_config::config_state_subscription(
TypeId::of::<ConfigStateSubscription>(),
Self::APP_ID.into(),
CONFIG_VERSION,
)
.map(|update| {
for error in update.errors {
log::error!("error loading config: {error:?}");
}
Message::ConfigState(update.config)
}),
cosmic_config::config_subscription::<_, cosmic_theme::ThemeMode>(
TypeId::of::<ThemeSubscription>(),
cosmic_theme::THEME_MODE_ID.into(),

View file

@ -17,7 +17,7 @@ use cosmic::{
};
use std::{collections::HashMap, path::PathBuf};
use crate::{fl, icon_cache_get, Action, Config, KeyBind, Message};
use crate::{fl, icon_cache_get, Action, Config, ConfigState, KeyBind, Message};
macro_rules! menu_button {
($($x:expr),+ $(,)?) => (
@ -86,6 +86,7 @@ pub fn context_menu<'a>(
pub fn menu_bar<'a>(
config: &Config,
config_state: &ConfigState,
key_binds: &HashMap<KeyBind, Action>,
projects: &Vec<(String, PathBuf)>,
) -> Element<'a, Message> {
@ -161,13 +162,13 @@ pub fn menu_bar<'a>(
path.display().to_string()
};
let mut recent_files = Vec::with_capacity(config.recent_files.len());
for (i, path) in config.recent_files.iter().enumerate() {
let mut recent_files = Vec::with_capacity(config_state.recent_files.len());
for (i, path) in config_state.recent_files.iter().enumerate() {
recent_files.push(menu_item(format_path(path), Action::OpenRecentFile(i)));
}
let mut recent_projects = Vec::with_capacity(config.recent_projects.len());
for (i, path) in config.recent_projects.iter().enumerate() {
let mut recent_projects = Vec::with_capacity(config_state.recent_projects.len());
for (i, path) in config_state.recent_projects.iter().enumerate() {
recent_projects.push(menu_item(format_path(path), Action::OpenRecentProject(i)));
}