diff options
author | aristocratos <gnmjpl@gmail.com> | 2021-06-19 14:57:27 +0200 |
---|---|---|
committer | aristocratos <gnmjpl@gmail.com> | 2021-06-19 14:57:27 +0200 |
commit | d459d088a0dfb216fc6827a940d8da3f61066ecd (patch) | |
tree | d56fd230fa7445b543f388166d3042c8fef28871 | |
parent | ba481d042cf340542bf642283a25a1faf5ec421b (diff) |
File reorganization and more efficient build
-rw-r--r-- | Makefile | 68 | ||||
-rw-r--r-- | src/btop.cpp (renamed from btop.cpp) | 104 | ||||
-rw-r--r-- | src/btop_config.cpp | 337 | ||||
-rw-r--r-- | src/btop_config.h | 285 | ||||
-rw-r--r-- | src/btop_draw.cpp | 281 | ||||
-rw-r--r-- | src/btop_draw.h | 222 | ||||
-rw-r--r-- | src/btop_input.h | 9 | ||||
-rw-r--r-- | src/btop_linux.cpp | 411 | ||||
-rw-r--r-- | src/btop_linux.h | 392 | ||||
-rw-r--r-- | src/btop_menu.h | 7 | ||||
-rw-r--r-- | src/btop_theme.cpp | 288 | ||||
-rw-r--r-- | src/btop_theme.h | 262 | ||||
-rw-r--r-- | src/btop_tools.cpp | 432 | ||||
-rw-r--r-- | src/btop_tools.h | 457 |
14 files changed, 2044 insertions, 1511 deletions
@@ -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 @@ -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); |