Skip to content

Commit

Permalink
Simplifying the settings and keybinds systems (#309)
Browse files Browse the repository at this point in the history
  • Loading branch information
cooltexture1 authored Mar 5, 2024
1 parent c27cd44 commit 9647fee
Show file tree
Hide file tree
Showing 15 changed files with 840 additions and 659 deletions.
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

0 comments on commit 9647fee

Please sign in to comment.