From 608246aac82f72e1786fde4d5e00745d98e73945 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Tue, 13 Aug 2024 20:58:51 +0100 Subject: [PATCH] [wip] Support rc.yaml Tried with: --- theme: - name: Adwaita-light - cornerRadius: 2 ... Needs lots of testing. --- include/config/yaml2xml.h | 11 ++++ meson.build | 2 + src/config/meson.build | 1 + src/config/rcxml.c | 39 +++++++++--- src/config/yaml2xml.c | 128 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 8 deletions(-) create mode 100644 include/config/yaml2xml.h create mode 100644 src/config/yaml2xml.c diff --git a/include/config/yaml2xml.h b/include/config/yaml2xml.h new file mode 100644 index 00000000..6d48241d --- /dev/null +++ b/include/config/yaml2xml.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef LABWC_YAML2XML_H +#define LABWC_YAML2XML_H +#include +#include + +struct buf; + +bool yaml_to_xml(struct buf *buffer, const char *filename); + +#endif /* LABWC_YAML2XML_H */ diff --git a/meson.build b/meson.build index 267b91b3..93d501c4 100644 --- a/meson.build +++ b/meson.build @@ -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 += [ diff --git a/src/config/meson.build b/src/config/meson.build index 70b1baa3..447e01c2 100644 --- a/src/config/meson.build +++ b/src/config/meson.build @@ -7,4 +7,5 @@ labwc_sources += files( 'tablet.c', 'tablet-tool.c', 'libinput.c', + 'yaml2xml.c', ) diff --git a/src/config/rcxml.c b/src/config/rcxml.c index da0bbde3..5762399c 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -15,6 +15,7 @@ #include #include #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 */ - 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(); } diff --git a/src/config/yaml2xml.c b/src/config/yaml2xml.c new file mode 100644 index 00000000..b5c9e0bd --- /dev/null +++ b/src/config/yaml2xml.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include +#include +#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, "\n"); + buf_add(buffer, "\n"); + break; + case YAML_DOCUMENT_END_EVENT: + buf_add(buffer, "\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, "\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, "\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; +}