[wip] Support rc.yaml

Tried with:

    ---
    theme:
    - name: Adwaita-light
    - cornerRadius: 2
    ...

Needs lots of testing.
This commit is contained in:
Johan Malm 2024-08-13 20:58:51 +01:00
parent 6687640665
commit 608246aac8
5 changed files with 173 additions and 8 deletions

11
include/config/yaml2xml.h Normal file
View file

@ -0,0 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef LABWC_YAML2XML_H
#define LABWC_YAML2XML_H
#include <stdbool.h>
#include <stdio.h>
struct buf;
bool yaml_to_xml(struct buf *buffer, const char *filename);
#endif /* LABWC_YAML2XML_H */

View file

@ -72,6 +72,7 @@ pixman = dependency('pixman-1')
math = cc.find_library('m')
png = dependency('libpng')
svg = dependency('librsvg-2.0', version: '>=2.46', required: false)
yaml = dependency('yaml-0.1')
if get_option('xwayland').enabled() and not wlroots_has_xwayland
error('no wlroots Xwayland support')
@ -119,6 +120,7 @@ labwc_deps = [
pixman,
math,
png,
yaml,
]
if have_rsvg
labwc_deps += [

View file

@ -7,4 +7,5 @@ labwc_sources += files(
'tablet.c',
'tablet-tool.c',
'libinput.c',
'yaml2xml.c',
)

View file

@ -15,6 +15,7 @@
#include <wlr/util/box.h>
#include <wlr/util/log.h>
#include "action.h"
#include "common/buf.h"
#include "common/dir.h"
#include "common/list.h"
#include "common/macros.h"
@ -35,6 +36,7 @@
#include "view.h"
#include "window-rules.h"
#include "workspaces.h"
#include "config/yaml2xml.h"
static bool in_regions;
static bool in_usable_area_override;
@ -1651,19 +1653,19 @@ rcxml_read(const char *filename)
{
rcxml_init();
struct wl_list paths;
struct wl_list paths_xml, paths_yaml;
if (filename) {
/* Honour command line argument -c <filename> */
wl_list_init(&paths);
wl_list_init(&paths_xml);
struct path *path = znew(*path);
path->string = xstrdup(filename);
wl_list_append(&paths, &path->link);
wl_list_append(&paths_xml, &path->link);
} else {
paths_config_create(&paths, "rc.xml");
paths_config_create(&paths_xml, "rc.xml");
paths_config_create(&paths_yaml, "rc.yaml");
}
/* Reading file into buffer before parsing - better for unit tests */
bool should_merge_config = rc.merge_config;
struct wl_list *(*iter)(struct wl_list *list);
iter = should_merge_config ? paths_get_prev : paths_get_next;
@ -1677,15 +1679,17 @@ rcxml_read(const char *filename)
*
* If merging, we iterate backwards (least important XDG Base Dir first)
* and keep going.
*
* We start with the XML version if it exists.
*/
for (struct wl_list *elm = iter(&paths); elm != &paths; elm = iter(elm)) {
for (struct wl_list *elm = iter(&paths_xml); elm != &paths_xml; elm = iter(elm)) {
struct path *path = wl_container_of(elm, path, link);
FILE *stream = fopen(path->string, "r");
if (!stream) {
continue;
}
wlr_log(WLR_INFO, "read config file %s", path->string);
wlr_log(WLR_INFO, "read xml config file %s", path->string);
struct buf b = BUF_INIT;
char *line = NULL;
@ -1705,7 +1709,26 @@ rcxml_read(const char *filename)
break;
}
};
paths_destroy(&paths);
/* ...then we do the YAML verion */
for (struct wl_list *elm = iter(&paths_yaml); elm != &paths_yaml; elm = iter(elm)) {
struct path *path = wl_container_of(elm, path, link);
wlr_log(WLR_INFO, "read yaml config file %s", path->string);
struct buf b = BUF_INIT;
bool success = yaml_to_xml(&b, path->string);
if (success) {
rcxml_parse_xml(&b);
}
buf_reset(&b);
if (!should_merge_config) {
break;
}
};
paths_destroy(&paths_xml);
paths_destroy(&paths_yaml);
post_processing();
validate();
}

128
src/config/yaml2xml.c Normal file
View file

@ -0,0 +1,128 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <assert.h>
#include <yaml.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <wlr/util/log.h>
#include "common/buf.h"
#include "common/mem.h"
#include "config/yaml2xml.h"
static struct element *elements;
static int nr_elements, alloc_elements;
struct element {
char name[64];
};
static struct element *
push(const char *name)
{
if (nr_elements == alloc_elements) {
alloc_elements = (alloc_elements + 16) * 2;
elements = xrealloc(elements,
alloc_elements * sizeof(struct element));
}
struct element *element = elements + nr_elements;
memset(element, 0, sizeof(*element));
nr_elements++;
strncpy(element->name, name, sizeof(element->name));
element->name[sizeof(element->name) - 1] = '\0';
return element;
}
static void
pop(char *buffer, size_t len)
{
strncpy(buffer, elements[nr_elements-1].name, len);
nr_elements--;
}
static void
process_one_event(struct buf *buffer, yaml_event_t *event)
{
static bool in_scalar;
switch (event->type) {
case YAML_NO_EVENT:
case YAML_ALIAS_EVENT:
case YAML_MAPPING_START_EVENT:
case YAML_MAPPING_END_EVENT:
case YAML_STREAM_START_EVENT:
case YAML_STREAM_END_EVENT:
break;
case YAML_DOCUMENT_START_EVENT:
buf_add(buffer, "<?xml version=\"1.0\"?>\n");
buf_add(buffer, "<labwc_config>\n");
break;
case YAML_DOCUMENT_END_EVENT:
buf_add(buffer, "</labwc_config>\n");
break;
case YAML_SCALAR_EVENT:
if (in_scalar) {
char element[64] = { 0 };
pop(element, sizeof(element));
buf_add(buffer, (char *)event->data.scalar.value);
buf_add(buffer, "</");
buf_add(buffer, element);
buf_add(buffer, ">\n");
in_scalar = false;
} else {
char *value = (char *)event->data.scalar.value;
buf_add(buffer, "<");
buf_add(buffer, value);
buf_add(buffer, ">");
push(value);
in_scalar = true;
}
break;
case YAML_SEQUENCE_START_EVENT:
assert(in_scalar);
buf_add(buffer, "\n");
in_scalar = false;
break;
case YAML_SEQUENCE_END_EVENT:
char element[64] = { 0 };
pop(element, sizeof(element));
buf_add(buffer, "</");
buf_add(buffer, element);
buf_add(buffer, ">\n");
break;
}
}
bool
yaml_to_xml(struct buf *buffer, const char *filename)
{
bool ret = false;
FILE *f = fopen(filename, "r");
if (!f) {
return false;
}
yaml_parser_t parser;
yaml_parser_initialize(&parser);
yaml_parser_set_input_file(&parser, f);
yaml_event_type_t event_type = 0;
while (event_type != YAML_STREAM_END_EVENT) {
yaml_event_t event;
int success = yaml_parser_parse(&parser, &event);
if (!success) {
wlr_log(WLR_ERROR, "yaml parse: %s", parser.problem);
yaml_parser_delete(&parser);
goto out;
}
process_one_event(buffer, &event);
event_type = event.type;
yaml_event_delete(&event);
}
yaml_parser_delete(&parser);
free(elements);
nr_elements = 0;
alloc_elements = 0;
ret = true;
out:
fclose(f);
return ret;
}