summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraristocratos <gnmjpl@gmail.com>2021-06-19 14:57:27 +0200
committeraristocratos <gnmjpl@gmail.com>2021-06-19 14:57:27 +0200
commitd459d088a0dfb216fc6827a940d8da3f61066ecd (patch)
treed56fd230fa7445b543f388166d3042c8fef28871
parentba481d042cf340542bf642283a25a1faf5ec421b (diff)
File reorganization and more efficient build
-rw-r--r--Makefile68
-rw-r--r--src/btop.cpp (renamed from btop.cpp)104
-rw-r--r--src/btop_config.cpp337
-rw-r--r--src/btop_config.h285
-rw-r--r--src/btop_draw.cpp281
-rw-r--r--src/btop_draw.h222
-rw-r--r--src/btop_input.h9
-rw-r--r--src/btop_linux.cpp411
-rw-r--r--src/btop_linux.h392
-rw-r--r--src/btop_menu.h7
-rw-r--r--src/btop_theme.cpp288
-rw-r--r--src/btop_theme.h262
-rw-r--r--src/btop_tools.cpp432
-rw-r--r--src/btop_tools.h457
14 files changed, 2044 insertions, 1511 deletions
diff --git a/Makefile b/Makefile
index 19265ad..3cf8d31 100644
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,46 @@
PREFIX ?= /usr/local
DOCDIR ?= $(PREFIX)/share/btop/doc
-CPP = g++
-override CPPFLAGS += -std=c++20 -pthread
-OPTFLAG = -O3
-INFOFLAGS += -Wall -Wextra -Wno-stringop-overread -pedantic
-INCLUDES = -Isrc -Iinclude
-btop: btop.cpp
- @mkdir -p bin
- $(CPP) $(CPPFLAGS) $(INCLUDES) $(OPTFLAG) $(INFOFLAGS) -o bin/btop btop.cpp
+#Compiler and Linker
+CXX := g++
+
+#The Target Binary Program
+TARGET := btop
+
+#The Directories, Source, Includes, Objects and Binary
+SRCDIR := src
+INCDIR := include
+BUILDDIR := obj
+TARGETDIR := bin
+SRCEXT := cpp
+DEPEXT := d
+OBJEXT := o
+
+#Flags, Libraries and Includes
+CXXFLAGS := -std=c++20 -pthread -O3 -Wall -Wextra -Wno-stringop-overread -pedantic
+INC := -I$(INCDIR) -I$(SRCDIR)
+
+#---------------------------------------------------------------------------------
+#DO NOT EDIT BELOW THIS LINE
+#---------------------------------------------------------------------------------
+SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
+OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
+
+#Default Make
+all: directories $(TARGET)
+
+#Make the Directories
+directories:
+ @mkdir -p $(TARGETDIR)
+ @mkdir -p $(BUILDDIR)
+
+#Clean only Objecst
+clean:
+ @rm -rf $(BUILDDIR)
+
+#Full Clean, Objects and Binaries
+dist-clean: clean
+ @rm -rf $(TARGETDIR)
install:
@mkdir -p $(DESTDIR)$(PREFIX)/bin
@@ -23,5 +55,21 @@ uninstall:
@rm -rf $(DESTDIR)$(DOCDIR)
@rm -rf $(DESTDIR)$(PREFIX)/share/btop
-clean:
- rm -rf bin
+#Pull in dependency info for *existing* .o files
+-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT))
+
+#Link
+$(TARGET): $(OBJECTS)
+ $(CXX) -o $(TARGETDIR)/$(TARGET) $^
+
+#Compile
+$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
+ $(CXX) $(CXXFLAGS) $(INC) -c -o $@ $<
+ @$(CXX) $(CXXFLAGS) $(INC) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT)
+ @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp
+ @sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT)
+ @sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT)
+ @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp
+
+#Non-File Targets
+.PHONY: all clean dist-clean uninstall
diff --git a/btop.cpp b/src/btop.cpp
index feb15ab..8ed0a60 100644
--- a/btop.cpp
+++ b/src/btop.cpp
@@ -30,19 +30,7 @@ tab-size = 4
#include <filesystem>
#include <unistd.h>
#include <robin_hood.h>
-
-namespace Global {
- const std::vector<std::array<std::string, 2>> Banner_src = {
- {"#E62525", "██████╗ ████████╗ ██████╗ ██████╗"},
- {"#CD2121", "██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗ ██╗ ██╗"},
- {"#B31D1D", "██████╔╝ ██║ ██║ ██║██████╔╝ ██████╗██████╗"},
- {"#9A1919", "██╔══██╗ ██║ ██║ ██║██╔═══╝ ╚═██╔═╝╚═██╔═╝"},
- {"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"},
- {"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"},
- };
- const std::string Version = "0.0.20";
- int coreCount;
-}
+#include <cmath>
#include <btop_tools.h>
#include <btop_config.h>
@@ -71,9 +59,23 @@ namespace Global {
#error Platform not supported!
#endif
+namespace Global {
+ const std::vector<std::array<std::string, 2>> Banner_src = {
+ {"#E62525", "██████╗ ████████╗ ██████╗ ██████╗"},
+ {"#CD2121", "██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗ ██╗ ██╗"},
+ {"#B31D1D", "██████╔╝ ██║ ██║ ██║██████╔╝ ██████╗██████╗"},
+ {"#9A1919", "██╔══██╗ ██║ ██║ ██║██╔═══╝ ╚═██╔═╝╚═██╔═╝"},
+ {"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"},
+ {"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"},
+ };
+ std::string Version = "0.0.21";
+ int coreCount;
+}
+
using std::string, std::vector, std::array, robin_hood::unordered_flat_map, std::atomic, std::endl, std::cout, std::views::iota, std::list, std::accumulate;
-using std::flush, std::endl, std::future, std::string_literals::operator""s, std::future_status;
+using std::flush, std::endl, std::future, std::string_literals::operator""s, std::future_status, std::to_string, std::round;
namespace fs = std::filesystem;
+namespace rng = std::ranges;
using namespace Tools;
@@ -89,6 +91,8 @@ namespace Global {
uint64_t start_time;
bool quitting = false;
+
+ bool arg_tty = false;
}
@@ -102,10 +106,26 @@ void argumentParser(int argc, char **argv){
exit(0);
}
else if (argument == "-h" || argument == "--help") {
- cout << "help here" << endl;
+ cout << "usage: btop [-h] [-v] [-/+t] [--debug]\n\n"
+ << "optional arguments:\n"
+ << " -h, --help show this help message and exit\n"
+ << " -v, --version show version info and exit\n"
+ << " -t, --tty_on force (ON) tty mode, max 16 colors and tty friendly graph symbols\n"
+ << " +t, --tty_off force (OFF) tty mode\n"
+ << " --debug start with loglevel set to DEBUG, overriding value set in config\n"
+ << endl;
exit(0);
}
- else if (argument == "--debug") Global::debug = true;
+ else if (argument == "--debug")
+ Global::debug = true;
+ else if (argument == "-t" || argument == "--tty_on") {
+ Config::set("tty_mode", true);
+ Global::arg_tty = true;
+ }
+ else if (argument == "+t" || argument == "--tty_off") {
+ Config::set("tty_mode", false);
+ Global::arg_tty = true;
+ }
else {
cout << " Unknown argument: " << argument << "\n" <<
" Use -h or --help for help." << endl;
@@ -163,18 +183,21 @@ void banner_gen() {
int bg_i;
Global::banner.clear();
Global::banner_width = 0;
+ auto tty_mode = (Config::getB("tty_mode"));
for (auto line: Global::Banner_src) {
if (auto w = ulen(line[1]); w > Global::banner_width) Global::banner_width = w;
fg = Theme::hex_to_color(line[0], !truecolor);
bg_i = 120-z*12;
bg = Theme::dec_to_color(bg_i, bg_i, bg_i, !truecolor);
for (size_t i = 0; i < line[1].size(); i += 3) {
- if (line[1][i] == ' '){
+ if (line[1][i] == ' ') {
letter = ' ';
i -= 2;
- } else{
- letter = line[1].substr(i, 3);
}
+ else
+ letter = line[1].substr(i, 3);
+
+ if (tty_mode && letter != "█" && letter != " ") letter = "░";
b_color = (letter == "█") ? fg : bg;
if (b_color != oc) Global::banner += b_color;
Global::banner += letter;
@@ -260,10 +283,10 @@ int main(int argc, char **argv){
{ vector<string> load_errors;
Config::load(Config::conf_file, load_errors);
- if (Global::debug) Logger::loglevel = 4;
- else Logger::loglevel = v_index(Logger::log_levels, Config::getS("log_level"));
+ if (Global::debug) Logger::set("DEBUG");
+ else Logger::set(Config::getS("log_level"));
- Logger::info("Log level set to " + Config::getS("log_level") + ".");
+ Logger::debug("Logger set to DEBUG");
for (auto& err_str : load_errors) Logger::warning(err_str);
}
@@ -283,6 +306,17 @@ int main(int argc, char **argv){
clean_quit(1);
}
+ Logger::debug("Running on " + Term::current_tty);
+ if (!Global::arg_tty && Config::getB("force_tty")) {
+ Config::set("tty_mode", true);
+ Logger::info("Forcing tty mode: setting 16 color mode and using tty friendly graph symbols");
+ }
+ else if (!Global::arg_tty && Term::current_tty.starts_with("/dev/tty")) {
+ Config::set("tty_mode", true);
+ Logger::info("Real tty detected, setting 16 color mode and using tty friendly graph symbols");
+ }
+
+
#if defined(LINUX)
//? Linux init
Proc::init();
@@ -329,7 +363,7 @@ int main(int argc, char **argv){
cout << "Colors:" << endl;
uint i = 0;
- for(auto& item : Theme::colors) {
+ for(auto& item : Theme::test_colors()) {
cout << rjust(item.first, 15) << ":" << item.second << "■"s * 10 << Fx::reset << " ";
// << Theme::dec(item.first)[0] << ":" << Theme::dec(item.first)[1] << ":" << Theme::dec(item.first)[2] << ;
if (++i == 4) {
@@ -341,7 +375,7 @@ int main(int argc, char **argv){
cout << "Gradients:";
- for (auto& [name, cvec] : Theme::gradients) {
+ for (auto& [name, cvec] : Theme::test_gradients()) {
cout << endl << rjust(name + ":", 10);
for (auto& color : cvec) {
cout << color << "■";
@@ -388,13 +422,21 @@ int main(int argc, char **argv){
// for (long long i = 100; i >= 0; i--) mydata.push_back(i);
Draw::Graph kgraph {};
- cout << Draw::createBox({.x = 5, .y = 10, .width = Term::width - 10, .height = 12, .line_color = Theme::c("proc_box"), .title = "graph", .fill = false, .num = 7}) << Mv::save << flush;
+ Draw::Graph kgraph2 {};
+ Draw::Graph kgraph3 {};
+
+ cout << Draw::createBox({.x = 5, .y = 10, .width = Term::width - 10, .height = 12, .line_color = Theme::c("proc_box"), .title = "braille", .fill = false, .num = 1}) << Mv::save;
+ cout << Draw::createBox({.x = 5, .y = 23, .width = Term::width - 10, .height = 12, .line_color = Theme::c("proc_box"), .title = "block", .fill = false, .num = 2});
+ cout << Draw::createBox({.x = 5, .y = 36, .width = Term::width - 10, .height = 12, .line_color = Theme::c("proc_box"), .title = "tty", .fill = false, .num = 3}) << flush;
// Draw::Meter kmeter {};
// Draw::Graph kgraph2 {};
// Draw::Graph kgraph3 {};
auto kts = time_micros();
- kgraph(Term::width - 12, 10, "cpu", mydata, false, false);
+ kgraph(Term::width - 12, 10, "cpu", mydata, "braille", false, false);
+ kgraph2(Term::width - 12, 10, "cpu", mydata, "block", false, false);
+ kgraph3(Term::width - 12, 10, "cpu", mydata, "tty", false, false);
+
// kmeter(Term::width - 12, "process");
// cout << Mv::save << kgraph(mydata) << "\n\nInit took " << time_micros() - kts << " μs. " << endl;
@@ -405,7 +447,10 @@ int main(int argc, char **argv){
// cout << kgraph2() << endl;
// exit(0);
- cout << Mv::restore << kgraph(mydata, true) << "\n\n" << Mv::d(1) << "Init took " << time_micros() - kts << " μs. " << endl;
+ cout << Mv::restore << kgraph(mydata, true)
+ << Mv::restore << Mv::d(13) << kgraph2(mydata, true)
+ << Mv::restore << Mv::d(26) << kgraph3(mydata, true) << endl
+ << Mv::d(1) << "Init took " << time_micros() - kts << " μs. " << endl;
// cout << Mv::save << kgraph(mydata, true) << "\n" << kgraph2(mydata, true) << "\n" << kgraph3(mydata, true) << "\n" << kmeter(mydata.back()) << "\n\nInit took " << time_micros() - kts << " μs. " << endl;
// sleep_ms(1000);
// mydata.push_back(50);
@@ -420,7 +465,10 @@ int main(int argc, char **argv){
// mydata.back() = y;
kts = time_micros();
// cout << Mv::restore << " "s * Term::width << "\n" << " "s * Term::width << endl;
- cout << Mv::restore << kgraph(mydata) << endl;
+ cout << Mv::restore << kgraph(mydata)
+ << Mv::restore << Mv::d(13) << kgraph2(mydata)
+ << Mv::restore << Mv::d(26) << kgraph3(mydata)
+ << endl;
// cout << Mv::restore << kgraph(mydata) << "\n" << kgraph2(mydata) << "\n" << " "s * Term::width << Mv::l(Term::width) << kgraph3(mydata) << "\n" << kmeter(mydata.back()) << endl;
ktavg.push_front(time_micros() - kts);
if (ktavg.size() > 100) ktavg.pop_back();
diff --git a/src/btop_config.cpp b/src/btop_config.cpp
new file mode 100644
index 0000000..c250a78
--- /dev/null
+++ b/src/btop_config.cpp
@@ -0,0 +1,337 @@
+/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
+
+ 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.
+
+indent = tab
+tab-size = 4
+*/
+
+#include <array>
+#include <robin_hood.h>
+#include <ranges>
+#include <atomic>
+#include <fstream>
+
+#include <btop_config.h>
+#include <btop_tools.h>
+
+using robin_hood::unordered_flat_map, std::map, std::array, std::atomic;
+namespace fs = std::filesystem;
+namespace rng = std::ranges;
+using namespace Tools;
+
+//* Functions and variables for reading and writing the btop config file
+namespace Config {
+ namespace {
+ atomic<bool> locked (false);
+ atomic<bool> writelock (false);
+ bool write_new;
+
+ vector<array<string, 2>> descriptions = {
+ {"color_theme", "#* Color theme, looks for a .theme file in \"/usr/[local/]share/bpytop/themes\" and \"~/.config/bpytop/themes\", \"Default\" for builtin default theme.\n"
+ "#* Prefix name by a plus sign (+) for a theme located in user themes folder, i.e. color_theme=\"+monokai\"." },
+ {"theme_background", "#* If the theme set background should be shown, set to False if you want terminal background transparency."},
+ {"truecolor", "#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false."},
+ {"graph_symbol", "#* Default symbols to use for graph creation, \"braille\", \"block\" or \"tty\".\n"
+ "#* \"braille\" offers the highest resolution but might not be included in all fonts.\n"
+ "#* \"block\" has half the resolution of braille but uses more common characters.\n"
+ "#* \"tty\" uses only 3 different symbols but will work with most fonts and should work in a real TTY.\n"
+ "#* Note that \"tty\" only has half the horizontal resolution of the other two, so will show a shorter historical view."},
+ {"graph_symbol_cpu", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
+ {"graph_symbol_mem", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
+ {"graph_symbol_net", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
+ {"graph_symbol_proc", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
+ {"force_tty", "#* Set to true to true to force tty mode regardless if a real tty has been detected or not."},
+ {"shown_boxes", "#* Manually set which boxes to show. Available values are \"cpu mem net proc\", separate values with whitespace."},
+ {"update_ms", "#* Update time in milliseconds, increases automatically if set below internal loops processing time, recommended 2000 ms or above for better sample times for graphs."},
+ {"proc_update_mult", "#* Processes update multiplier, sets how often the process list is updated as a multiplier of \"update_ms\".\n"
+ "#* Set to 2 or higher to greatly decrease bpytop cpu usage. (Only integers)."},
+ {"proc_sorting", "#* Processes sorting, \"pid\" \"program\" \"arguments\" \"threads\" \"user\" \"memory\" \"cpu lazy\" \"cpu responsive\",\n"
+ "#* \"cpu lazy\" updates top process over time, \"cpu responsive\" updates top process directly."},
+ {"proc_reversed", "#* Reverse sorting order, True or False."},
+ {"proc_tree", "#* Show processes as a tree."},
+ {"proc_colors", "#* Use the cpu graph colors in the process list."},
+ {"proc_gradient", "#* Use a darkening gradient in the process list."},
+ {"proc_per_core", "#* If process cpu usage should be of the core it's running on or usage of the total available cpu power."},
+ {"proc_mem_bytes", "#* Show process memory as bytes instead of percent."},
+ {"cpu_graph_upper", "#* Sets the CPU stat shown in upper half of the CPU graph, \"total\" is always available.\n"
+ "#* Select from a list of detected attributes from the options menu."},
+ {"cpu_graph_lower", "#* Sets the CPU stat shown in lower half of the CPU graph, \"total\" is always available.\n"
+ "#* Select from a list of detected attributes from the options menu."},
+ {"cpu_invert_lower", "#* Toggles if the lower CPU graph should be inverted."},
+ {"cpu_single_graph", "#* Set to True to completely disable the lower CPU graph."},
+ {"show_uptime", "#* Shows the system uptime in the CPU box."},
+ {"check_temp", "#* Show cpu temperature."},
+ {"cpu_sensor", "#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors."},
+ {"show_coretemp", "#* Show temperatures for cpu cores also if check_temp is True and sensors has been found."},
+ {"temp_scale", "#* Which temperature scale to use, available values: \"celsius\", \"fahrenheit\", \"kelvin\" and \"rankine\"."},
+ {"show_cpu_freq", "#* Show CPU frequency."},
+ {"draw_clock", "#* Draw a clock at top of screen, formatting according to strftime, empty string to disable."},
+ {"background_update", "#* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort."},
+ {"custom_cpu_name", "#* Custom cpu model name, empty string to disable."},
+ {"disks_filter", "#* Optional filter for shown disks, should be full path of a mountpoint, separate multiple values with a comma \",\".\n"
+ "#* Begin line with \"exclude=\" to change to exclude filter, otherwise defaults to \"most include\" filter. Example: disks_filter=\"exclude=/boot, /home/user\"."},
+ {"mem_graphs", "#* Show graphs instead of meters for memory values."},
+ {"show_swap", "#* If swap memory should be shown in memory box."},
+ {"swap_disk", "#* Show swap as a disk, ignores show_swap value above, inserts itself after first disk."},
+ {"show_disks", "#* If mem box should be split to also show disks info."},
+ {"only_physical", "#* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar."},
+ {"use_fstab", "#* Read disks list from /etc/fstab. This also disables only_physical."},
+ {"show_io_stat", "#* Toggles if io stats should be shown in regular disk usage view."},
+ {"io_mode", "#* Toggles io mode for disks, showing only big graphs for disk read/write speeds."},
+ {"io_graph_combined", "#* Set to True to show combined read/write io graphs in io mode."},
+ {"io_graph_speeds", "#* Set the top speed for the io graphs in MiB/s (10 by default), use format \"device:speed\" separate disks with a comma \",\".\n"
+ "#* Example: \"/dev/sda:100, /dev/sdb:20\"."},
+ {"net_download", "#* Set fixed values for network graphs, default \"10M\" = 10 Mibibytes, possible units \"K\", \"M\", \"G\", append with \"bit\" for bits instead of bytes, i.e \"100mbit\"."},
+ {"net_upload", ""},
+ {"net_auto", "#* Start in network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest."},
+ {"net_sync", "#* Sync the scaling for download and upload to whichever currently has the highest scale."},
+ {"net_color_fixed", "#* If the network graphs color gradient should scale to bandwidth usage or auto scale, bandwidth usage is based on \"net_download\" and \"net_upload\" values."},
+ {"net_iface", "#* Starts with the Network Interface specified here."},
+ {"show_battery", "#* Show battery stats in top right if battery is present."},
+ {"log_level", "#* Set loglevel for \"~/.config/bpytop/error.log\" levels are: \"ERROR\" \"WARNING\" \"INFO\" \"DEBUG\".\n"
+ "#* The level set includes all lower levels, i.e. \"DEBUG\" will show all logging info."}
+ };
+
+ unordered_flat_map<string, string> strings = {
+ {"color_theme", "Default"},
+ {"shown_boxes", "cpu mem net proc"},
+ {"graph_symbol", "braille"},
+ {"graph_symbol_cpu", "default"},
+ {"graph_symbol_mem", "default"},
+ {"graph_symbol_net", "default"},
+ {"graph_symbol_proc", "default"},
+ {"proc_sorting", "cpu lazy"},
+ {"cpu_graph_upper", "total"},
+ {"cpu_graph_lower", "total"},
+ {"cpu_sensor", "Auto"},
+ {"temp_scale", "celsius"},
+ {"draw_clock", "%X"},
+ {"custom_cpu_name", ""},
+ {"disks_filter", ""},
+ {"io_graph_speeds", ""},
+ {"net_download", "10M"},
+ {"net_upload", "10M"},
+ {"net_iface", ""},
+ {"log_level", "WARNING"},
+ {"proc_filter", ""}
+ };
+ unordered_flat_map<string, string> stringsTmp;
+
+ unordered_flat_map<string, bool> bools = {
+ {"theme_background", true},
+ {"truecolor", true},
+ {"proc_reversed", false},
+ {"proc_tree", false},
+ {"proc_colors", true},
+ {"proc_gradient", true},
+ {"proc_per_core", false},
+ {"proc_mem_bytes", true},
+ {"cpu_invert_lower", true},
+ {"cpu_single_graph", false},
+ {"show_uptime", true},
+ {"check_temp", true},
+ {"show_coretemp", true},
+ {"show_cpu_freq", true},
+ {"background_update", true},
+ {"mem_graphs", true},
+ {"show_swap", true},
+ {"swap_disk", true},
+ {"show_disks", true},
+ {"only_physical", true},
+ {"use_fstab", false},
+ {"show_io_stat", true},
+ {"io_mode", false},
+ {"io_graph_combined", false},
+ {"net_color_fixed", false},
+ {"net_auto", true},
+ {"net_sync", false},
+ {"show_battery", true},
+ {"tty_mode", false},
+ {"force_tty", false},
+ };
+ unordered_flat_map<string, bool> boolsTmp;
+
+ unordered_flat_map<string, int> ints = {
+ {"update_ms", 2000},
+ {"proc_update_mult", 2},
+ };
+ unordered_flat_map<string, int> intsTmp;
+
+ bool _locked(const string& name){
+ atomic_wait(writelock);
+ if (!write_new && rng::find_if(descriptions, [&name](const auto& a){ return a.at(0) == name; }) != descriptions.end())
+ write_new = true;
+ return locked.load();
+ }
+ }
+
+ fs::path conf_dir;
+ fs::path conf_file;
+
+ vector<string> valid_graph_symbols = { "braille", "block", "tty" };
+
+ //* Return bool config value <name>
+ const bool& getB(string name){
+ return bools.at(name);
+ }
+
+ //* Return integer config value <name>
+ const int& getI(string name){
+ return ints.at(name);
+ }
+
+ //* Return string config value <name>
+ const string& getS(string name){
+ return strings.at(name);
+ }
+
+ //* Set config value <name> to bool <value>
+ void set(string name, bool value){
+ if (_locked(name)) boolsTmp.insert_or_assign(name, value);
+ else bools.at(name) = value;
+ }
+
+ //* Set config value <name> to int <value>
+ void set(string name, int value){
+ if (_locked(name)) intsTmp.insert_or_assign(name, value);
+ ints.at(name) = value;
+ }
+
+ //* Set config value <name> to string <value>
+ void set(string name, string value){
+ if (_locked(name)) stringsTmp.insert_or_assign(name, value);
+ else strings.at(name) = value;
+ }
+
+ //* Flip config bool <name>
+ void flip(string name){
+ if (_locked(name)) {
+ if (boolsTmp.contains(name)) boolsTmp.at(name) = !boolsTmp.at(name);
+ else boolsTmp.insert_or_assign(name, (!bools.at(name)));
+ }
+ else bools.at(name) = !bools.at(name);
+ }
+
+ //* Wait if locked then lock config and cache changes until unlock
+ void lock(){
+ atomic_wait_set(locked);
+ }
+
+ //* Unlock config and write any cached values to config
+ void unlock(){
+ atomic_wait_set(writelock);
+
+ for (auto& item : stringsTmp){
+ strings.at(item.first) = item.second;
+ }
+ stringsTmp.clear();
+
+ for (auto& item : intsTmp){
+ ints.at(item.first) = item.second;
+ }
+ intsTmp.clear();
+
+ for (auto& item : boolsTmp){
+ bools.at(item.first) = item.second;
+ }
+ boolsTmp.clear();
+
+ locked = false;
+ writelock = false;
+ }
+
+ //* Load the config file from disk
+ void load(fs::path conf_file, vector<string>& load_errors){
+ if (conf_file.empty())
+ return;
+ else if (!fs::exists(conf_file)) {
+ write_new = true;
+ return;
+ }
+ std::ifstream cread(conf_file);
+ if (cread.good()) {
+ vector<string> valid_names;
+ for (auto &n : descriptions)
+ valid_names.push_back(n[0]);
+ string v_string;
+ getline(cread, v_string, '\n');
+ if (!v_string.ends_with(Global::Version))
+ write_new = true;
+ while (!cread.eof()) {
+ cread >> std::ws;
+ if (cread.peek() == '#') {
+ cread.ignore(SSmax, '\n');
+ continue;
+ }
+ string name, value;
+ getline(cread, name, '=');
+ if (!v_contains(valid_names, name)) {
+ cread.ignore(SSmax, '\n');
+ continue;
+ }
+
+ if (bools.contains(name)) {
+ cread >> value;
+ if (!isbool(value))
+ load_errors.push_back("Got an invalid bool value for config name: " + name);
+ else
+ bools.at(name) = stobool(value);
+ }
+ else if (ints.contains(name)) {
+ cread >> value;
+ if (!isint(value))
+ load_errors.push_back("Got an invalid integer value for config name: " + name);
+ else
+ ints.at(name) = stoi(value);
+ }
+ else if (strings.contains(name)) {
+ cread >> std::ws;
+ if (cread.peek() == '"') {
+ cread.ignore(1);
+ getline(cread, value, '"');
+ }
+ else cread >> value;
+
+ if (name == "log_level" && !v_contains(Logger::log_levels, value))
+ load_errors.push_back("Invalid log_level: " + value);
+ else if (name == "graph_symbol" && !v_contains(valid_graph_symbols, value))
+ load_errors.push_back("Invalid graph symbol identifier: " + value);
+ else
+ strings.at(name) = value;
+ }
+
+ cread.ignore(SSmax, '\n');
+ }
+ cread.close();
+ if (!load_errors.empty()) write_new = true;
+ }
+ }
+
+ //* Write the config file to disk
+ void write(){
+ if (conf_file.empty() || !write_new) return;
+ Logger::debug("Writing new config file");
+ std::ofstream cwrite(conf_file, std::ios::trunc);
+ if (cwrite.good()) {
+ cwrite << "#? Config file for btop v. " << Global::Version;
+ for (auto [name, description] : descriptions) {
+ cwrite << "\n\n" << (description.empty() ? "" : description + "\n") << name << "=";
+ if (strings.contains(name)) cwrite << "\"" << strings.at(name) << "\"";
+ else if (ints.contains(name)) cwrite << ints.at(name);
+ else if (bools.contains(name)) cwrite << (bools.at(name) ? "True" : "False");
+ }
+ cwrite.close();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/btop_config.h b/src/btop_config.h
index 3ab70e6..98e239c 100644
--- a/src/btop_config.h
+++ b/src/btop_config.h
@@ -16,303 +16,52 @@ indent = tab
tab-size = 4
*/
-#ifndef _btop_config_included_
-#define _btop_config_included_
+#pragma once
#include <string>
#include <vector>
-#include <array>
-#include <robin_hood.h>
#include <filesystem>
-#include <btop_tools.h>
-
-using std::string, std::vector, robin_hood::unordered_flat_map, std::map;
-namespace fs = std::filesystem;
-using namespace Tools;
-
+using std::string, std::vector;
//* Functions and variables for reading and writing the btop config file
namespace Config {
- namespace {
-
- fs::path conf_dir;
- fs::path conf_file;
-
- atomic<bool> locked (false);
- atomic<bool> writelock (false);
- bool write_new;
- vector<array<string, 2>> descriptions = {
- {"color_theme", "#* Color theme, looks for a .theme file in \"/usr/[local/]share/bpytop/themes\" and \"~/.config/bpytop/themes\", \"Default\" for builtin default theme.\n"
- "#* Prefix name by a plus sign (+) for a theme located in user themes folder, i.e. color_theme=\"+monokai\"." },
- {"theme_background", "#* If the theme set background should be shown, set to False if you want terminal background transparency."},
- {"truecolor", "#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false."},
- {"shown_boxes", "#* Manually set which boxes to show. Available values are \"cpu mem net proc\", separate values with whitespace."},
- {"update_ms", "#* Update time in milliseconds, increases automatically if set below internal loops processing time, recommended 2000 ms or above for better sample times for graphs."},
- {"proc_update_mult", "#* Processes update multiplier, sets how often the process list is updated as a multiplier of \"update_ms\".\n"
- "#* Set to 2 or higher to greatly decrease bpytop cpu usage. (Only integers)."},
- {"proc_sorting", "#* Processes sorting, \"pid\" \"program\" \"arguments\" \"threads\" \"user\" \"memory\" \"cpu lazy\" \"cpu responsive\",\n"
- "#* \"cpu lazy\" updates top process over time, \"cpu responsive\" updates top process directly."},
- {"proc_reversed", "#* Reverse sorting order, True or False."},
- {"proc_tree", "#* Show processes as a tree."},
- {"proc_colors", "#* Use the cpu graph colors in the process list."},
- {"proc_gradient", "#* Use a darkening gradient in the process list."},
- {"proc_per_core", "#* If process cpu usage should be of the core it's running on or usage of the total available cpu power."},
- {"proc_mem_bytes", "#* Show process memory as bytes instead of percent."},
- {"cpu_graph_upper", "#* Sets the CPU stat shown in upper half of the CPU graph, \"total\" is always available.\n"
- "#* Select from a list of detected attributes from the options menu."},
- {"cpu_graph_lower", "#* Sets the CPU stat shown in lower half of the CPU graph, \"total\" is always available.\n"
- "#* Select from a list of detected attributes from the options menu."},
- {"cpu_invert_lower", "#* Toggles if the lower CPU graph should be inverted."},
- {"cpu_single_graph", "#* Set to True to completely disable the lower CPU graph."},
- {"show_uptime", "#* Shows the system uptime in the CPU box."},
- {"check_temp", "#* Show cpu temperature."},
- {"cpu_sensor", "#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors."},
- {"show_coretemp", "#* Show temperatures for cpu cores also if check_temp is True and sensors has been found."},
- {"temp_scale", "#* Which temperature scale to use, available values: \"celsius\", \"fahrenheit\", \"kelvin\" and \"rankine\"."},
- {"show_cpu_freq", "#* Show CPU frequency."},
- {"draw_clock", "#* Draw a clock at top of screen, formatting according to strftime, empty string to disable."},
- {"background_update", "#* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort."},
- {"custom_cpu_name", "#* Custom cpu model name, empty string to disable."},
- {"disks_filter", "#* Optional filter for shown disks, should be full path of a mountpoint, separate multiple values with a comma \",\".\n"
- "#* Begin line with \"exclude=\" to change to exclude filter, otherwise defaults to \"most include\" filter. Example: disks_filter=\"exclude=/boot, /home/user\"."},
- {"mem_graphs", "#* Show graphs instead of meters for memory values."},
- {"show_swap", "#* If swap memory should be shown in memory box."},
- {"swap_disk", "#* Show swap as a disk, ignores show_swap value above, inserts itself after first disk."},
- {"show_disks", "#* If mem box should be split to also show disks info."},
- {"only_physical", "#* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar."},
- {"use_fstab", "#* Read disks list from /etc/fstab. This also disables only_physical."},
- {"show_io_stat", "#* Toggles if io stats should be shown in regular disk usage view."},
- {"io_mode", "#* Toggles io mode for disks, showing only big graphs for disk read/write speeds."},
- {"io_graph_combined", "#* Set to True to show combined read/write io graphs in io mode."},
- {"io_graph_speeds", "#* Set the top speed for the io graphs in MiB/s (10 by default), use format \"device:speed\" separate disks with a comma \",\".\n"
- "#* Example: \"/dev/sda:100, /dev/sdb:20\"."},
- {"net_download", "#* Set fixed values for network graphs, default \"10M\" = 10 Mibibytes, possible units \"K\", \"M\", \"G\", append with \"bit\" for bits instead of bytes, i.e \"100mbit\"."},
- {"net_upload", ""},
- {"net_auto", "#* Start in network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest."},
- {"net_sync", "#* Sync the scaling for download and upload to whichever currently has the highest scale."},
- {"net_color_fixed", "#* If the network graphs color gradient should scale to bandwidth usage or auto scale, bandwidth usage is based on \"net_download\" and \"net_upload\" values."},
- {"net_iface", "#* Starts with the Network Interface specified here."},
- {"show_battery", "#* Show battery stats in top right if battery is present."},
- {"log_level", "#* Set loglevel for \"~/.config/bpytop/error.log\" levels are: \"ERROR\" \"WARNING\" \"INFO\" \"DEBUG\".\n"
- "#* The level set includes all lower levels, i.e. \"DEBUG\" will show all logging info."}
- };
+ extern std::filesystem::path conf_dir;
+ extern std::filesystem::path conf_file;
- unordered_flat_map<string, string> strings = {
- {"color_theme", "Default"},
- {"shown_boxes", "cpu mem net proc"},
- {"proc_sorting", "cpu lazy"},
- {"cpu_graph_upper", "total"},
- {"cpu_graph_lower", "total"},
- {"cpu_sensor", "Auto"},
- {"temp_scale", "celsius"},
- {"draw_clock", "%X"},
- {"custom_cpu_name", ""},
- {"disks_filter", ""},
- {"io_graph_speeds", ""},
- {"net_download", "10M"},
- {"net_upload", "10M"},
- {"net_iface", ""},
- {"log_level", "WARNING"},
- {"proc_filter", ""}
- };
- unordered_flat_map<string, string> stringsTmp;
-
- unordered_flat_map<string, bool> bools = {
- {"theme_background", true},
- {"truecolor", true},
- {"proc_reversed", false},
- {"proc_tree", false},
- {"proc_colors", true},
- {"proc_gradient", true},
- {"proc_per_core", false},
- {"proc_mem_bytes", true},
- {"cpu_invert_lower", true},
- {"cpu_single_graph", false},
- {"show_uptime", true},
- {"check_temp", true},
- {"show_coretemp", true},
- {"show_cpu_freq", true},
- {"background_update", true},
- {"mem_graphs", true},
- {"show_swap", true},
- {"swap_disk", true},
- {"show_disks", true},
- {"only_physical", true},
- {"use_fstab", false},
- {"show_io_stat", true},
- {"io_mode", false},
- {"io_graph_combined", false},
- {"net_color_fixed", false},
- {"net_auto", true},
- {"net_sync", false},
- {"show_battery", true},
- };
- unordered_flat_map<string, bool> boolsTmp;
-
- unordered_flat_map<string, int> ints = {
- {"update_ms", 2000},
- {"proc_update_mult", 2},
- };
- unordered_flat_map<string, int> intsTmp;
-
- bool _locked(){
- atomic_wait(writelock);
- if (!write_new) write_new = true;
- return locked.load();
- }
- }
+ extern vector<string> valid_graph_symbols;
//* Return bool config value <name>
- const bool& getB(string name){
- return bools.at(name);
- }
+ const bool& getB(string name);