tk_cmd ====== X evaluate expression tree in ec_tk_expr X cmd token X example X tk_re cleanup / rework ================ X ec_completed_item_update() X ec_completed_item_set_display_value() X add_no_match X add_partial_match - check XXX in code X properly manage quotes in shlex X remove the _new() functions X iterate children nodes without chaining them - add a node vector type: will be used in several nodes (ex: or, seq, ...) - check allocation model everywhere - checkpatch? - use linux style (update .emacs) - better logs - check return values (-1 or NULL) + use errno - check missing static / const X license: SPDX - check all completion nodes X split ecoli_tk.h - size_t or unsigned int? X rename: X ec_tk -> ec_node X ec_parsed_tk -> ec_parsed X ec_completed_tk -> ec_completed X tk, gen_tk, token, ... -> node X tokens -> input_str / input_strvec ? X save node path in completion to fix help string - code coverage - try to hide structures X anything better than weakref? - add ec_node_defaults.[ch] providing usual implementations of node methods X use vec for strvec / ELOOP in case of loop X remove weakref? - sh_lex to provide offsets in attributes - accessors for all structs dependencies ============ X pass the current parsed state when parsing/completing X new node "once" - new node "condition" logs ==== X register log types yaml ==== X register nodes by name X interface to add attributes: all nodes must be configurable through a generic api: X attr string X attr string list X attr node X attr node list X attr int X yaml interface to create nodes - example examples ======== - example which parses arguments (argc/argv) - example that acts as bash completion (ip link ?) - calculator example (var assignation, expression evaluation) - example with libedit - mini script language - configuration file - mini shell: cd, ls, cat, stat - mini network console based on ip - dialog-like for use in shell doc === - overview - add api doc in .h - generate automatic api doc - architecture - coding rules, process - each node - allocation model - say that it stops at first match (no ambigous support) - say that completion must be exhaustive build framework =============== - .map files for API - split libs, tests and examples - add make help - add make config - -fvisibility= - use meson tests ===== - complete automatic tests with "make test" new nodes ========= - regexp X node which always matches X file + partial completion - ether, ip, network - fusion node: need to match several children, same for completion? - float - not - reparse: parse a tree with received strvec, then another tree with strvec generated from first tree encoding ======== - support utf-8 and other encodings - example - documentation netconf example =============== / demonstration example that parses yang file and generate cli ----------------------- readline: [tab] list possible completions (matches/partial only) [?] list what is expected, example: "command [foo] toto|titi|" help("command f") -> foo (help of foo) toto (help of toto) titi (help of titi) (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 the match (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 With MAX_INT, this is the best (less bad) alternative 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 completion_item { const char *value; const char *disp; } 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) - 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() ----- sh_lex or str(foo) str(foo2) str(bar) complete(sh_lex, ["'fo"]) complete(sh_lex, ["fo"]) -> ["foo", "foo2"] ----- #include #include 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; } ---- expr expr expr [toto] | tutu [toto [titi]] pre_op = "!" post_op = "^" post = val | pre_op expr | "(" expr ")" term = post post_op* prod = term ( "*" term )* sum = prod ( "+" prod )* expr = sum ----- break on malloc: b debug_malloc # or: b debug_realloc condition malloc_seq >= alternative watch malloc_seq condition malloc_seq == run c --------------- about split in several libraries There are several options: 1/ one library, config options to select libyaml, libedit - need to manage dependencies in build system 2/ one library for ecoli-core, one for ecoli-yaml, one for ecoli-edit - extra complexity 3/ one library with core + yaml + edit dependency is managed at runtime