Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplifiing the settings and keybinds systems #309

Merged
merged 7 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 0 additions & 30 deletions src/auth.rs

This file was deleted.

287 changes: 41 additions & 246 deletions src/console/mod.rs → src/console.rs
Original file line number Diff line number Diff line change
@@ -1,247 +1,15 @@
// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::paths;

use std::any::Any;
use std::cell::{Ref, RefCell};
use std::collections::HashMap;
use std::fs;
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::marker::PhantomData;
use std::str::FromStr;
use std::sync::Arc;

use crate::format::{Color, Component, ComponentType};
use crate::render;
use crate::ui;
use log::Level;
use parking_lot::Mutex;

const FILTERED_CRATES: &[&str] = &[
//"reqwest", // TODO: needed?
"mime",
];

pub struct CVar<T: Sized + Any + 'static> {
pub name: &'static str,
pub ty: PhantomData<T>,
pub description: &'static str,
pub mutable: bool,
pub serializable: bool,
pub default: &'static dyn Fn() -> T,
}

pub const LOG_LEVEL_TERM: CVar<String> = CVar {
ty: PhantomData,
name: "log_level_term",
description: "log level of messages to log to the terminal",
mutable: false,
serializable: true,
default: &|| "info".to_owned(),
};

pub const LOG_LEVEL_FILE: CVar<String> = CVar {
ty: PhantomData,
name: "log_level_file",
description: "log level of messages to log to the log file",
mutable: false,
serializable: true,
default: &|| "trace".to_owned(),
};

pub fn register_vars(vars: &mut Vars) {
vars.register(LOG_LEVEL_TERM);
vars.register(LOG_LEVEL_FILE);
}

fn log_level_from_str(s: &str, default: log::Level) -> log::Level {
// TODO: no opposite of FromStr in log crate?
use log::Level::*;
match s {
"trace" => Trace,
"debug" => Debug,
"info" => Info,
"warn" => Warn,
"error" => Error,
_ => default,
}
}

impl Var for CVar<i64> {
fn serialize(&self, val: &Box<dyn Any>) -> String {
val.downcast_ref::<i64>().unwrap().to_string()
}

fn deserialize(&self, input: &str) -> Box<dyn Any> {
Box::new(input.parse::<i64>().unwrap())
}

fn description(&self) -> &'static str {
self.description
}

fn can_serialize(&self) -> bool {
self.serializable
}
}

impl Var for CVar<f64> {
fn serialize(&self, val: &Box<dyn Any>) -> String {
val.downcast_ref::<f64>().unwrap().to_string()
}

fn deserialize(&self, input: &str) -> Box<dyn Any> {
Box::new(input.parse::<f64>().unwrap())
}

fn description(&self) -> &'static str {
self.description
}

fn can_serialize(&self) -> bool {
self.serializable
}
}

impl Var for CVar<bool> {
fn serialize(&self, val: &Box<dyn Any>) -> String {
val.downcast_ref::<bool>().unwrap().to_string()
}

fn deserialize(&self, input: &str) -> Box<dyn Any> {
Box::new(input.parse::<bool>().unwrap())
}

fn description(&self) -> &'static str {
self.description
}

fn can_serialize(&self) -> bool {
self.serializable
}
}

impl Var for CVar<String> {
fn serialize(&self, val: &Box<dyn Any>) -> String {
format!("\"{}\"", val.downcast_ref::<String>().unwrap())
}

fn deserialize(&self, input: &str) -> Box<dyn Any> {
Box::new(input[1..input.len() - 1].to_owned())
}

fn description(&self) -> &'static str {
self.description
}
fn can_serialize(&self) -> bool {
self.serializable
}
}

pub trait Var {
fn serialize(&self, val: &Box<dyn Any>) -> String;
fn deserialize(&self, input: &str) -> Box<dyn Any>;
fn description(&self) -> &'static str;
fn can_serialize(&self) -> bool;
}

#[derive(Default)]
pub struct Vars {
names: HashMap<String, &'static str>,
vars: HashMap<&'static str, Box<dyn Var>>,
var_values: HashMap<&'static str, RefCell<Box<dyn Any>>>,
}

impl Vars {
pub fn new() -> Vars {
Default::default()
}

pub fn register<T: Sized + Any>(&mut self, var: CVar<T>)
where
CVar<T>: Var,
{
if self.vars.contains_key(var.name) {
panic!("Key registered twice {}", var.name);
}
self.names.insert(var.name.to_owned(), var.name);
self.var_values
.insert(var.name, RefCell::new(Box::new((var.default)())));
self.vars.insert(var.name, Box::new(var));
}

pub fn get<T: Sized + Any>(&self, var: CVar<T>) -> Ref<T>
where
CVar<T>: Var,
{
// Should never fail
let var = self.var_values.get(var.name).unwrap().borrow();
Ref::map(var, |v| v.downcast_ref::<T>().unwrap())
}

pub fn set<T: Sized + Any>(&self, var: CVar<T>, val: T)
where
CVar<T>: Var,
{
*self.var_values.get(var.name).unwrap().borrow_mut() = Box::new(val);
self.save_config();
}

pub fn load_config(&mut self) {
if let Ok(file) = fs::File::open(paths::get_config_dir().join("conf.cfg")) {
let reader = BufReader::new(file);
for line in reader.lines() {
let line = line.unwrap();
if line.starts_with('#') || line.is_empty() {
continue;
}
let parts = line
.splitn(2, ' ')
.map(|v| v.to_owned())
.collect::<Vec<String>>();
let (name, arg) = (&parts[0], &parts[1]);
if let Some(var_name) = self.names.get(name) {
let var = self.vars.get(var_name).unwrap();
let val = var.deserialize(arg);
if var.can_serialize() {
self.var_values.insert(var_name, RefCell::new(val));
}
}
}
}
}
use crate::format::{Color, Component, ComponentType};
use crate::settings::SettingStore;
use crate::{paths, ui};
use crate::{render, StringSetting};

pub fn save_config(&self) {
let mut file =
BufWriter::new(fs::File::create(paths::get_config_dir().join("conf.cfg")).unwrap());
for (name, var) in &self.vars {
if !var.can_serialize() {
continue;
}
for line in var.description().lines() {
writeln!(file, "# {}", line).unwrap();
}
write!(
file,
"{} {}\n\n",
name,
var.serialize(&self.var_values.get(name).unwrap().borrow())
)
.unwrap();
}
}
}
use std::fs;
use std::io::Write;
use std::str::FromStr;
use std::sync::Arc;

pub struct Console {
history: Vec<Component>,
Expand Down Expand Up @@ -287,9 +55,9 @@ impl Console {
log::Level::from_str(&variable_string).ok()
}

pub fn configure(&mut self, vars: &Vars) {
self.log_level_term = log_level_from_str(&vars.get(LOG_LEVEL_TERM), log::Level::Info);
self.log_level_file = log_level_from_str(&vars.get(LOG_LEVEL_FILE), log::Level::Debug);
pub fn configure(&mut self, settings: &SettingStore) {
self.log_level_term = term_log_level(settings).unwrap_or(Level::Info);
self.log_level_file = file_log_level(settings).unwrap_or(Level::Debug);

for name in ["RUST_LOG", "LOG_LEVEL"].iter() {
if let Some(level) = Console::log_level_from_env(name) {
Expand All @@ -305,15 +73,15 @@ impl Console {
}
}

pub fn is_active(&self) -> bool {
pub fn _is_active(&self) -> bool {
self.active
}

pub fn toggle(&mut self) {
self.active = !self.active;
}

pub fn activate(&mut self) {
pub fn _activate(&mut self) {
self.active = true;
}

Expand Down Expand Up @@ -447,6 +215,33 @@ impl Console {
}
}

fn _log_level_from_str(s: &str) -> Option<log::Level> {
// TODO: no opposite of FromStr in log crate?
use log::Level::*;
match s {
"trace" => Some(Trace),
"debug" => Some(Debug),
"info" => Some(Info),
"warn" => Some(Warn),
"error" => Some(Error),
_ => None,
}
}

fn term_log_level(store: &SettingStore) -> Option<Level> {
let val = store.get_string(StringSetting::LogLevelTerm);
Level::from_str(&val).ok()
}
fn file_log_level(store: &SettingStore) -> Option<Level> {
let val = store.get_string(StringSetting::LogLevelFile);
Level::from_str(&val).ok()
}

const FILTERED_CRATES: &[&str] = &[
//"reqwest", // TODO: needed?
"mime",
];

pub struct ConsoleProxy {
console: Arc<Mutex<Console>>,
}
Expand Down
Loading
Loading