Merge branch 'master' into simple_mode

This commit is contained in:
Clement Tsang 2020-03-04 23:47:53 -05:00 committed by GitHub
commit fee8b5c8a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 346 additions and 28 deletions

View File

@ -20,6 +20,14 @@ _Remove the irrelevant one:_
_Please state how this was tested:_
_Please tick which platforms this change was tested on:_
- [ ] Windows
- [ ] macOS
- [ ] Linux
## Checklist
_Please ensure all are ticked (and actually done):_

View File

@ -134,7 +134,7 @@ Run using `btm`.
- `-s`, `--show_disabled_data` will show data entries in the graph legends even if the lines for that entry are disabled.
- `-C`, `--config` takes in a file path leading to a TOML file.
- `-C`, `--config` takes in a file path leading to a TOML file. If doesn't exist, creates one.
- `-b`, `--basic` will enable basic mode, removing all graphs from the main interface and condensing data.

View File

@ -38,7 +38,7 @@ Note some colours may not be compatible with the terminal you are using. For exa
## Default config locations
bottom will check specific locations by default for a config file.
bottom will check specific locations by default for a config file. If no file is found, it will be created.
- For Unix-based systems: `$HOME/.config/bottom/bottom.toml`.
- For Windows: `{FOLDERID_RoamingAppData}\bottom\bottom.toml` (for example, `C:\Users\Clement\AppData\Roaming\bottom\bottom.toml`).

View File

@ -56,3 +56,95 @@ pub const SEARCH_HELP_TEXT: [&str; 13] = [
"Alt-w/F2 Toggle whether to match the whole word\n",
"Alt-r/F3 Toggle whether to use regex\n",
];
pub const DEFAULT_CONFIG_CONTENT: &str = r##"
# This is a default config file for bottom. All of the settings are commented
# out by default; if you wish to change them uncomment and modify as you see
# fit.
# This group of options represents a command-line flag/option. Flags explicitly
# added when running (ie: btm -a) will override this config file if an option
# is also set here.
[flags]
#avg_cpu = true
#dot_marker = false
#rate = 1000
#left_legend = false
#current_usage = false
#group_processes = false
#case_sensitive = false
#whole_word = true
#regex = true
#show_disabled_data = true
# Defaults to Celsius. Temperature is one of:
#temperature_type = "k"
#temperature_type = "f"
#temperature_type = "c"
#temperature_type = "kelvin"
#temperature_type = "fahrenheit"
#temperature_type = "celsius"
# Defaults to processes. Default widget is one of:
#default_widget = "cpu_default"
#default_widget = "memory_default"
#default_widget = "disk_default"
#default_widget = "temperature_default"
#default_widget = "network_default"
#default_widget = "process_default"
# These are all the components that support custom theming. Currently, it only
# supports taking in a string representing a hex colour. Note that colour support
# will, at the end of the day, depend on terminal support - for example, the
# macOS default Terminal does NOT like custom colours and it will glitch out.
#
# The default options here are based on gruvbox: https://github.com/morhetz/gruvbox
[colors]
# Represents the colour of table headers (processes, CPU, disks, temperature).
#table_header_color="#458588"
# Represents the colour of the label each widget has.
#widget_title_color="#cc241d"
# Represents the average CPU color
#avg_cpu_color="#d3869b"
# Represents the colour the core will use in the CPU legend and graph.
#cpu_core_colors=["#cc241d", "#98971a"]
# Represents the colour RAM will use in the memory legend and graph.
#ram_color="#fb4934"
# Represents the colour SWAP will use in the memory legend and graph.
#swap_color="#fabd2f"
# Represents the colour rx will use in the network legend and graph.
#rx_color="#458588"
# Represents the colour tx will use in the network legend and graph.
#tx_color="#689d6a"
# Represents the colour of the border of unselected widgets.
#border_color="#ebdbb2"
# Represents the colour of the border of selected widgets.
#highlighted_border_color="#fe8019"
# Represents the colour of most text.
#text_color="#ebdbb2"
# Represents the colour of text that is selected.
#selected_text_color="#282828"
# Represents the background colour of text that is selected.
#selected_bg_color="#458588"
# Represents the colour of the lines and text of the graph.
#graph_color="#ebdbb2"
# Represents the cursor's colour.
#cursor_color="#458588"
"##;

View File

@ -6,7 +6,7 @@ extern crate clap;
extern crate futures;
#[macro_use]
extern crate lazy_static;
#[macro_use]
#[macro_use]CEvent
extern crate log;
use std::{
@ -79,7 +79,7 @@ fn get_matches() -> clap::ArgMatches<'static> {
(@arg RATE_MILLIS: -r --rate +takes_value "Sets a refresh rate in milliseconds; the minimum is 250ms, defaults to 1000ms. Smaller values may take more resources.")
(@arg LEFT_LEGEND: -l --left_legend "Puts external chart legends on the left side rather than the default right side.")
(@arg USE_CURR_USAGE: -u --current_usage "Within Linux, sets a process' CPU usage to be based on the total current CPU usage, rather than assuming 100% usage.")
(@arg CONFIG_LOCATION: -C --config +takes_value "Sets the location of the config file. Expects a config file in the TOML format.")
(@arg CONFIG_LOCATION: -C --config +takes_value "Sets the location of the config file. Expects a config file in the TOML format. If it doesn't exist, one is created.")
(@arg BASIC_MODE: -b --basic "Hides graphs and uses a more basic look")
(@arg GROUP_PROCESSES: -g --group "Groups processes with the same name together on launch.")
(@arg CASE_SENSITIVE: -S --case_sensitive "Match case when searching by default.")
@ -392,32 +392,250 @@ fn create_logger() -> error::Result<()> {
}
fn create_config(flag_config_location: Option<&str>) -> error::Result<Config> {
use std::ffi::OsString;
let config_path = if let Some(conf_loc) = flag_config_location {
OsString::from(conf_loc)
} else if cfg!(target_os = "windows") {
if let Some(home_path) = dirs::config_dir() {
let mut path = home_path;
path.push(DEFAULT_WINDOWS_CONFIG_FILE_PATH);
path.into_os_string()
} else {
OsString::new()
}
} else if let Some(home_path) = dirs::home_dir() {
let mut path = home_path;
path.push(DEFAULT_UNIX_CONFIG_FILE_PATH);
path.into_os_string()
} else {
OsString::new()
};
use std::{ffi::OsString, fs};
let config_path = if let Some(conf_loc) = flag_config_location {
OsString::from(conf_loc)
} else if cfg!(target_os = "windows") {
if let Some(home_path) = dirs::config_dir() {
let mut path = home_path;
path.push(DEFAULT_WINDOWS_CONFIG_FILE_PATH);
path.into_os_string()
} else {
OsString::new()
}
} else if let Some(home_path) = dirs::home_dir() {
let mut path = home_path;
path.push(DEFAULT_UNIX_CONFIG_FILE_PATH);
path.into_os_string()
} else {
OsString::new()
};
let path = std::path::Path::new(&config_path);
let path = std::path::Path::new(&config_path);
if let Ok(config_str) = std::fs::read_to_string(path) {
Ok(toml::from_str(config_str.as_str())?)
} else {
Ok(Config::default())
}
if let Ok(config_string) = fs::read_to_string(path) {
Ok(toml::from_str(config_string.as_str())?)
} else {
if let Some(parent_path) = path.parent() {
fs::create_dir_all(parent_path)?;
}
fs::File::create(path)?.write_all(DEFAULT_CONFIG_CONTENT.as_bytes())?;
Ok(toml::from_str(DEFAULT_CONFIG_CONTENT)?)
}
}
fn get_update_rate_in_milliseconds(
update_rate: &Option<&str>, config: &Config,
) -> error::Result<u128> {
let update_rate_in_milliseconds = if let Some(update_rate) = update_rate {
update_rate.parse::<u128>()?
} else if let Some(flags) = &config.flags {
if let Some(rate) = flags.rate {
rate as u128
} else {
constants::DEFAULT_REFRESH_RATE_IN_MILLISECONDS
}
} else {
constants::DEFAULT_REFRESH_RATE_IN_MILLISECONDS
};
if update_rate_in_milliseconds < 250 {
return Err(BottomError::InvalidArg(
"Please set your update rate to be greater than 250 milliseconds.".to_string(),
));
} else if update_rate_in_milliseconds > u128::from(std::u64::MAX) {
return Err(BottomError::InvalidArg(
"Please set your update rate to be less than unsigned INT_MAX.".to_string(),
));
}
Ok(update_rate_in_milliseconds)
}
fn get_temperature_option(
matches: &clap::ArgMatches<'static>, config: &Config,
) -> error::Result<data_harvester::temperature::TemperatureType> {
if matches.is_present("FAHRENHEIT") {
return Ok(data_harvester::temperature::TemperatureType::Fahrenheit);
} else if matches.is_present("KELVIN") {
return Ok(data_harvester::temperature::TemperatureType::Kelvin);
} else if matches.is_present("CELSIUS") {
return Ok(data_harvester::temperature::TemperatureType::Celsius);
} else if let Some(flags) = &config.flags {
if let Some(temp_type) = &flags.temperature_type {
// Give lowest priority to config.
return match temp_type.as_str() {
"fahrenheit" | "f" => {
Ok(data_harvester::temperature::TemperatureType::Fahrenheit)
}
"kelvin" | "k" => {
Ok(data_harvester::temperature::TemperatureType::Kelvin)
}
"celsius" | "c" => {
Ok(data_harvester::temperature::TemperatureType::Celsius)
}
_ => {
Err(BottomError::ConfigError(
"Invalid temperature type. Please have the value be of the form \
<kelvin|k|celsius|c|fahrenheit|f>"
.to_string(),
))
}
}
}
}
Ok(data_harvester::temperature::TemperatureType::Celsius)
}
fn get_avg_cpu_option(matches: &clap::ArgMatches<'static>, config: &Config) -> bool {
if matches.is_present("AVG_CPU") {
return true;
} else if let Some(flags) = &config.flags {
if let Some(avg_cpu) = flags.avg_cpu {
return avg_cpu;
}
}
false
}
fn get_use_dot_option(matches: &clap::ArgMatches<'static>, config: &Config) -> bool {
if matches.is_present("DOT_MARKER") {
return true;
} else if let Some(flags) = &config.flags {
if let Some(dot_marker) = flags.dot_marker {
return dot_marker;
}
}
false
}
fn get_use_left_legend_option(matches: &clap::ArgMatches<'static>, config: &Config) -> bool {
if matches.is_present("LEFT_LEGEND") {
return true;
} else if let Some(flags) = &config.flags {
if let Some(left_legend) = flags.left_legend {
return left_legend;
}
}
false
}
fn get_use_current_cpu_total_option(matches: &clap::ArgMatches<'static>, config: &Config) -> bool {
if matches.is_present("USE_CURR_USAGE") {
return true;
} else if let Some(flags) = &config.flags {
if let Some(current_usage) = flags.current_usage {
return current_usage;
}
}
false
}
fn get_show_disabled_data_option(matches: &clap::ArgMatches<'static>, config: &Config) -> bool {
if matches.is_present("SHOW_DISABLED_DATA") {
return true;
} else if let Some(flags) = &config.flags {
if let Some(show_disabled_data) = flags.show_disabled_data {
return show_disabled_data;
}
}
false
}
fn enable_app_grouping(matches: &clap::ArgMatches<'static>, config: &Config, app: &mut App) {
if matches.is_present("GROUP_PROCESSES") {
app.toggle_grouping();
} else if let Some(flags) = &config.flags {
if let Some(grouping) = flags.group_processes {
if grouping {
app.toggle_grouping();
}
}
}
}
fn enable_app_case_sensitive(matches: &clap::ArgMatches<'static>, config: &Config, app: &mut App) {
if matches.is_present("CASE_SENSITIVE") {
app.process_search_state.search_toggle_ignore_case();
} else if let Some(flags) = &config.flags {
if let Some(case_sensitive) = flags.case_sensitive {
if case_sensitive {
app.process_search_state.search_toggle_ignore_case();
}
}
}
}
fn enable_app_match_whole_word(
matches: &clap::ArgMatches<'static>, config: &Config, app: &mut App,
) {
if matches.is_present("WHOLE_WORD") {
app.process_search_state.search_toggle_whole_word();
} else if let Some(flags) = &config.flags {
if let Some(whole_word) = flags.whole_word {
if whole_word {
app.process_search_state.search_toggle_whole_word();
}
}
}
}
fn enable_app_use_regex(matches: &clap::ArgMatches<'static>, config: &Config, app: &mut App) {
if matches.is_present("REGEX_DEFAULT") {
app.process_search_state.search_toggle_regex();
} else if let Some(flags) = &config.flags {
if let Some(regex) = flags.regex {
if regex {
app.process_search_state.search_toggle_regex();
}
}
}
}
fn get_default_widget(matches: &clap::ArgMatches<'static>, config: &Config) -> app::WidgetPosition {
if matches.is_present("CPU_WIDGET") {
return app::WidgetPosition::Cpu;
} else if matches.is_present("MEM_WIDGET") {
return app::WidgetPosition::Mem;
} else if matches.is_present("DISK_WIDGET") {
return app::WidgetPosition::Disk;
} else if matches.is_present("TEMP_WIDGET") {
return app::WidgetPosition::Temp;
} else if matches.is_present("NET_WIDGET") {
return app::WidgetPosition::Network;
} else if matches.is_present("PROC_WIDGET") {
return app::WidgetPosition::Process;
} else if let Some(flags) = &config.flags {
if let Some(default_widget) = &flags.default_widget {
match default_widget.as_str() {
"cpu_default" => {
return app::WidgetPosition::Cpu;
}
"memory_default" => {
return app::WidgetPosition::Mem;
}
"processes_default" => {
return app::WidgetPosition::Process;
}
"network_default" => {
return app::WidgetPosition::Network;
}
"temperature_default" => {
return app::WidgetPosition::Temp;
}
"disk_default" => {
return app::WidgetPosition::Disk;
}
_ => {}
}
}
}
app::WidgetPosition::Process
}
fn try_drawing(