2016-12-20 04:05:43 +00:00
|
|
|
#include "components/bar.hpp"
|
2016-06-15 03:32:35 +00:00
|
|
|
#include "components/command_line.hpp"
|
|
|
|
#include "components/config.hpp"
|
config_parser: Introduce stricter syntax conventions (#1377)
This is the next step to merge #1237 in stages.
Currently there are barely any restrictions on how the config can be
written. This causes things like config files with DOS line endings to
not be parsed properly (#1366) because polybar splits by `\n` and when
parsing section headers, it can't deal with the `\r` at the end of the
line and thus doesn't recognize any section headers.
With this PR we introduce some rules as to what characters are allowed
in section names and keys.
Note: When talking about spaces I refer to any character for which
`isspace()` returns `true`.
The rules are as follows:
* A section name or a key name cannot contain any spaces as well as any
of there characters:`"'=;#[](){}:.$\%`
* Spaces at the beginning and end of lines are always ignored when
parsing
* Comment lines start with `;` or `#` and last for the whole line. The
whole line will be ignored by the parser. You cannot start a comment at
the end of a line.
* Section headers have the following form `[HEADER_NAME]`
* Key-value lines look like this:
`KEY_NAME{SPACES}={SPACES}VALUE_STRING` where `{SPACES}` represents any
number of spaces. `VALUE_STRING` can contain any characters. If it is
*surrounded* with double quotes (`"`), those quotes will be removed,
this can be used to add spaces to the beginning or end of the value
* Empty lines are lines with only spaces in them
* If the line has any other form, it is a syntax error
This will introduce the following breaking changes because of how
underdefined the config syntax was before:
* `key = ""` will get treated as an empty string instead of the literal
* string `""`
* Any section or key name with forbidden characters will now be syntax
errors.
* Certain strings will be forbidden as section names: `self`, `root`,
* `BAR`. Because they have a special meaning inside references and so a
* section `[root]` can never be referenced.
This replaces the current parser implementation with a new more robust
one that will later be expanded to also check for dependency cycles and
allow for values that contain references mixed with other strings.
This PR also now expands the config paths given over the command line so
that `--config=~/.config/polybar/config` resolves properly.
Closes #1032
Closes #1694
* config_parser: Add skeleton with tests
First step in the config_parser develoment. Only tests functions that
are easily testable without many outside dependencies. Integration tests
will follow.
* config_parser: Implement parse_header
* config_parser: Implement get_line_type
* feat(string): Add trim functions with predicate
Not only trimming based on single character matching but based on a
freely specifiable predicate. Will be used to trim all spaces (based on
isspace)
* config_parser: Implement parse_key
* config_parser: Implement parse_line for valid lines
* config_parser: Throw exception on invalid lines
* config_parser: Remove line_no and file_index from parse_line
Cleaner to let the caller catch and fill in the line number and file
path
* string: Clear up misleading description of trim
Before, trim would remove all characters that *didn't* match the
predicate and thus the predicate isspace wouldn't work correctly. But
because we used the inverse (isnospace_pred) it all worked out, but if
the function was used with any other function, it wouldn't have given
the desired output
* config_parser: Implement parse_file
* config_parser: Switch operation to config_parser
This changes the way the config is invoked. Now main.cpp creates a
config_parser object which then returns the singleton config object from
the parse method. Subsequent calls to config::make will return the
already created config object as before
The config_parser does not yet have all the functionality of the old
parser: `inherit` directives are not yet resolved. Other than that all
the old functionality is implemented (creating sectionmap and applying
include-file)
Any sort of dependency detection (except for include-file) are still
missing
* config: Move xrm initialization to constructor
config_parser handles the detection of xrdb references and passes that
info to the config object.
This finally allows us to delete the config::parse_file function because
everything in it has been implemented (except for xrdb detection and
file error handling)
* refactor(config_parser): Cleanup
* config_parser: Set config data after initialization
Looks much cleaner this way
* config_parser: Expand include-file paths
* config_parser: Init xrm if the config uses %{xrdb references
* config_parser: Use same type of maps as in old impl
Polybar has some weird, not yet fixed, inheriting behaviour and it
changes depending on the order in which the config stores its data.
Using the same type of maps ensures that the behaviour stays the same.
* refactor(config_parser): Clearer invalid name error message
* config_parser: Don't allow reserved section names
Sections with the names 'self', 'BAR', 'root' could never be referenced
because those strings have a special meaning inside references
* config_parser: Handle inherit directives
This uses the old copy_inherited function, so this still suffers from
crashes if there are cyclic dependencies.
This also fixes the behaviour where any key that starts with 'inherit'
would be treated as an inherit directive
* config_parser: Clearer dependency cycle error message
* refactor(config_parser): Handle file errors when parsing
This removes the need to check if the file exists separately
* fix(config): expand config file path
Now paths using ~ and environment variables can be used as the config
path
* fix(config): Properly recognize xrdb references
* config_parser: Make messages more informative
* doc(config): Improve commenting
Comments now describe what the config_parser actually does instead of
what it will do.
We also now follow the rule that single line comments inside functions
should use `//` comments
* refactor: Move else on same line as curly braces
* fix(config_parser): Don't duplicate paths in `files`
* refactor(config_parser): Use else if for clarity
* fix(config): Undefined behavior in syntax_error
Before the custom what() method produced undefined behavior because the
returned string became invalid once the function returned.
* refactor(config): descriptive name for useless lines
is_valid could easily be confused as meaning syntactically invalid
without it being clarified in a comment
* refactor(config): Use separate strings instead of key_value
Takes just as much space and is much better to read
* fix(config_parser): TestCase -> TestSuite and fix macro call
Ref: #1644
* config_parser: use const string& in method args
* config_parser: Improve comments
* config_parser: Incorporate review comments
2019-08-06 17:41:31 +00:00
|
|
|
#include "components/config_parser.hpp"
|
2016-06-15 03:32:35 +00:00
|
|
|
#include "components/controller.hpp"
|
2022-01-22 19:35:37 +00:00
|
|
|
#include "ipc/ipc.hpp"
|
2016-11-20 22:04:31 +00:00
|
|
|
#include "utils/env.hpp"
|
2016-06-15 03:32:35 +00:00
|
|
|
#include "utils/inotify.hpp"
|
2016-12-03 14:46:48 +00:00
|
|
|
#include "utils/process.hpp"
|
2018-05-12 16:44:28 +00:00
|
|
|
#include "x11/connection.hpp"
|
2016-06-15 03:32:35 +00:00
|
|
|
|
2016-11-19 05:22:44 +00:00
|
|
|
using namespace polybar;
|
2016-06-15 03:32:35 +00:00
|
|
|
|
2016-11-25 07:42:31 +00:00
|
|
|
int main(int argc, char** argv) {
|
2016-06-15 03:32:35 +00:00
|
|
|
// clang-format off
|
|
|
|
const command_line::options opts{
|
2017-01-13 02:52:56 +00:00
|
|
|
command_line::option{"-h", "--help", "Display this help and exit"},
|
|
|
|
command_line::option{"-v", "--version", "Display build details and exit"},
|
2020-04-21 22:12:08 +00:00
|
|
|
command_line::option{"-l", "--log", "Set the logging verbosity (default: notice)", "LEVEL", {"error", "warning", "notice", "info", "trace"}},
|
2016-06-15 03:32:35 +00:00
|
|
|
command_line::option{"-q", "--quiet", "Be quiet (will override -l)"},
|
|
|
|
command_line::option{"-c", "--config", "Path to the configuration file", "FILE"},
|
|
|
|
command_line::option{"-r", "--reload", "Reload when the configuration has been modified"},
|
2017-01-19 17:12:39 +00:00
|
|
|
command_line::option{"-d", "--dump", "Print value of PARAM in bar section and exit", "PARAM"},
|
2019-06-24 15:58:40 +00:00
|
|
|
command_line::option{"-m", "--list-monitors", "Print list of available monitors and exit (Removes cloned monitors)"},
|
|
|
|
command_line::option{"-M", "--list-all-monitors", "Print list of all available monitors (Including cloned monitors) and exit"},
|
2017-01-13 02:52:56 +00:00
|
|
|
command_line::option{"-w", "--print-wmname", "Print the generated WM_NAME and exit"},
|
2017-01-19 17:12:39 +00:00
|
|
|
command_line::option{"-s", "--stdout", "Output data to stdout instead of drawing it to the X window"},
|
|
|
|
command_line::option{"-p", "--png", "Save png snapshot to FILE after running for 3 seconds", "FILE"},
|
2016-06-15 03:32:35 +00:00
|
|
|
};
|
|
|
|
// clang-format on
|
|
|
|
|
2017-01-19 10:11:28 +00:00
|
|
|
unsigned char exit_code{EXIT_SUCCESS};
|
2016-12-03 15:44:08 +00:00
|
|
|
bool reload{false};
|
|
|
|
|
2020-04-21 22:12:08 +00:00
|
|
|
logger& logger{const_cast<decltype(logger)>(logger::make(loglevel::NOTICE))};
|
2016-12-05 19:41:00 +00:00
|
|
|
|
2016-12-03 14:46:48 +00:00
|
|
|
try {
|
|
|
|
//==================================================
|
|
|
|
// Parse command line arguments
|
|
|
|
//==================================================
|
|
|
|
string scriptname{argv[0]};
|
2016-12-09 10:32:41 +00:00
|
|
|
vector<string> args{argv + 1, argv + argc};
|
|
|
|
|
2017-01-11 02:07:28 +00:00
|
|
|
command_line::parser::make_type cli{command_line::parser::make(move(scriptname), move(opts))};
|
2016-12-05 19:41:00 +00:00
|
|
|
cli->process_input(args);
|
2016-12-03 14:46:48 +00:00
|
|
|
|
2016-12-05 19:41:00 +00:00
|
|
|
if (cli->has("quiet")) {
|
2016-12-03 14:46:48 +00:00
|
|
|
logger.verbosity(loglevel::ERROR);
|
2016-12-05 19:41:00 +00:00
|
|
|
} else if (cli->has("log")) {
|
2016-12-09 11:22:58 +00:00
|
|
|
logger.verbosity(logger::parse_verbosity(cli->get("log")));
|
2016-12-03 14:46:48 +00:00
|
|
|
}
|
|
|
|
|
2016-12-05 19:41:00 +00:00
|
|
|
if (cli->has("help")) {
|
|
|
|
cli->usage();
|
2016-12-20 04:05:43 +00:00
|
|
|
return EXIT_SUCCESS;
|
2016-12-05 19:41:00 +00:00
|
|
|
} else if (cli->has("version")) {
|
2016-12-03 14:46:48 +00:00
|
|
|
print_build_info(version_details(args));
|
2016-12-20 04:05:43 +00:00
|
|
|
return EXIT_SUCCESS;
|
2016-12-03 14:46:48 +00:00
|
|
|
}
|
|
|
|
|
2022-01-22 19:35:37 +00:00
|
|
|
eventloop::eventloop loop{};
|
|
|
|
|
2016-12-24 01:55:21 +00:00
|
|
|
//==================================================
|
|
|
|
// Connect to X server
|
|
|
|
//==================================================
|
2017-01-24 07:49:27 +00:00
|
|
|
auto xcb_error = 0;
|
|
|
|
auto xcb_screen = 0;
|
|
|
|
auto xcb_connection = xcb_connect(nullptr, &xcb_screen);
|
2016-12-24 01:55:21 +00:00
|
|
|
|
2017-01-24 07:49:27 +00:00
|
|
|
if (xcb_connection == nullptr) {
|
|
|
|
throw application_error("A connection to X could not be established...");
|
|
|
|
} else if ((xcb_error = xcb_connection_has_error(xcb_connection))) {
|
|
|
|
throw application_error("X connection error... (what: " + connection::error_str(xcb_error) + ")");
|
2016-12-24 01:55:21 +00:00
|
|
|
}
|
|
|
|
|
2017-01-24 07:49:27 +00:00
|
|
|
connection& conn{connection::make(xcb_connection, xcb_screen)};
|
2016-12-24 01:55:21 +00:00
|
|
|
conn.ensure_event_mask(conn.root(), XCB_EVENT_MASK_PROPERTY_CHANGE);
|
|
|
|
|
2017-01-13 03:50:33 +00:00
|
|
|
//==================================================
|
|
|
|
// List available XRandR entries
|
|
|
|
//==================================================
|
2019-06-24 15:58:40 +00:00
|
|
|
if (cli->has("list-monitors") || cli->has("list-all-monitors")) {
|
|
|
|
bool purge_clones = !cli->has("list-all-monitors");
|
|
|
|
auto monitors = randr_util::get_monitors(conn, conn.root(), true, purge_clones);
|
|
|
|
for (auto&& mon : monitors) {
|
fix(monitor): do not include outputs when monitors are supported (#2485)
* fix(monitor): do not include outputs when monitors are supported
Previously, when splitting an output into two monitors, `polybar -m`
would report both the splitted monitors and the output. This was not
caught by the the clone detection as the detection works by removing
monitors contained into another monitors (and monitors were excluded
from that logic) and we want the other way around: outputs covered by
monitors should be ignored.
Instead of trying to detect covered outputs, the solution is quite
simple: when monitors are supported, do not consider outputs, unless
we request all outputs. A monitor can be set primary (and RandR
reports primary outputs as primary monitors). The only information we
would miss from monitors are things like refresh rate and EDID. We
don't need that, so we are fine.
As monitors are only created for connected output (and they are in
this case "active") or disconnected output if they are mapped (and
they are in this case "inactive"), I am a bit unsure if we have
exactly the same behaviour as previously when `connected_only` is set
to `false`.
As some modules require an output, we keep the output in the
`monitor_t` structure and we ensure it is correctly set when using
monitors. A monitor can have 0 or several outputs. We only handle the
0 and 1 cases. When a monitor has more outputs, only the first one is
used. AFAIK, only the xbacklight module needs that and I think we are
fine waiting for a user needing this module and merging monitors.
The C++ binding fail to expose the `outputs()` method to iterate over
the outputs of a monitor. This seems to be a bug in XPP. The field is
correctly defined in the RandR XML file and it works with the Python
binding.
```xml
<struct name="MonitorInfo">
<field type="ATOM" name="name" />
<field type="BOOL" name="primary" />
<field type="BOOL" name="automatic" />
<field type="CARD16" name="nOutput" />
<field type="INT16" name="x" />
<field type="INT16" name="y" />
<field type="CARD16" name="width" /> <!-- pixels -->
<field type="CARD16" name="height" /> <!-- pixels -->
<field type="CARD32" name="width_in_millimeters" />
<field type="CARD32" name="height_in_millimeters" />
<list type="OUTPUT" name="outputs">
<fieldref>nOutput</fieldref>
</list>
</struct>
```
Falling back to C only to access the list of outputs is not enough
because the list is appended to the structure and not visible through
the public API. When copied, the structure loses the list of monitors.
Also, change the mention "XRandR monitor" to "no output" when there is
no output attached. People using monitors know what it means and it is
useful to catch a future regression where we don't have an output at
all (which would break the brightness plugin).
Fix #2481
* Update CHANGELOG.md
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
2021-09-02 16:07:21 +00:00
|
|
|
if (mon->output == XCB_NONE) {
|
|
|
|
printf("%s: %ix%i+%i+%i (no output%s)\n", mon->name.c_str(), mon->w, mon->h, mon->x, mon->y,
|
2019-01-20 19:20:30 +00:00
|
|
|
mon->primary ? ", primary" : "");
|
2017-01-13 03:50:33 +00:00
|
|
|
} else {
|
config_parser: Introduce stricter syntax conventions (#1377)
This is the next step to merge #1237 in stages.
Currently there are barely any restrictions on how the config can be
written. This causes things like config files with DOS line endings to
not be parsed properly (#1366) because polybar splits by `\n` and when
parsing section headers, it can't deal with the `\r` at the end of the
line and thus doesn't recognize any section headers.
With this PR we introduce some rules as to what characters are allowed
in section names and keys.
Note: When talking about spaces I refer to any character for which
`isspace()` returns `true`.
The rules are as follows:
* A section name or a key name cannot contain any spaces as well as any
of there characters:`"'=;#[](){}:.$\%`
* Spaces at the beginning and end of lines are always ignored when
parsing
* Comment lines start with `;` or `#` and last for the whole line. The
whole line will be ignored by the parser. You cannot start a comment at
the end of a line.
* Section headers have the following form `[HEADER_NAME]`
* Key-value lines look like this:
`KEY_NAME{SPACES}={SPACES}VALUE_STRING` where `{SPACES}` represents any
number of spaces. `VALUE_STRING` can contain any characters. If it is
*surrounded* with double quotes (`"`), those quotes will be removed,
this can be used to add spaces to the beginning or end of the value
* Empty lines are lines with only spaces in them
* If the line has any other form, it is a syntax error
This will introduce the following breaking changes because of how
underdefined the config syntax was before:
* `key = ""` will get treated as an empty string instead of the literal
* string `""`
* Any section or key name with forbidden characters will now be syntax
errors.
* Certain strings will be forbidden as section names: `self`, `root`,
* `BAR`. Because they have a special meaning inside references and so a
* section `[root]` can never be referenced.
This replaces the current parser implementation with a new more robust
one that will later be expanded to also check for dependency cycles and
allow for values that contain references mixed with other strings.
This PR also now expands the config paths given over the command line so
that `--config=~/.config/polybar/config` resolves properly.
Closes #1032
Closes #1694
* config_parser: Add skeleton with tests
First step in the config_parser develoment. Only tests functions that
are easily testable without many outside dependencies. Integration tests
will follow.
* config_parser: Implement parse_header
* config_parser: Implement get_line_type
* feat(string): Add trim functions with predicate
Not only trimming based on single character matching but based on a
freely specifiable predicate. Will be used to trim all spaces (based on
isspace)
* config_parser: Implement parse_key
* config_parser: Implement parse_line for valid lines
* config_parser: Throw exception on invalid lines
* config_parser: Remove line_no and file_index from parse_line
Cleaner to let the caller catch and fill in the line number and file
path
* string: Clear up misleading description of trim
Before, trim would remove all characters that *didn't* match the
predicate and thus the predicate isspace wouldn't work correctly. But
because we used the inverse (isnospace_pred) it all worked out, but if
the function was used with any other function, it wouldn't have given
the desired output
* config_parser: Implement parse_file
* config_parser: Switch operation to config_parser
This changes the way the config is invoked. Now main.cpp creates a
config_parser object which then returns the singleton config object from
the parse method. Subsequent calls to config::make will return the
already created config object as before
The config_parser does not yet have all the functionality of the old
parser: `inherit` directives are not yet resolved. Other than that all
the old functionality is implemented (creating sectionmap and applying
include-file)
Any sort of dependency detection (except for include-file) are still
missing
* config: Move xrm initialization to constructor
config_parser handles the detection of xrdb references and passes that
info to the config object.
This finally allows us to delete the config::parse_file function because
everything in it has been implemented (except for xrdb detection and
file error handling)
* refactor(config_parser): Cleanup
* config_parser: Set config data after initialization
Looks much cleaner this way
* config_parser: Expand include-file paths
* config_parser: Init xrm if the config uses %{xrdb references
* config_parser: Use same type of maps as in old impl
Polybar has some weird, not yet fixed, inheriting behaviour and it
changes depending on the order in which the config stores its data.
Using the same type of maps ensures that the behaviour stays the same.
* refactor(config_parser): Clearer invalid name error message
* config_parser: Don't allow reserved section names
Sections with the names 'self', 'BAR', 'root' could never be referenced
because those strings have a special meaning inside references
* config_parser: Handle inherit directives
This uses the old copy_inherited function, so this still suffers from
crashes if there are cyclic dependencies.
This also fixes the behaviour where any key that starts with 'inherit'
would be treated as an inherit directive
* config_parser: Clearer dependency cycle error message
* refactor(config_parser): Handle file errors when parsing
This removes the need to check if the file exists separately
* fix(config): expand config file path
Now paths using ~ and environment variables can be used as the config
path
* fix(config): Properly recognize xrdb references
* config_parser: Make messages more informative
* doc(config): Improve commenting
Comments now describe what the config_parser actually does instead of
what it will do.
We also now follow the rule that single line comments inside functions
should use `//` comments
* refactor: Move else on same line as curly braces
* fix(config_parser): Don't duplicate paths in `files`
* refactor(config_parser): Use else if for clarity
* fix(config): Undefined behavior in syntax_error
Before the custom what() method produced undefined behavior because the
returned string became invalid once the function returned.
* refactor(config): descriptive name for useless lines
is_valid could easily be confused as meaning syntactically invalid
without it being clarified in a comment
* refactor(config): Use separate strings instead of key_value
Takes just as much space and is much better to read
* fix(config_parser): TestCase -> TestSuite and fix macro call
Ref: #1644
* config_parser: use const string& in method args
* config_parser: Improve comments
* config_parser: Incorporate review comments
2019-08-06 17:41:31 +00:00
|
|
|
printf("%s: %ix%i+%i+%i%s\n", mon->name.c_str(), mon->w, mon->h, mon->x, mon->y,
|
|
|
|
mon->primary ? " (primary)" : "");
|
2017-01-13 03:50:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2016-12-03 14:46:48 +00:00
|
|
|
//==================================================
|
|
|
|
// Load user configuration
|
|
|
|
//==================================================
|
2016-12-09 10:32:41 +00:00
|
|
|
string confpath;
|
2016-12-03 14:46:48 +00:00
|
|
|
|
2017-01-13 03:50:33 +00:00
|
|
|
// Make sure a bar name is passed in
|
2021-10-07 12:48:47 +00:00
|
|
|
if (cli->has(1)) {
|
2017-01-24 05:58:45 +00:00
|
|
|
fprintf(stderr, "Unrecognized argument \"%s\"\n", cli->get(1).c_str());
|
2017-01-13 03:50:33 +00:00
|
|
|
cli->usage();
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2016-12-05 19:41:00 +00:00
|
|
|
if (cli->has("config")) {
|
2016-12-09 10:32:41 +00:00
|
|
|
confpath = cli->get("config");
|
2016-12-03 14:46:48 +00:00
|
|
|
} else {
|
2020-03-01 21:03:17 +00:00
|
|
|
confpath = file_util::get_config_path();
|
2021-10-05 11:07:19 +00:00
|
|
|
|
2021-10-31 10:53:23 +00:00
|
|
|
if (string_util::ends_with(confpath, "/config")) {
|
2021-10-05 11:07:19 +00:00
|
|
|
logger::make().warn(
|
2021-10-31 10:53:23 +00:00
|
|
|
"Naming your configuration file 'config' is deprecated, the expected name is 'config.ini'.");
|
2021-10-05 11:07:19 +00:00
|
|
|
}
|
2020-03-01 21:03:17 +00:00
|
|
|
}
|
2021-10-31 10:53:23 +00:00
|
|
|
|
2020-03-01 21:03:17 +00:00
|
|
|
if (confpath.empty()) {
|
2016-12-03 14:46:48 +00:00
|
|
|
throw application_error("Define configuration using --config=PATH");
|
|
|
|
}
|
|
|
|
|
2021-10-07 12:48:47 +00:00
|
|
|
string barname;
|
|
|
|
if (cli->has(0)) {
|
|
|
|
barname = cli->get(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
config_parser parser{logger, move(confpath), move(barname)};
|
config_parser: Introduce stricter syntax conventions (#1377)
This is the next step to merge #1237 in stages.
Currently there are barely any restrictions on how the config can be
written. This causes things like config files with DOS line endings to
not be parsed properly (#1366) because polybar splits by `\n` and when
parsing section headers, it can't deal with the `\r` at the end of the
line and thus doesn't recognize any section headers.
With this PR we introduce some rules as to what characters are allowed
in section names and keys.
Note: When talking about spaces I refer to any character for which
`isspace()` returns `true`.
The rules are as follows:
* A section name or a key name cannot contain any spaces as well as any
of there characters:`"'=;#[](){}:.$\%`
* Spaces at the beginning and end of lines are always ignored when
parsing
* Comment lines start with `;` or `#` and last for the whole line. The
whole line will be ignored by the parser. You cannot start a comment at
the end of a line.
* Section headers have the following form `[HEADER_NAME]`
* Key-value lines look like this:
`KEY_NAME{SPACES}={SPACES}VALUE_STRING` where `{SPACES}` represents any
number of spaces. `VALUE_STRING` can contain any characters. If it is
*surrounded* with double quotes (`"`), those quotes will be removed,
this can be used to add spaces to the beginning or end of the value
* Empty lines are lines with only spaces in them
* If the line has any other form, it is a syntax error
This will introduce the following breaking changes because of how
underdefined the config syntax was before:
* `key = ""` will get treated as an empty string instead of the literal
* string `""`
* Any section or key name with forbidden characters will now be syntax
errors.
* Certain strings will be forbidden as section names: `self`, `root`,
* `BAR`. Because they have a special meaning inside references and so a
* section `[root]` can never be referenced.
This replaces the current parser implementation with a new more robust
one that will later be expanded to also check for dependency cycles and
allow for values that contain references mixed with other strings.
This PR also now expands the config paths given over the command line so
that `--config=~/.config/polybar/config` resolves properly.
Closes #1032
Closes #1694
* config_parser: Add skeleton with tests
First step in the config_parser develoment. Only tests functions that
are easily testable without many outside dependencies. Integration tests
will follow.
* config_parser: Implement parse_header
* config_parser: Implement get_line_type
* feat(string): Add trim functions with predicate
Not only trimming based on single character matching but based on a
freely specifiable predicate. Will be used to trim all spaces (based on
isspace)
* config_parser: Implement parse_key
* config_parser: Implement parse_line for valid lines
* config_parser: Throw exception on invalid lines
* config_parser: Remove line_no and file_index from parse_line
Cleaner to let the caller catch and fill in the line number and file
path
* string: Clear up misleading description of trim
Before, trim would remove all characters that *didn't* match the
predicate and thus the predicate isspace wouldn't work correctly. But
because we used the inverse (isnospace_pred) it all worked out, but if
the function was used with any other function, it wouldn't have given
the desired output
* config_parser: Implement parse_file
* config_parser: Switch operation to config_parser
This changes the way the config is invoked. Now main.cpp creates a
config_parser object which then returns the singleton config object from
the parse method. Subsequent calls to config::make will return the
already created config object as before
The config_parser does not yet have all the functionality of the old
parser: `inherit` directives are not yet resolved. Other than that all
the old functionality is implemented (creating sectionmap and applying
include-file)
Any sort of dependency detection (except for include-file) are still
missing
* config: Move xrm initialization to constructor
config_parser handles the detection of xrdb references and passes that
info to the config object.
This finally allows us to delete the config::parse_file function because
everything in it has been implemented (except for xrdb detection and
file error handling)
* refactor(config_parser): Cleanup
* config_parser: Set config data after initialization
Looks much cleaner this way
* config_parser: Expand include-file paths
* config_parser: Init xrm if the config uses %{xrdb references
* config_parser: Use same type of maps as in old impl
Polybar has some weird, not yet fixed, inheriting behaviour and it
changes depending on the order in which the config stores its data.
Using the same type of maps ensures that the behaviour stays the same.
* refactor(config_parser): Clearer invalid name error message
* config_parser: Don't allow reserved section names
Sections with the names 'self', 'BAR', 'root' could never be referenced
because those strings have a special meaning inside references
* config_parser: Handle inherit directives
This uses the old copy_inherited function, so this still suffers from
crashes if there are cyclic dependencies.
This also fixes the behaviour where any key that starts with 'inherit'
would be treated as an inherit directive
* config_parser: Clearer dependency cycle error message
* refactor(config_parser): Handle file errors when parsing
This removes the need to check if the file exists separately
* fix(config): expand config file path
Now paths using ~ and environment variables can be used as the config
path
* fix(config): Properly recognize xrdb references
* config_parser: Make messages more informative
* doc(config): Improve commenting
Comments now describe what the config_parser actually does instead of
what it will do.
We also now follow the rule that single line comments inside functions
should use `//` comments
* refactor: Move else on same line as curly braces
* fix(config_parser): Don't duplicate paths in `files`
* refactor(config_parser): Use else if for clarity
* fix(config): Undefined behavior in syntax_error
Before the custom what() method produced undefined behavior because the
returned string became invalid once the function returned.
* refactor(config): descriptive name for useless lines
is_valid could easily be confused as meaning syntactically invalid
without it being clarified in a comment
* refactor(config): Use separate strings instead of key_value
Takes just as much space and is much better to read
* fix(config_parser): TestCase -> TestSuite and fix macro call
Ref: #1644
* config_parser: use const string& in method args
* config_parser: Improve comments
* config_parser: Incorporate review comments
2019-08-06 17:41:31 +00:00
|
|
|
config::make_type conf = parser.parse();
|
2016-12-09 10:32:41 +00:00
|
|
|
|
2016-12-03 14:46:48 +00:00
|
|
|
//==================================================
|
|
|
|
// Dump requested data
|
|
|
|
//==================================================
|
2016-12-05 19:41:00 +00:00
|
|
|
if (cli->has("dump")) {
|
2017-01-13 02:52:56 +00:00
|
|
|
printf("%s\n", conf.get(conf.section(), cli->get("dump")).c_str());
|
2016-12-20 04:05:43 +00:00
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
if (cli->has("print-wmname")) {
|
2021-09-27 15:35:45 +00:00
|
|
|
printf("%s\n", bar::make(loop, true)->settings().wmname.c_str());
|
2017-01-13 02:52:56 +00:00
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
2016-12-03 14:46:48 +00:00
|
|
|
|
|
|
|
//==================================================
|
2016-12-05 19:41:00 +00:00
|
|
|
// Create controller and run application
|
2016-12-03 14:46:48 +00:00
|
|
|
//==================================================
|
2022-01-22 19:35:37 +00:00
|
|
|
unique_ptr<ipc::ipc> ipc{};
|
2016-12-05 19:41:00 +00:00
|
|
|
|
2016-12-30 22:32:05 +00:00
|
|
|
if (conf.get(conf.section(), "enable-ipc", false)) {
|
2022-01-22 19:35:37 +00:00
|
|
|
ipc = ipc::ipc::make(loop);
|
2016-12-03 14:46:48 +00:00
|
|
|
}
|
|
|
|
|
2022-01-22 19:35:37 +00:00
|
|
|
auto ctrl = controller::make((bool)ipc, loop);
|
2016-12-05 19:41:00 +00:00
|
|
|
|
2021-09-11 12:56:08 +00:00
|
|
|
if (!ctrl->run(cli->has("stdout"), cli->get("png"), cli->has("reload"))) {
|
2016-12-03 14:46:48 +00:00
|
|
|
reload = true;
|
|
|
|
}
|
|
|
|
} catch (const exception& err) {
|
|
|
|
logger.err(err.what());
|
|
|
|
exit_code = EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2016-12-20 04:05:43 +00:00
|
|
|
logger.info("Waiting for spawned processes to end");
|
2016-12-21 07:00:09 +00:00
|
|
|
while (process_util::notify_childprocess()) {
|
2016-12-20 04:05:43 +00:00
|
|
|
;
|
2016-12-21 07:00:09 +00:00
|
|
|
}
|
2016-06-15 03:32:35 +00:00
|
|
|
|
2016-12-20 04:05:43 +00:00
|
|
|
if (reload) {
|
2016-12-09 11:43:31 +00:00
|
|
|
logger.info("Re-launching application...");
|
|
|
|
process_util::exec(move(argv[0]), move(argv));
|
2016-12-03 14:46:48 +00:00
|
|
|
}
|
2016-11-25 07:42:31 +00:00
|
|
|
|
2016-12-20 04:05:43 +00:00
|
|
|
logger.info("Reached end of application...");
|
|
|
|
return exit_code;
|
2016-06-15 03:32:35 +00:00
|
|
|
}
|