* Assert API
*
* Helpers to check at runtime if a condition is true, and abort
- * otherwise.
+ * (exit) otherwise.
*/
#ifndef ECOLI_ASSERT_
#include <ecoli_parsed.h>
#include <ecoli_completed.h>
+struct ec_completed_item {
+ TAILQ_ENTRY(ec_completed_item) next;
+ enum ec_completed_type type;
+ const struct ec_node *node;
+ char *str;
+ char *display;
+ struct ec_keyval *attrs;
+
+ /* reverse order: [0] = last, [len-1] = root */
+ const struct ec_node **path;
+ size_t pathlen;
+};
+
struct ec_completed *ec_completed(void)
{
struct ec_completed *completed = NULL;
return 0;
}
+const char *
+ec_completed_item_get_str(const struct ec_completed_item *item)
+{
+ return item->str;
+}
+
+const char *
+ec_completed_item_get_display(const struct ec_completed_item *item)
+{
+ return item->display;
+}
+
+enum ec_completed_type
+ec_completed_item_get_type(const struct ec_completed_item *item)
+{
+ return item->type;
+}
+
void ec_completed_item_free(struct ec_completed_item *item)
{
if (item == NULL)
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+/**
+ * API for generating completions item on a node.
+ *
+ * This file provide helpers to list and manipulate the possible
+ * completions for a given input.
+ *
+ * XXX completed vs item
+ */
+
#ifndef ECOLI_COMPLETED_
#define ECOLI_COMPLETED_
EC_PARTIAL_MATCH,
};
-struct ec_completed_item {
- TAILQ_ENTRY(ec_completed_item) next;
- enum ec_completed_type type;
- const struct ec_node *node;
- char *str;
- char *display;
- struct ec_keyval *attrs;
-
- /* reverse order: [0] = last, [len-1] = root */
- const struct ec_node **path;
- size_t pathlen;
-};
+struct ec_completed_item;
TAILQ_HEAD(ec_completed_item_list, ec_completed_item);
struct ec_parsed *parsed_state,
const struct ec_strvec *strvec);
+/**
+ * Create a completion object (list of completion items).
+ *
+ *
+ */
struct ec_completed *ec_completed(void);
+/**
+ * Free a completion object and all its items.
+ *
+ *
+ */
+void ec_completed_free(struct ec_completed *completed);
+
+/**
+ *
+ *
+ *
+ */
+void ec_completed_dump(FILE *out,
+ const struct ec_completed *completed);
+
+
+/**
+ * Create a completion item.
+ *
+ *
+ */
struct ec_completed_item *
ec_completed_item(struct ec_parsed *state, const struct ec_node *node);
+
+/**
+ * Set type and value of a completion item.
+ *
+ *
+ */
int ec_completed_item_set(struct ec_completed_item *item,
enum ec_completed_type type, const char *str);
+
+/**
+ * Add a completion item to a completion list.
+ *
+ *
+ */
int ec_completed_item_add(struct ec_completed *completed,
struct ec_completed_item *item);
+
+/**
+ * Get the string value of a completion item.
+ *
+ *
+ */
+const char *
+ec_completed_item_get_str(const struct ec_completed_item *item);
+
+/**
+ * Get the display string value of a completion item.
+ *
+ *
+ */
+const char *
+ec_completed_item_get_display(const struct ec_completed_item *item);
+
+/**
+ * Get the type of a completion item.
+ *
+ *
+ */
+enum ec_completed_type
+ec_completed_item_get_type(const struct ec_completed_item *item);
+
+/**
+ *
+ *
+ *
+ */
void ec_completed_item_free(struct ec_completed_item *item);
+/**
+ * Set the display value of an item.
+ *
+ *
+ */
int ec_completed_item_set_display(struct ec_completed_item *item,
const char *display);
-void ec_completed_free(struct ec_completed *completed);
-void ec_completed_dump(FILE *out,
- const struct ec_completed *completed);
+/**
+ *
+ *
+ *
+ */
int
ec_node_default_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
struct ec_parsed *state,
const struct ec_strvec *strvec);
+/**
+ *
+ *
+ *
+ */
unsigned int ec_completed_count(
const struct ec_completed *completed,
enum ec_completed_type flags);
+/**
+ *
+ *
+ *
+ */
struct ec_completed_iter {
enum ec_completed_type type;
const struct ec_completed *completed;
const struct ec_completed_item *cur_match;
};
+/**
+ *
+ *
+ *
+ */
struct ec_completed_iter *
ec_completed_iter(struct ec_completed *completed,
enum ec_completed_type type);
+/**
+ *
+ *
+ *
+ */
const struct ec_completed_item *ec_completed_iter_next(
struct ec_completed_iter *iter);
+/**
+ *
+ *
+ *
+ */
void ec_completed_iter_free(struct ec_completed_iter *iter);
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+/**
+ * Register initialization routines.
+ */
+
#ifndef ECOLI_INIT_
#define ECOLI_INIT_
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+/**
+ * Interface to manage the ecoli nodes.
+ *
+ * A node is a main structure of the ecoli library, used to define how
+ * to match and complete the input tokens. A node is a generic object
+ * that implements:
+ * - a parse(node, input) method: check if an input matches
+ * - a complete(node, input) method: return possible completions for
+ * a given input
+ * - some other methods to initialize, free, ...
+ *
+ * One basic example is the string node (ec_node_str). A node
+ * ec_node_str("foo") will match any token list starting with "foo",
+ * for example:
+ * - ["foo"]
+ * - ["foo", "bar", ...]
+ * But will not match:
+ * - []
+ * - ["bar", ...]
+ *
+ * A node ec_node_str("foo") will complete with "foo" if the input
+ * contains one token, with the same beginning than "foo":
+ * - [""]
+ * - ["f"]
+ * - ["fo"]
+ * - ["foo"]
+ * But it will not complete:
+ * - []
+ * - ["bar"]
+ * - ["f", ""]
+ * - ["", "f"]
+ *
+ * A node can have child nodes. For instance, a sequence node
+ * ec_node_seq(ec_node_str("foo"), ec_node_str("bar")) will match
+ * ["foo", "bar"].
+ */
+
#ifndef ECOLI_NODE_
#define ECOLI_NODE_
#ifndef ECOLI_NODE_ANY_
#define ECOLI_NODE_ANY_
+/* no specific API for this node */
+
#endif
return parsed->strvec;
}
-/* number of parsed strings in the vector */
+/* number of strings in the parsed vector */
size_t ec_parsed_len(const struct ec_parsed *parsed)
{
if (parsed == NULL || parsed->strvec == NULL)
#define EC_PARSED_NOMATCH INT_MIN
/* internal: used by nodes
*
- * state is the current parse tree, which is built bit by bit while
+ * state is the current parse tree, which is built piece by piece while
* parsing the node tree: ec_node_parse_child() creates a new child in
* this state parse tree, and calls the parse() method for the child
* node, with state pointing to this new child. If it does not match,
/* only check matching completions */
iter = ec_completed_iter(c, EC_MATCH);
while ((item = ec_completed_iter_next(iter)) != NULL) {
- if (item->str != NULL && strcmp(item->str, s) == 0)
+ const char *str = ec_completed_item_get_str(item);
+ if (str != NULL && strcmp(str, s) == 0)
break;
}
static struct ec_completed *c;
static struct ec_completed_iter *iter;
const struct ec_completed_item *item;
+ enum ec_completed_type item_type;
+ const char *item_str, *item_display;
(void)s;
if (item == NULL)
return NULL;
+ item_str = ec_completed_item_get_str(item);
if (c->count_match == 1) {
/* don't add the trailing space for partial completions */
if (state == 0) {
- if (item->type == EC_MATCH)
+ item_type = ec_completed_item_get_type(item);
+ if (item_type == EC_MATCH)
rl_completion_suppress_append = 0;
else
rl_completion_suppress_append = 1;
}
- return strdup(item->str);
+ return strdup(item_str);
} else if (rl_completion_type == '?') {
/* on second try only show the display part */
- return strdup(item->display);
+ item_display = ec_completed_item_get_display(item);
+ return strdup(item_display);
}
- return strdup(item->str);
+ return strdup(item_str);
}
static char **my_attempted_completion(const char *text, int start, int end)
/* this function builds the help string */
static char *get_node_help(const struct ec_completed_node *compnode)
{
- const struct ec_completed_item *item;
- const struct ec_node *node;
+// const struct ec_completed_item *item;
+// const struct ec_node *node;
char *help = NULL;
const char *node_help = NULL;
const char *node_desc = NULL;
- size_t i;
+// size_t i;
+ (void)compnode;
+#if 0 //XXX
/* Since we display only one help per node, only look at the first item
* to get the path. The objective is to retrieve the most precise
* help for this node. */
if (node_desc == NULL)
node_desc = ec_node_desc(node);
}
+#endif
if (node_help == NULL)
node_help = "";
- anything better than weakref?
- add get_max_parse_len() for all relevant nodes
- add ec_node_defaults.[ch] providing usual implementations of node methods
-- use vec for strvec
+X use vec for strvec
dependencies
============
logs
====
-- register log types
+X register log types
yaml
====
readline:
-[tab] list possible completions (matches only)
+[tab] list possible completions (matches/partial only)
[?] list what is expected, example:
"command [foo] toto|titi|<int>"
titi (help of titi)
<int> (help of int)
+
+----------------
+
+struct names
+============
+
+ideas:
+
+- ec_node: a node that can be parsed/completed
+- ec_parse: a tree describing the result of parse(node, input)
+- ec_comp: a list describing the result of complete(node, input)
+
+ec_comp_item
+
+
+---------------
+
+node tree
+=========
+
+Example:
+
+1 seq
+2 option
+3 str(foo)
+4 or
+5 int(1,10)
+6 str(bar)
+7 str(foo)
+
+parse() returns a tree
+=======
+
+- each node of the tree refers to a ec_node
+- each node points to the strvec that matches
+- parse returns the first matching solution
+- usually try to match as many str in the vecs (seq node)
+
+[foo] ->
+1 seq
+2 option
+4 or
+7 str(foo)
+
+The parse cb of the node is:
+
+parse_cb(node, current_parse_state, strvec, *nmatch)
+
+return values:
+- 0: success, child->strvec is set by node (NULL = no_match)
+- -1: error (errno is set)
+maybe complex to use:
+- the node must set it (ex: "return ec_parsed_node_match()")
+- the caller must use accessor to check if it matches or not
+
+alternative idea for return values:
+- >= 0: match, ret == nb_tk
+- -1: error (errno is set)
+- -2 or MAX_INT: success, but no match
+This is strange to have a specific value for no match
+
+alternative idea for return values:
+- ec_parse_result_match(n_tokens >= 0)
+- ec_parse_result_nomatch()
+- ec_parse_result_error(errno)
+
+A node always try to consume the maximum number of tokens.
+Example:
+1 seq
+2 option
+3 str(foo)
+4 str(foo)
+5 str(bar)
+
+[foo, foo, bar] matches
+[foo, bar] does *not* match
+
+complete() returns a list of possible completions
+==========
+
+problems:
+- partial completion: in a path dir/file, completion stops once
+ after the directory
+- displayed value is not the completion token: when completing a
+ file in several subdirectories, the full path is not displayed
+- any parent node can modify the completions, ex: add missing quotes
+ in ec_node_sh_lex(), filter completions in case of a ec_node_filter()
+- a command line may want to display the help from the most specific
+ token, or not.
+- some specific nodes can complete several tokens
+
+struct item {
+ const char *str;
+ type: full, partial, unknown
+}
+
+full: the completion item matches token
+partial: beginning of a completion, does not match the token
+ (good example is a directory in a path)
+unknown: could complete, but the node does not know how
+
+struct completed_elt {
+ ec_parsed *parse_tree; // current tree state
+ ec_node *last; // last node of the tree
+ list of items; // list of items for this parse tree
+}
+
+struct completed {
+ list(elt)
+}
+
+The callback is:
+
+complete_cb(node, current_complete_state, current_parse_state, strvec)
+return:
+- 0 = success, the current complete state is updated
+- -1 = error (set errno?)
+
+
+a node can filter the completions
+
+
+[] ->
+ foo 3 str(foo)
+ seq
+ option
+ str(foo) <-
+
+ ? 5 int(1,10)
+ seq
+ option
+ or
+ int <-
+
+ bar 6 str(bar)
+ foo 7 str(bar)
+...
+
+
+[foo, ] ->
+
+ ? 5 int(1,10)
+ seq
+ option
+ str(foo)
+ or
+ int <-
+
+ bar 6 str(bar)
+ foo 7 str(bar)
+
+
+
+-----
+
+changes:
+- a completion item should contain a strvec for the value
+ (the display string remains a string)
+- use a INT_MIN or a specific
+- there is maybe no good reason to split in:
+ - ec_completed_item()
+ - ec_completed_item_set()
+ - ec_completed_item_set_display()
+ - ec_completed_item_add()
+
+
+-----
+
+#include <stdio.h>
+#include <stdbool.h>
+
+
+struct res {
+ int a;
+};
+
+static inline bool is_success(struct res r)
+{
+ if (r.a == 0)
+ return true;
+ return false;
+}
+
+
+static inline struct res res(int a)
+{
+ struct res r;
+ r.a = a;
+ return r;
+}
+
+int main(void)
+{
+ struct res r;
+
+ r = res(0);
+
+ printf("%d\n", r.a);
+ if (is_success(r))
+ printf("success: %d\n", r.a);
+
+ r = res(1);
+
+ printf("%d\n", r.a);
+ if (is_success(r))
+ printf("success: %d\n", r.a);
+
+ return 0;
+}