2016-06-15 03:32:35 +00:00
|
|
|
#pragma once
|
2017-01-11 02:07:28 +00:00
|
|
|
|
2016-12-13 17:24:01 +00:00
|
|
|
#include <unordered_map>
|
2016-06-15 03:32:35 +00:00
|
|
|
|
|
|
|
#include "common.hpp"
|
|
|
|
#include "components/logger.hpp"
|
2016-11-25 12:55:15 +00:00
|
|
|
#include "errors.hpp"
|
2017-01-20 01:25:54 +00:00
|
|
|
#include "settings.hpp"
|
2016-11-20 22:04:31 +00:00
|
|
|
#include "utils/env.hpp"
|
2016-12-19 21:01:37 +00:00
|
|
|
#include "utils/file.hpp"
|
2016-06-15 03:32:35 +00:00
|
|
|
#include "utils/string.hpp"
|
2017-01-26 16:17:02 +00:00
|
|
|
#if WITH_XRM
|
2016-11-02 19:22:45 +00:00
|
|
|
#include "x11/xresources.hpp"
|
2017-01-20 01:25:54 +00:00
|
|
|
#endif
|
2016-06-15 03:32:35 +00:00
|
|
|
|
2016-11-19 05:22:44 +00:00
|
|
|
POLYBAR_NS
|
2016-06-15 03:32:35 +00:00
|
|
|
|
|
|
|
DEFINE_ERROR(value_error);
|
|
|
|
DEFINE_ERROR(key_error);
|
|
|
|
|
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
|
|
|
using valuemap_t = std::unordered_map<string, string>;
|
|
|
|
using sectionmap_t = std::map<string, valuemap_t>;
|
|
|
|
using file_list = vector<string>;
|
|
|
|
|
2016-06-15 03:32:35 +00:00
|
|
|
class config {
|
|
|
|
public:
|
2016-12-09 08:40:46 +00:00
|
|
|
using make_type = const config&;
|
2016-12-09 10:32:41 +00:00
|
|
|
static make_type make(string path = "", string bar = "");
|
2016-12-01 06:54:45 +00:00
|
|
|
|
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
|
|
|
explicit config(const logger& logger, string&& path = "", string&& bar = "")
|
|
|
|
: m_log(logger), m_file(move(path)), m_barname(move(bar)){};
|
2016-06-15 03:32:35 +00:00
|
|
|
|
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
|
|
|
const string& filepath() const;
|
2016-12-14 04:12:15 +00:00
|
|
|
string section() const;
|
|
|
|
|
2021-10-07 12:48:47 +00:00
|
|
|
static constexpr const char* BAR_PREFIX = "bar/";
|
|
|
|
|
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
|
|
|
/**
|
|
|
|
* \brief Instruct the config to connect to the xresource manager
|
|
|
|
*/
|
|
|
|
void use_xrm();
|
|
|
|
|
|
|
|
void set_sections(sectionmap_t sections);
|
|
|
|
|
|
|
|
void set_included(file_list included);
|
|
|
|
|
2016-11-25 12:55:15 +00:00
|
|
|
void warn_deprecated(const string& section, const string& key, string replacement) const;
|
2016-06-15 03:32:35 +00:00
|
|
|
|
2016-11-29 14:53:32 +00:00
|
|
|
/**
|
|
|
|
* Returns true if a given parameter exists
|
|
|
|
*/
|
2016-12-13 17:24:01 +00:00
|
|
|
bool has(const string& section, const string& key) const {
|
|
|
|
auto it = m_sections.find(section);
|
|
|
|
return it != m_sections.end() && it->second.find(key) != it->second.end();
|
2016-11-29 14:53:32 +00:00
|
|
|
}
|
|
|
|
|
2017-01-13 19:03:08 +00:00
|
|
|
/**
|
|
|
|
* Set parameter value
|
|
|
|
*/
|
|
|
|
void set(const string& section, const string& key, string&& value) {
|
|
|
|
auto it = m_sections.find(section);
|
|
|
|
if (it == m_sections.end()) {
|
|
|
|
valuemap_t values;
|
|
|
|
values[key] = value;
|
|
|
|
m_sections[section] = move(values);
|
|
|
|
}
|
|
|
|
auto it2 = it->second.find(key);
|
|
|
|
if ((it2 = it->second.find(key)) == it->second.end()) {
|
|
|
|
it2 = it->second.emplace_hint(it2, key, value);
|
|
|
|
} else {
|
|
|
|
it2->second = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-15 03:32:35 +00:00
|
|
|
/**
|
|
|
|
* Get parameter for the current bar by name
|
|
|
|
*/
|
2016-12-30 22:32:05 +00:00
|
|
|
template <typename T = string>
|
2016-12-13 17:24:01 +00:00
|
|
|
T get(const string& key) const {
|
2016-12-14 04:12:15 +00:00
|
|
|
return get<T>(section(), key);
|
2016-06-15 03:32:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get value of a variable by section and parameter name
|
|
|
|
*/
|
2016-12-30 22:32:05 +00:00
|
|
|
template <typename T = string>
|
2016-12-13 17:24:01 +00:00
|
|
|
T get(const string& section, const string& key) const {
|
2016-12-15 16:13:15 +00:00
|
|
|
auto it = m_sections.find(section);
|
2020-10-06 16:22:10 +00:00
|
|
|
if (it == m_sections.end()) {
|
|
|
|
throw key_error("Missing section \"" + section + "\"");
|
|
|
|
}
|
|
|
|
if (it->second.find(key) == it->second.end()) {
|
2017-01-26 19:10:33 +00:00
|
|
|
throw key_error("Missing parameter \"" + section + "." + key + "\"");
|
2016-12-13 17:24:01 +00:00
|
|
|
}
|
2016-12-15 16:13:15 +00:00
|
|
|
return dereference<T>(section, key, it->second.at(key), convert<T>(string{it->second.at(key)}));
|
2016-06-15 03:32:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get value of a variable by section and parameter name
|
|
|
|
* with a default value in case the parameter isn't defined
|
|
|
|
*/
|
2016-12-30 22:32:05 +00:00
|
|
|
template <typename T = string>
|
2016-12-13 17:24:01 +00:00
|
|
|
T get(const string& section, const string& key, const T& default_value) const {
|
2016-12-15 16:13:15 +00:00
|
|
|
try {
|
|
|
|
string string_value{get<string>(section, key)};
|
2016-12-15 19:57:03 +00:00
|
|
|
T result{convert<T>(string{string_value})};
|
2016-12-15 16:13:15 +00:00
|
|
|
return dereference<T>(move(section), move(key), move(string_value), move(result));
|
|
|
|
} catch (const key_error& err) {
|
2016-12-13 17:24:01 +00:00
|
|
|
return default_value;
|
Add units support (POINT, PIXEL, SPACE) (#2578)
* add units support (POINT, PIXEL, SPACE) for polybar
- add a size_with_unit struct
- add a geometry_format_values struct
- move dpi initialisation from renderer.cpp to bar.cpp
- add a string to size_with_unit converter
- add point support (with pt)
- add pixel support (with px)
* Fix unit test compilation
* clang-format
* Better names
The old names didn't really capture the purpose of the structs and
function.
space_type -> spacing_type
space_size -> spacing_val
size_type -> extent_type
geometry -> extent_val
geometry_format_values -> percentage_with_offset
* Remove parse_size_with_unit
No longer needed. The convert<spacing_val> function in config.cpp
already does all the work for us and always setting the type to pixel
was wrong.
In addition, line-size should not be of type spacing_val but extent_val.
* Cleanup
I tried to address most of my comments on the old PR
* Fix renderer width calculation
We can't just blindly add the x difference to the width because for
example the width should increase if x < width and the increase keeps
x < width.
Similarly, we can't just add the offset to the width.
* Rename geom_format_to_pixels to percentage_with_offset_to_pixel
* Cleanup
* Apply suggested changes from Patrick on GitHub
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* Update src/components/bar.cpp
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* Update src/components/config.cpp
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* Update src/components/builder.cpp
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* Update src/components/builder.cpp
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* config: Use stod for parsing percentage
* Use stof instead of strtof
* units: Fix test edge cases
* Remove unnecessary clang-format toggle
* Use percentage_with_offset for margin-{top,bottom}
* Support negative extent values
* Rename unit to units and create a cpp file
* Move percentage_with_offset_to_pixel unit test to units
* Add unit tests for units_utils
* Clarify when and how negative spacing/extent is allowed
Negative spacing is never allowed and produces a config error.
Extents allow negative values in theory, but only a few use-cases accept
it.
Only the extent value used for the `%{O}` tag and the offset value in
percentage_with_offset can be negative. Everything else is capped below
at 0.
The final pixel value of percentage_with_offset also caps below at 0.
* Fix parsing errors not being caught in config
* Print a proper error message for uncaught exceptions
* Cleanup module::get_output
All changes preserve the existing semantics
* Stop using remove_trailing_space in module::get_output
Instead, we first check if the current tag is built, and only if it is,
the spacing is prepended.
* Remove unused imports
* Restore old behavior
If there are two tags and the second one isn't built (module::build
returns false), the space in between them is removed.
For example in the mpd module:
format-online = <toggle> <label-song> foo
If mpd is not running, the mpd module will return false when trying to
build the `<label-song>` tag. If we don't remove the space between
`<toggle>` and `<label-song>`, we end up with two spaces between
`<toggle>` and `foo`.
This change is to match the old behavior where at least one trailing
space character was removed from the builder.
* Add changelog entry
* Remove unused setting
* Use percentage with offset for tray-offset
Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr>
Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
|
|
|
} catch (const std::exception& err) {
|
2019-10-27 22:19:36 +00:00
|
|
|
m_log.err("Invalid value for \"%s.%s\", using default value (reason: %s)", section, key, err.what());
|
|
|
|
return default_value;
|
2016-12-13 17:24:01 +00:00
|
|
|
}
|
2016-06-15 03:32:35 +00:00
|
|
|
}
|
|
|
|
|
2021-09-28 16:01:40 +00:00
|
|
|
/**
|
|
|
|
* Get list of key-value pairs starting with a prefix by section.
|
|
|
|
*
|
|
|
|
* Eg: if you have in config `env-FOO = bar`,
|
|
|
|
* get_with_prefix(section, "env-") will return [{"FOO", "bar"}]
|
|
|
|
*/
|
2021-09-28 20:07:30 +00:00
|
|
|
template <typename T = string>
|
|
|
|
vector<pair<string, T>> get_with_prefix(const string& section, const string& key_prefix) const {
|
2021-09-28 16:01:40 +00:00
|
|
|
auto it = m_sections.find(section);
|
|
|
|
if (it == m_sections.end()) {
|
|
|
|
throw key_error("Missing section \"" + section + "\"");
|
|
|
|
}
|
|
|
|
|
2021-09-28 20:07:30 +00:00
|
|
|
vector<pair<string, T>> list;
|
2021-09-28 16:01:40 +00:00
|
|
|
for (const auto& kv_pair : it->second) {
|
|
|
|
const auto& key = kv_pair.first;
|
|
|
|
|
|
|
|
if (key.substr(0, key_prefix.size()) == key_prefix) {
|
2021-09-28 20:07:30 +00:00
|
|
|
const T& val = get<T>(section, key);
|
2021-09-28 16:01:40 +00:00
|
|
|
list.emplace_back(key.substr(key_prefix.size()), val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2016-06-15 03:32:35 +00:00
|
|
|
/**
|
|
|
|
* Get list of values for the current bar by name
|
|
|
|
*/
|
2016-12-30 22:32:05 +00:00
|
|
|
template <typename T = string>
|
2016-12-13 17:24:01 +00:00
|
|
|
vector<T> get_list(const string& key) const {
|
2016-12-14 04:12:15 +00:00
|
|
|
return get_list<T>(section(), key);
|
2016-06-15 03:32:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get list of values by section and parameter name
|
|
|
|
*/
|
2016-12-30 22:32:05 +00:00
|
|
|
template <typename T = string>
|
2016-12-13 17:24:01 +00:00
|
|
|
vector<T> get_list(const string& section, const string& key) const {
|
2016-12-15 16:13:15 +00:00
|
|
|
vector<T> results;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
try {
|
|
|
|
string string_value{get<string>(section, key + "-" + to_string(results.size()))};
|
2016-12-15 19:57:03 +00:00
|
|
|
T value{convert<T>(string{string_value})};
|
2016-12-15 16:13:15 +00:00
|
|
|
|
|
|
|
if (!string_value.empty()) {
|
|
|
|
results.emplace_back(dereference<T>(section, key, move(string_value), move(value)));
|
|
|
|
} else {
|
|
|
|
results.emplace_back(move(value));
|
|
|
|
}
|
|
|
|
} catch (const key_error& err) {
|
|
|
|
break;
|
2016-12-13 17:24:01 +00:00
|
|
|
}
|
2016-06-15 03:32:35 +00:00
|
|
|
}
|
|
|
|
|
2016-12-15 16:13:15 +00:00
|
|
|
if (results.empty()) {
|
2017-01-26 19:10:33 +00:00
|
|
|
throw key_error("Missing parameter \"" + section + "." + key + "-0\"");
|
2016-12-15 16:13:15 +00:00
|
|
|
}
|
2016-06-15 03:32:35 +00:00
|
|
|
|
2016-12-15 16:13:15 +00:00
|
|
|
return results;
|
2016-06-15 03:32:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get list of values by section and parameter name
|
|
|
|
* with a default list in case the list isn't defined
|
|
|
|
*/
|
2016-12-30 22:32:05 +00:00
|
|
|
template <typename T = string>
|
2016-12-13 17:24:01 +00:00
|
|
|
vector<T> get_list(const string& section, const string& key, const vector<T>& default_value) const {
|
2016-12-15 16:13:15 +00:00
|
|
|
vector<T> results;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
try {
|
|
|
|
string string_value{get<string>(section, key + "-" + to_string(results.size()))};
|
2016-12-15 19:57:03 +00:00
|
|
|
T value{convert<T>(string{string_value})};
|
2016-12-15 16:13:15 +00:00
|
|
|
|
|
|
|
if (!string_value.empty()) {
|
|
|
|
results.emplace_back(dereference<T>(section, key, move(string_value), move(value)));
|
|
|
|
} else {
|
|
|
|
results.emplace_back(move(value));
|
|
|
|
}
|
|
|
|
} catch (const key_error& err) {
|
|
|
|
break;
|
Add units support (POINT, PIXEL, SPACE) (#2578)
* add units support (POINT, PIXEL, SPACE) for polybar
- add a size_with_unit struct
- add a geometry_format_values struct
- move dpi initialisation from renderer.cpp to bar.cpp
- add a string to size_with_unit converter
- add point support (with pt)
- add pixel support (with px)
* Fix unit test compilation
* clang-format
* Better names
The old names didn't really capture the purpose of the structs and
function.
space_type -> spacing_type
space_size -> spacing_val
size_type -> extent_type
geometry -> extent_val
geometry_format_values -> percentage_with_offset
* Remove parse_size_with_unit
No longer needed. The convert<spacing_val> function in config.cpp
already does all the work for us and always setting the type to pixel
was wrong.
In addition, line-size should not be of type spacing_val but extent_val.
* Cleanup
I tried to address most of my comments on the old PR
* Fix renderer width calculation
We can't just blindly add the x difference to the width because for
example the width should increase if x < width and the increase keeps
x < width.
Similarly, we can't just add the offset to the width.
* Rename geom_format_to_pixels to percentage_with_offset_to_pixel
* Cleanup
* Apply suggested changes from Patrick on GitHub
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* Update src/components/bar.cpp
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* Update src/components/config.cpp
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* Update src/components/builder.cpp
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* Update src/components/builder.cpp
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* config: Use stod for parsing percentage
* Use stof instead of strtof
* units: Fix test edge cases
* Remove unnecessary clang-format toggle
* Use percentage_with_offset for margin-{top,bottom}
* Support negative extent values
* Rename unit to units and create a cpp file
* Move percentage_with_offset_to_pixel unit test to units
* Add unit tests for units_utils
* Clarify when and how negative spacing/extent is allowed
Negative spacing is never allowed and produces a config error.
Extents allow negative values in theory, but only a few use-cases accept
it.
Only the extent value used for the `%{O}` tag and the offset value in
percentage_with_offset can be negative. Everything else is capped below
at 0.
The final pixel value of percentage_with_offset also caps below at 0.
* Fix parsing errors not being caught in config
* Print a proper error message for uncaught exceptions
* Cleanup module::get_output
All changes preserve the existing semantics
* Stop using remove_trailing_space in module::get_output
Instead, we first check if the current tag is built, and only if it is,
the spacing is prepended.
* Remove unused imports
* Restore old behavior
If there are two tags and the second one isn't built (module::build
returns false), the space in between them is removed.
For example in the mpd module:
format-online = <toggle> <label-song> foo
If mpd is not running, the mpd module will return false when trying to
build the `<label-song>` tag. If we don't remove the space between
`<toggle>` and `<label-song>`, we end up with two spaces between
`<toggle>` and `foo`.
This change is to match the old behavior where at least one trailing
space character was removed from the builder.
* Add changelog entry
* Remove unused setting
* Use percentage with offset for tray-offset
Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr>
Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
|
|
|
} catch (const std::exception& err) {
|
2019-10-27 22:19:36 +00:00
|
|
|
m_log.err("Invalid value in list \"%s.%s\", using list as-is (reason: %s)", section, key, err.what());
|
|
|
|
return default_value;
|
2016-12-13 17:24:01 +00:00
|
|
|
}
|
2016-06-15 03:32:35 +00:00
|
|
|
}
|
|
|
|
|
2016-12-15 16:13:15 +00:00
|
|
|
if (!results.empty()) {
|
|
|
|
return results;
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
return default_value;
|
2016-06-15 03:32:35 +00:00
|
|
|
}
|
|
|
|
|
2021-09-12 20:48:27 +00:00
|
|
|
void ignore_key(const string& section, const string& key) const;
|
|
|
|
|
2016-12-14 04:12:15 +00:00
|
|
|
/**
|
|
|
|
* Attempt to load value using the deprecated key name. If successful show a
|
|
|
|
* warning message. If it fails load the value using the new key and given
|
|
|
|
* fallback value
|
|
|
|
*/
|
2016-12-30 22:32:05 +00:00
|
|
|
template <typename T = string>
|
2016-12-14 04:12:15 +00:00
|
|
|
T deprecated(const string& section, const string& old, const string& newkey, const T& fallback) const {
|
|
|
|
try {
|
|
|
|
T value{get<T>(section, old)};
|
|
|
|
warn_deprecated(section, old, newkey);
|
|
|
|
return value;
|
|
|
|
} catch (const key_error& err) {
|
|
|
|
return get<T>(section, newkey, fallback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-11-04 15:08:54 +00:00
|
|
|
* \see deprecated<T>
|
2016-12-14 04:12:15 +00:00
|
|
|
*/
|
2016-12-30 22:32:05 +00:00
|
|
|
template <typename T = string>
|
2016-12-14 04:12:15 +00:00
|
|
|
T deprecated_list(const string& section, const string& old, const string& newkey, const vector<T>& fallback) const {
|
|
|
|
try {
|
|
|
|
vector<T> value{get_list<T>(section, old)};
|
|
|
|
warn_deprecated(section, old, newkey);
|
|
|
|
return value;
|
|
|
|
} catch (const key_error& err) {
|
|
|
|
return get_list<T>(section, newkey, fallback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-15 03:32:35 +00:00
|
|
|
protected:
|
2016-12-13 17:24:01 +00:00
|
|
|
void copy_inherited();
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T convert(string&& value) const;
|
|
|
|
|
2016-06-15 03:32:35 +00:00
|
|
|
/**
|
2016-11-18 16:40:16 +00:00
|
|
|
* Dereference value reference
|
2016-06-15 03:32:35 +00:00
|
|
|
*/
|
|
|
|
template <typename T>
|
2016-12-14 19:14:31 +00:00
|
|
|
T dereference(const string& section, const string& key, const string& var, const T& fallback) const {
|
2016-11-18 16:40:16 +00:00
|
|
|
if (var.substr(0, 2) != "${" || var.substr(var.length() - 1) != "}") {
|
2016-12-13 17:24:01 +00:00
|
|
|
return fallback;
|
2016-11-18 16:40:16 +00:00
|
|
|
}
|
2016-06-15 03:32:35 +00:00
|
|
|
|
2016-11-18 16:40:16 +00:00
|
|
|
auto path = var.substr(2, var.length() - 3);
|
|
|
|
size_t pos;
|
2016-06-15 03:32:35 +00:00
|
|
|
|
2016-12-13 17:24:01 +00:00
|
|
|
if (path.compare(0, 4, "env:") == 0) {
|
2017-01-20 01:25:54 +00:00
|
|
|
return dereference_env<T>(path.substr(4));
|
2016-12-13 17:24:01 +00:00
|
|
|
} else if (path.compare(0, 5, "xrdb:") == 0) {
|
2017-01-20 01:25:54 +00:00
|
|
|
return dereference_xrdb<T>(path.substr(5));
|
2016-12-19 21:01:37 +00:00
|
|
|
} else if (path.compare(0, 5, "file:") == 0) {
|
2017-01-20 01:25:54 +00:00
|
|
|
return dereference_file<T>(path.substr(5));
|
2016-11-18 16:40:16 +00:00
|
|
|
} else if ((pos = path.find(".")) != string::npos) {
|
2016-11-19 18:18:28 +00:00
|
|
|
return dereference_local<T>(path.substr(0, pos), path.substr(pos + 1), section);
|
2016-11-18 16:40:16 +00:00
|
|
|
} else {
|
2017-01-26 19:10:33 +00:00
|
|
|
throw value_error("Invalid reference defined at \"" + section + "." + key + "\"");
|
2016-06-15 03:32:35 +00:00
|
|
|
}
|
2016-11-18 16:40:16 +00:00
|
|
|
}
|
2016-06-15 03:32:35 +00:00
|
|
|
|
2016-11-18 16:40:16 +00:00
|
|
|
/**
|
|
|
|
* Dereference local value reference defined using:
|
|
|
|
* ${root.key}
|
2017-01-26 18:33:14 +00:00
|
|
|
* ${root.key:fallback}
|
2016-11-18 16:40:16 +00:00
|
|
|
* ${self.key}
|
2017-01-26 18:33:14 +00:00
|
|
|
* ${self.key:fallback}
|
2016-11-18 16:40:16 +00:00
|
|
|
* ${section.key}
|
2017-01-26 18:33:14 +00:00
|
|
|
* ${section.key:fallback}
|
2016-11-18 16:40:16 +00:00
|
|
|
*/
|
|
|
|
template <typename T>
|
2016-12-13 17:24:01 +00:00
|
|
|
T dereference_local(string section, const string& key, const string& current_section) const {
|
|
|
|
if (section == "BAR") {
|
2016-12-15 16:13:15 +00:00
|
|
|
m_log.warn("${BAR.key} is deprecated. Use ${root.key} instead");
|
2016-12-13 17:24:01 +00:00
|
|
|
}
|
2016-10-19 07:16:08 +00:00
|
|
|
|
2016-12-14 04:12:15 +00:00
|
|
|
section = string_util::replace(section, "BAR", this->section(), 0, 3);
|
|
|
|
section = string_util::replace(section, "root", this->section(), 0, 4);
|
2016-11-19 18:18:28 +00:00
|
|
|
section = string_util::replace(section, "self", current_section, 0, 4);
|
2016-06-15 03:32:35 +00:00
|
|
|
|
2016-12-15 16:13:15 +00:00
|
|
|
try {
|
2016-12-15 19:57:03 +00:00
|
|
|
string string_value{get<string>(section, key)};
|
|
|
|
T result{convert<T>(string{string_value})};
|
|
|
|
return dereference<T>(string(section), move(key), move(string_value), move(result));
|
2016-12-15 16:13:15 +00:00
|
|
|
} catch (const key_error& err) {
|
2017-01-26 18:33:14 +00:00
|
|
|
size_t pos;
|
|
|
|
if ((pos = key.find(':')) != string::npos) {
|
|
|
|
string fallback = key.substr(pos + 1);
|
2017-01-26 19:10:33 +00:00
|
|
|
m_log.info("The reference ${%s.%s} does not exist, using defined fallback value \"%s\"", section,
|
|
|
|
key.substr(0, pos), fallback);
|
2017-01-26 18:33:14 +00:00
|
|
|
return convert<T>(move(fallback));
|
|
|
|
}
|
|
|
|
throw value_error("The reference ${" + section + "." + key + "} does not exist (no fallback set)");
|
2016-12-13 17:24:01 +00:00
|
|
|
}
|
2016-11-18 16:40:16 +00:00
|
|
|
}
|
2016-10-19 07:16:08 +00:00
|
|
|
|
2016-11-18 16:40:16 +00:00
|
|
|
/**
|
|
|
|
* Dereference environment variable reference defined using:
|
|
|
|
* ${env:key}
|
|
|
|
* ${env:key:fallback value}
|
|
|
|
*/
|
|
|
|
template <typename T>
|
2017-01-20 01:25:54 +00:00
|
|
|
T dereference_env(string var) const {
|
2016-11-18 16:40:16 +00:00
|
|
|
size_t pos;
|
2017-01-20 01:25:54 +00:00
|
|
|
string env_default;
|
2019-07-01 21:33:01 +00:00
|
|
|
/*
|
|
|
|
* This is needed because with only the string we cannot distinguish
|
|
|
|
* between an empty string as default and not default
|
|
|
|
*/
|
|
|
|
bool has_default = false;
|
2016-06-15 03:32:35 +00:00
|
|
|
|
2017-01-26 18:33:14 +00:00
|
|
|
if ((pos = var.find(':')) != string::npos) {
|
2016-12-14 19:14:31 +00:00
|
|
|
env_default = var.substr(pos + 1);
|
2019-07-01 21:33:01 +00:00
|
|
|
has_default = true;
|
2016-11-18 16:40:16 +00:00
|
|
|
var.erase(pos);
|
|
|
|
}
|
2016-06-15 03:32:35 +00:00
|
|
|
|
2019-07-01 21:33:01 +00:00
|
|
|
if (env_util::has(var)) {
|
|
|
|
string env_value{env_util::get(var)};
|
2017-01-20 01:31:55 +00:00
|
|
|
m_log.info("Environment var reference ${%s} found (value=%s)", var, env_value);
|
2016-12-14 19:14:31 +00:00
|
|
|
return convert<T>(move(env_value));
|
2019-07-01 21:33:01 +00:00
|
|
|
} else if (has_default) {
|
2017-01-20 01:31:55 +00:00
|
|
|
m_log.info("Environment var ${%s} is undefined, using defined fallback value \"%s\"", var, env_default);
|
|
|
|
return convert<T>(move(env_default));
|
2016-12-13 17:24:01 +00:00
|
|
|
} else {
|
2017-01-20 01:31:55 +00:00
|
|
|
throw value_error(sstream() << "Environment var ${" << var << "} does not exist (no fallback set)");
|
2016-12-13 17:24:01 +00:00
|
|
|
}
|
2016-11-18 16:40:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Dereference X resource db value defined using:
|
|
|
|
* ${xrdb:key}
|
|
|
|
* ${xrdb:key:fallback value}
|
|
|
|
*/
|
|
|
|
template <typename T>
|
2017-01-20 01:25:54 +00:00
|
|
|
T dereference_xrdb(string var) const {
|
2016-11-18 16:40:16 +00:00
|
|
|
size_t pos;
|
2017-01-26 16:17:02 +00:00
|
|
|
#if not WITH_XRM
|
2017-01-26 20:34:38 +00:00
|
|
|
m_log.warn("No built-in support to dereference ${xrdb:%s} references (requires `xcb-util-xrm`)", var);
|
2017-01-26 18:33:14 +00:00
|
|
|
if ((pos = var.find(':')) != string::npos) {
|
2017-01-26 16:17:02 +00:00
|
|
|
return convert<T>(var.substr(pos + 1));
|
2017-01-20 01:25:54 +00:00
|
|
|
}
|
2017-01-26 16:17:02 +00:00
|
|
|
return convert<T>("");
|
2017-01-20 01:25:54 +00:00
|
|
|
#else
|
|
|
|
if (!m_xrm) {
|
|
|
|
throw application_error("xrm is not initialized");
|
|
|
|
}
|
2016-11-18 16:40:16 +00:00
|
|
|
|
2017-01-20 01:25:54 +00:00
|
|
|
string fallback;
|
2019-07-01 21:33:01 +00:00
|
|
|
bool has_fallback = false;
|
2017-01-26 18:33:14 +00:00
|
|
|
if ((pos = var.find(':')) != string::npos) {
|
2017-01-20 01:25:54 +00:00
|
|
|
fallback = var.substr(pos + 1);
|
2019-07-01 21:33:01 +00:00
|
|
|
has_fallback = true;
|
2017-01-20 01:25:54 +00:00
|
|
|
var.erase(pos);
|
2016-11-18 16:40:16 +00:00
|
|
|
}
|
2016-06-15 03:32:35 +00:00
|
|
|
|
2017-01-20 01:25:54 +00:00
|
|
|
try {
|
|
|
|
auto value = m_xrm->require<string>(var.c_str());
|
|
|
|
m_log.info("Found matching X resource \"%s\" (value=%s)", var, value);
|
|
|
|
return convert<T>(move(value));
|
|
|
|
} catch (const xresource_error& err) {
|
2019-07-01 21:33:01 +00:00
|
|
|
if (has_fallback) {
|
2020-04-21 22:14:02 +00:00
|
|
|
m_log.info("%s, using defined fallback value \"%s\"", err.what(), fallback);
|
2017-01-20 01:25:54 +00:00
|
|
|
return convert<T>(move(fallback));
|
|
|
|
}
|
|
|
|
throw value_error(sstream() << err.what() << " (no fallback set)");
|
|
|
|
}
|
|
|
|
#endif
|
2016-06-15 03:32:35 +00:00
|
|
|
}
|
|
|
|
|
2016-12-19 21:01:37 +00:00
|
|
|
/**
|
|
|
|
* Dereference file reference by reading its contents
|
|
|
|
* ${file:/absolute/file/path}
|
2017-01-20 01:31:55 +00:00
|
|
|
* ${file:/absolute/file/path:fallback value}
|
2016-12-19 21:01:37 +00:00
|
|
|
*/
|
|
|
|
template <typename T>
|
2017-01-20 01:25:54 +00:00
|
|
|
T dereference_file(string var) const {
|
|
|
|
size_t pos;
|
|
|
|
string fallback;
|
2019-07-01 21:33:01 +00:00
|
|
|
bool has_fallback = false;
|
2017-01-26 18:33:14 +00:00
|
|
|
if ((pos = var.find(':')) != string::npos) {
|
2017-01-20 01:25:54 +00:00
|
|
|
fallback = var.substr(pos + 1);
|
2019-07-01 21:33:01 +00:00
|
|
|
has_fallback = true;
|
2017-01-20 01:25:54 +00:00
|
|
|
var.erase(pos);
|
2016-12-19 21:01:37 +00:00
|
|
|
}
|
2017-09-04 21:00:35 +00:00
|
|
|
var = file_util::expand(var);
|
2016-12-19 21:01:37 +00:00
|
|
|
|
2017-01-20 01:31:55 +00:00
|
|
|
if (file_util::exists(var)) {
|
|
|
|
m_log.info("File reference \"%s\" found", var);
|
|
|
|
return convert<T>(string_util::trim(file_util::contents(var), '\n'));
|
2019-07-01 21:33:01 +00:00
|
|
|
} else if (has_fallback) {
|
2020-04-21 22:14:02 +00:00
|
|
|
m_log.info("File reference \"%s\" not found, using defined fallback value \"%s\"", var, fallback);
|
2017-01-20 01:31:55 +00:00
|
|
|
return convert<T>(move(fallback));
|
|
|
|
} else {
|
|
|
|
throw value_error(sstream() << "The file \"" << var << "\" does not exist (no fallback set)");
|
|
|
|
}
|
2016-12-19 21:01:37 +00:00
|
|
|
}
|
|
|
|
|
2016-06-15 03:32:35 +00:00
|
|
|
private:
|
2016-12-15 16:13:15 +00:00
|
|
|
const logger& m_log;
|
2016-06-15 03:32:35 +00:00
|
|
|
string m_file;
|
2016-12-14 04:12:15 +00:00
|
|
|
string m_barname;
|
2016-12-15 02:30:41 +00:00
|
|
|
sectionmap_t m_sections{};
|
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
|
|
|
|
|
|
|
/**
|
|
|
|
* Absolute path of all files that were parsed in the process of parsing the
|
|
|
|
* config (Path of the main config file also included)
|
|
|
|
*/
|
|
|
|
file_list m_included;
|
2017-01-26 16:17:02 +00:00
|
|
|
#if WITH_XRM
|
2017-01-20 01:25:54 +00:00
|
|
|
unique_ptr<xresource_manager> m_xrm;
|
|
|
|
#endif
|
2016-06-15 03:32:35 +00:00
|
|
|
};
|
|
|
|
|
2016-11-19 05:22:44 +00:00
|
|
|
POLYBAR_NS_END
|