summaryrefslogtreecommitdiffstats
path: root/src/app/session.rs
blob: 8b1853fb8eea9fa536b1dbc292b2f717c4263488 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use std::fs::File;

use serde::Serialize;
use serde_yaml::{Error as YamlError, Value as YamlValue};

use crate::common::SESSION_PATH;
use crate::io::MIN_WIDTH_FOR_DUAL_PANE;
use crate::log_info;

/// Everything about the current session.
/// We keep track of display settings (metadata, dual pane, second pane as preview).
/// Display hidden files is read from args or set to false by default.
/// Since it's specific to a tab, it's not stored here.
///
/// Reads its display values from a session file and updates them when modified.
/// The file is stored at [`crate::common::SESSION_PATH`] which points to `~/.config/fm/session.yaml`.
/// Unreachable or unreadable files are ignored.
///
/// Holds settings about display :
/// - do we display one or two tabs ? Default to true.
/// - do we display files metadata ? Default to true.
/// - do we use to second pane to preview files ? Default to false.
#[derive(Debug, Serialize)]
pub struct Session {
    /// do we display one or two tabs ?
    dual: bool,
    /// do we display all info or only the filenames ?
    metadata: bool,
    /// use the second pane to preview
    preview: bool,
    /// session filepath
    #[serde(skip_serializing)]
    filepath: String,
}

impl Default for Session {
    fn default() -> Self {
        Self {
            dual: true,
            metadata: true,
            preview: false,
            filepath: shellexpand::tilde(SESSION_PATH).to_string(),
        }
    }
}

impl Session {
    /// Creates a new instance of `DisplaySettings`.
    /// Tries to read them from the session file.
    /// Use default value if the file can't be read.
    pub fn new(width: usize) -> Self {
        Self::default().update_from_config(width)
    }

    fn update_from_config(mut self, width: usize) -> Self {
        let Ok(file) = File::open(&self.filepath) else {
            log_info!("Couldn't open file {file}", file = self.filepath);
            return self;
        };
        let Ok(yaml): Result<YamlValue, YamlError> = serde_yaml::from_reader(file) else {
            log_info!(
                "Couldn't parse session from file {file}",
                file = self.filepath
            );
            return self;
        };
        match yaml["dual"] {
            YamlValue::Bool(value) => self.dual = Self::parse_dual_pane(value, width),
            _ => self.dual = true,
        }
        match yaml["metadata"] {
            YamlValue::Bool(value) => self.metadata = value,
            _ => self.metadata = true,
        }
        match yaml["preview"] {
            YamlValue::Bool(value) => self.preview = value,
            _ => self.preview = false,
        }
        self
    }

    fn parse_dual_pane(session_bool: bool, width: usize) -> bool {
        if !Self::display_wide_enough(width) {
            return false;
        }
        session_bool
    }

    /// use two panes ?
    pub fn dual(&self) -> bool {
        self.dual
    }

    /// do we display all info or only the filenames ?
    pub fn metadata(&self) -> bool {
        self.metadata
    }

    /// use the second pane to preview
    pub fn preview(&self) -> bool {
        self.preview
    }

    /// True iff the terminal is wide enough to display two panes
    pub fn display_wide_enough(width: usize) -> bool {
        width >= MIN_WIDTH_FOR_DUAL_PANE
    }

    /// True if we display 2 tabs.
    /// It requires two conditions:
    /// 1. The display should be wide enough, bigger than [`crate::io::MIN_WIDTH_FOR_DUAL_PANE`].
    /// 2. The `dual_tab` setting must be true.
    pub fn use_dual_tab(&self, width: usize) -> bool {
        self.dual && Self::display_wide_enough(width)
    }

    pub fn set_dual(&mut self, dual: bool) {
        self.dual = dual;
        self.update_yaml_file();
    }

    pub fn toggle_dual(&mut self) {
        self.dual = !self.dual;
        self.update_yaml_file();
    }

    pub fn toggle_metadata(&mut self) {
        self.metadata = !self.metadata;
        self.update_yaml_file();
    }

    pub fn toggle_preview(&mut self) {
        self.preview = !self.preview;
        self.update_yaml_file();
    }

    /// Writes itself to the session file.
    /// Does nothing if an error is encountered while creating or writing to the session file.
    fn update_yaml_file(&self) {
        let mut file = match File::create(&self.filepath) {
            Ok(file) => file,
            Err(error) => {
                log_info!(
                    "Couldn't create session {file}. Error: {error:?}",
                    file = self.filepath
                );
                return;
            }
        };
        match serde_yaml::to_writer(&mut file, &self) {
            Ok(()) => (),
            Err(e) => log_info!(
                "Couldn't write config to session {file}. Error: {e:?}",
                file = self.filepath
            ),
        }
    }
}