Skip to content

Commit

Permalink
WIP: compose: add iteration API
Browse files Browse the repository at this point in the history
Allow users to iterate the entries in a compose table. This is useful
for other projects which want programmable access to the sequences,
without having to write their own parser.

TODO:
- Convert to use heap instead of recursion.
- Convert to an iterator API instead of `for_each` callback API - it
  sucks.
- Tests in `test/compose.c`.
- Check doxygen output.
- Convert tools/compose.c to an `xkbcli compose`:
    - Add support for `--file`.
    - Better names for the `--locale` arguments.
    - Add `--format` (currently only `text-v1`).
    - Check return value of `printf`s.
    - Add to `xkbcli`.
    - Test it in `test/tool-option-parsing.py`.
    - Write manpage.

Signed-off-by: Ran Benita <[email protected]>
  • Loading branch information
bluetech authored and wismill committed Sep 16, 2023
1 parent c1b6c79 commit d865f12
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 4 deletions.
89 changes: 89 additions & 0 deletions include/xkbcommon/xkbcommon-compose.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,95 @@ xkb_compose_table_ref(struct xkb_compose_table *table);
void
xkb_compose_table_unref(struct xkb_compose_table *table);

/**
* @struct xkb_compose_table_entry
* Opaque Compose table entry object.
*
* Represents a single entry in a Compose file in the iteration API.
* It is immutable.
*
* @sa xkb_compose_table_for_each
* @since 1.5.0
*/
struct xkb_compose_table_entry;

/**
* Get the left-hand side of a Compose table entry.
*
* For example, given the following entry
* \<dead_tilde> \<space> : "~" asciitilde # TILDE
* returns `{XKB_KEY_dead_tilde, XKB_KEY_space}`.
*
* @returns The array of left-hand side keysyms. The number of keysyms
* is returned in the nsyms out-parameter.
*
* @memberof xkb_compose_table_entry
* @since 1.5.0
*/
const xkb_keysym_t *
xkb_compose_table_entry_lhs(struct xkb_compose_table_entry *entry,
size_t *nsyms);

/**
* Get the right-hand result keysym of a Compose table entry.
*
* For example, given the following entry
* \<dead_tilde> \<space> : "~" asciitilde # TILDE
* it will return `XKB_KEY_asciitilde`.
*
* The keysym is optional; if the entry does not specify a keysym,
* returns `XKB_KEY_NoSymbol`.
*
* @memberof xkb_compose_table_entry
* @since 1.5.0
*/
xkb_keysym_t
xkb_compose_table_entry_keysym(struct xkb_compose_table_entry *entry);

/**
* Get the right-hand result string of a Compose table entry.
*
* The string is UTF-8 encoded and `\0`-terminated.
*
* For example, given the following entry
* \<dead_tilde> \<space> : "~" asciitilde # TILDE
* it will return `"~"`.
*
* The string is optional; if the entry does not specify a string,
* returns the empty string.
*
* @memberof xkb_compose_table_entry
* @since 1.5.0
*/
const char *
xkb_compose_table_entry_utf8(struct xkb_compose_table_entry *entry);

/**
* The iterator function type used by xkb_compose_table_for_each().
*
* @sa xkb_compose_table_for_each
* @memberof xkb_compose
* @since 1.5.0
*/
typedef void
(*xkb_compose_table_iter_t)(struct xkb_compose_table_entry *entry,
void *data);

/**
* Run a specified function for every valid entry in the table.
*
* The entries are returned in lexicographic order of the left-hand
* side of entries. This does not correspond to the order in which
* the entries appear in the Compose file.
*
* @memberof xkb_compose_table
* @since 1.5.0
*/
void
xkb_compose_table_for_each(struct xkb_compose_table *table,
xkb_compose_table_iter_t iter,
void *data);

/** Flags for compose state creation. */
enum xkb_compose_state_flags {
/** Do not apply any flags. */
Expand Down
3 changes: 0 additions & 3 deletions src/compose/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,6 @@ OR PERFORMANCE OF THIS SOFTWARE.
#include "utf8.h"
#include "parser.h"

#define MAX_LHS_LEN 10
#define MAX_INCLUDE_DEPTH 5

/*
* Grammar adapted from libX11/modules/im/ximcp/imLcPrs.c.
* See also the XCompose(5) manpage.
Expand Down
3 changes: 3 additions & 0 deletions src/compose/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
#ifndef COMPOSE_PARSER_H
#define COMPOSE_PARSER_H

#define MAX_LHS_LEN 10
#define MAX_INCLUDE_DEPTH 5

bool
parse_string(struct xkb_compose_table *table,
const char *string, size_t len,
Expand Down
62 changes: 62 additions & 0 deletions src/compose/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "table.h"
#include "parser.h"
#include "paths.h"
#include "xkbcommon/xkbcommon.h"

static struct xkb_compose_table *
xkb_compose_table_new(struct xkb_context *ctx,
Expand Down Expand Up @@ -226,3 +227,64 @@ xkb_compose_table_new_from_locale(struct xkb_context *ctx,
free(path);
return table;
}

XKB_EXPORT const xkb_keysym_t *
xkb_compose_table_entry_lhs(struct xkb_compose_table_entry *entry,
size_t *nsyms)
{
*nsyms = entry->nsyms;
return entry->syms;
}

XKB_EXPORT xkb_keysym_t
xkb_compose_table_entry_keysym(struct xkb_compose_table_entry *entry)
{
return entry->keysym;
}

XKB_EXPORT const char *
xkb_compose_table_entry_utf8(struct xkb_compose_table_entry *entry)
{
return entry->utf8;
}

static void
for_each_helper(struct xkb_compose_table *table,
xkb_compose_table_iter_t iter,
void *data,
xkb_keysym_t *syms,
size_t nsyms,
uint16_t p)
{
if (!p) {
return;
}
const struct compose_node *node = &darray_item(table->nodes, p);
for_each_helper(table, iter, data, syms, nsyms, node->lokid);
syms[nsyms++] = node->keysym;
if (node->is_leaf) {
struct xkb_compose_table_entry entry = {
.syms = syms,
.nsyms = nsyms,
.keysym = node->leaf.keysym,
.utf8 = &darray_item(table->utf8, node->leaf.utf8),
};
iter(&entry, data);
} else {
for_each_helper(table, iter, data, syms, nsyms, node->internal.eqkid);
}
nsyms--;
for_each_helper(table, iter, data, syms, nsyms, node->hikid);
}

XKB_EXPORT void
xkb_compose_table_for_each(struct xkb_compose_table *table,
xkb_compose_table_iter_t iter,
void *data)
{
if (darray_size(table->nodes) <= 1) {
return;
}
xkb_keysym_t syms[MAX_LHS_LEN];
for_each_helper(table, iter, data, syms, 0, 1);
}
7 changes: 7 additions & 0 deletions src/compose/table.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,11 @@ struct xkb_compose_table {
darray(struct compose_node) nodes;
};

struct xkb_compose_table_entry {
xkb_keysym_t *syms;
size_t nsyms;
xkb_keysym_t keysym;
const char *utf8;
};

#endif
29 changes: 28 additions & 1 deletion tools/compose.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <stdlib.h>

#include "xkbcommon/xkbcommon.h"
#include "xkbcommon/xkbcommon-keysyms.h"
#include "xkbcommon/xkbcommon-compose.h"

static void
Expand All @@ -44,6 +45,32 @@ usage(FILE *fp, char *progname)
);
}

static void
compose_table_print_cb(struct xkb_compose_table_entry *entry, void *data)
{
size_t nsyms;
const xkb_keysym_t *syms = xkb_compose_table_entry_lhs(entry, &nsyms);
char buf[128];
for (size_t i = 0; i < nsyms; i++) {
xkb_keysym_get_name(syms[i], buf, sizeof(buf));
printf("<%s>", buf);
if (i + 1 < nsyms) {
printf(" ");
}
}
printf(":");
const char *utf8 = xkb_compose_table_entry_utf8(entry);
if (*utf8 != '\0') {
printf(" \"%s\"", utf8);
}
const xkb_keysym_t keysym = xkb_compose_table_entry_keysym(entry);
if (keysym != XKB_KEY_NoSymbol) {
xkb_keysym_get_name(keysym, buf, sizeof(buf));
printf(" %s", buf);
}
printf("\n");
}

int
main(int argc, char *argv[])
{
Expand Down Expand Up @@ -116,7 +143,7 @@ main(int argc, char *argv[])
goto out;
}

printf("Compiled successfully from locale %s\n", locale);
xkb_compose_table_for_each(compose_table, compose_table_print_cb, NULL);

out:
xkb_compose_table_unref(compose_table);
Expand Down
8 changes: 8 additions & 0 deletions xkbcommon.map
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,11 @@ global:
xkb_utf32_to_keysym;
xkb_keymap_key_get_mods_for_level;
} V_0.8.0;

V_1.5.0 {
global:
xkb_compose_table_entry_lhs;
xkb_compose_table_entry_keysym;
xkb_compose_table_entry_utf8;
xkb_compose_table_for_each;
} V_1.0.0;

0 comments on commit d865f12

Please sign in to comment.