| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
|
Updated v2 of the layouts to use a subset of JSON. |
Sorry, something went wrong.
|
I think the file comment should be less about how the code works and what the functions are called and more about how the format looks. It should list the keys and their meanings at least. In layout_string_init it seems unnecessary to memset all 8K when you are just going to overwrite it. I'd just set write and be done with it. In layout_string_copy it is inefficient to use strlcat when you know the write offset, because strlcat will need to scan the string again to find same. You can use memcpy since you know the space available, or snprintf. Can you make layout_string_format a function instead of a macro? Macros like this are hard to read. You could make int layout_string_write(struct layout_string *ls, const char *fmt, ...);. It would be nice to unify v1 and v2 so they both use the same struct layout_string buffer. Or alternatively I am OK with moving v1 into a layout-custom-old.c file and leaving it entirely unmodified except for code to change function names and to skip floating panes. A lot of the functions are missing comments above the function definition. It should be all or none in a file (preferably all). You can't do this: sscanf(layout, "{\"V\":%d,\"L\":%n", &version, &n)
Because JSON fields are not ordered, so you could receive L before V, or with new fields we add later in between. Also spaces need to be ignored between tokens. It is perfectly valid for someone to have say { "L": {}, "V": 99 } or with newlines. I think we will need to build a separate parse step so we first run over the string and pull out the keys and values. This could either be generic for JSON (so build something which is just key-value and doesn't care about what keys there are), or it could understand the keys and build say struct layout_parse_input { int version; ... }. |
Sorry, something went wrong.
|
Ah yeah, whitespace. I will write a tokenization step. I wanted to keep the versioning contained to the file, so I"ll adapt version 1 to use the same string building method as version 2. I'm not sure if it will change with the with the addition of the tokenization step, but I'll unify them. I was trying to do something too cute with layout_string_copy, where I called strlcat on the write pointer, which points to the end of string. It should just be a memcpy. Thank you for the feedback! |
Sorry, something went wrong.
|
Oh, and as for the comments. It felt strange to duplicate what the code was doing with a comment at the top, but I'll change it to document the format, and document each function. |
Sorry, something went wrong.
|
I have added a string tokenizer and a JSON parser that is tuned to v2 of the format. The struct naming isn't perfect. I hope I didn't go overboard. I wanted to write something that could be extended in the future with minimal friction. It needs a bit more testing, but the plumbing is all there and it works on common examples. What do you think? I believe I addressed the rest of the feedback pertaining to constructing the layout strings, and I converted layout_append_v1 to use the new layout_string_write. |
Sorry, something went wrong.
|
Oh, I should mention. There is possible follow-up work to do. At this point, some of the pane keys are ignored (last, active, zindex, and id). Some of these may be useful for reconstructing a layout. We can save and apply this context later from the evaluation step in a struct that hitches a ride though the call chain. Also, **cause can be passed though the tokenize, parse, and eval steps if we want better error messages. Both these points were out of scope for this PR. EDIT1: I should also mention that the tokenizer does not handle escaped characters other than whitespace. Didn't seem necessary at this point. |
Sorry, something went wrong.
|
I think I'm going to try and simplify the memory management of the parser. The general structure still stands though! |
Sorry, something went wrong.
|
Don't return NULL if no client in format_cb_window_layout or you will break use of the format from a config file. Just assume the client is not a control client if not set. |
Sorry, something went wrong.
|
OK some more comments: Same as above for format_cb_window_visible_layout (handle ft->c == NULL). Comments should be neutral and third person that is don't address the reader, so change Please work off of the current format.. I would just say "... deprecated at some point in future and should no longer be used.". I would expand the next paragraph though to list the fields out a bit more: * The current (v2) format is JSON. The top level has two key: * "V": version number, currently 2; * "L": array of layout cells * Each cell is an object with: * "w": cell width * "h": cell height * "x": horizontal position * "y": vertical position * If the cell is a node cell (with child cells), it additionally has: * "c": array of child cells * If the cell is a leaf cell (that is, containing a pane and no child cells), it additionally has: * "i": pane ID as %n * "l": index into last panes list, if not the active pane * "a": true if the active pane * "z": z-index, if a floating pane */ I would omit documenting the v1 format since we do not want people to use it, if you want to say it as a checksum and v2 does not that would be enough. I don't think KEY_* defines buy us anything except another layer of indirection. I would remove them and just use "V" etc inline. Definitely the same for VAL_TYPE_*. statics and enums and structs should still have layout_ prefix. I think TOK_OPENCURLY would be better as OPENOBJECT and OPENBRACKET would be better as OPENARRAY, that is, name them after what they mean not the character type. That also avoids people getting confused with terminology because to many people brackets are () not [] (the latter would be "square brackets"), or "curly brackets" are "braces". JSON integers can signed 64 bits so int64_t not int, it does not support unsigned integers though (somewhat annoyingly), so int64_t is enough. I think we should support at least \" inside strings unless it is very difficult to do. I can't remember if \\ means \ but if it does we should support that too? |
Sorry, something went wrong.
|
In layout_string_write, you do not need tmp, you can just drop the x and do: int len;
...
len = vsnprintf(ls->write, remaining, fmt, ap);
va_end(ap);
if (len < 0 || len >= (int)remaining)
return (-1);
ls->write += len;
You know LAYOUT_STRING_MAX is small so no fear of overflowing INT_MAX here. This will \0 terminate it for you also. |
Sorry, something went wrong.
|
I believe I have addressed everything you mentioned. I also got rid of all the string allocation in the parser and implemented views to use on the input. Made things a lot more simple. Do you think it is worthwhile at this point to implement a struct layout_parse_ctx which would be returned from layout_construct instead of a struct layout_cell? The context would hold error strings, the layout root, and other data we may want in the future like z_index or last_panes data. |
Sorry, something went wrong.
|
Sorry, something went wrong.
|
I would probably keep json_node_type as public and have an API like: struct json_node *json_find(struct json_node *jn, const char *key); enum json_node_type json_get_type(struct json_node *jn); struct json_node *json_array_first(struct json_node *jn); struct json_node *json_array_next(struct json_node *jn); int json_get_string(struct json_node *jn, const char **s); // get_number, get_boolean, get_object You could probably live without json_get_type since you know what type you want and just rely on get_string and friends to fail or succeed... |
Sorry, something went wrong.
|
Awesome, thanks for the feedback. This all makes sense, ill start implementing. I would like your opinion on my reasoning for the string view and if you think it is useful. The primary reason i started liking the string view is for error reporting. Since it references the input, the surrounding context of the error can be given to the user. We can also store a pointer to the input along with the allocated string. Big picture, is it worthwhile to supply 'N' characters of surrounding context to the user on an error? |
Sorry, something went wrong.
|
I think it is probably more infrastructure than it is worth for this. But you could still do that if you want because when there is an error, you have the context at that point, no? I just mean don't store it as a pointer into the string (or if you do, don't expose that externally - copy it before you do - so that the caller has a normal string and does not have to worry about it being special). |
Sorry, something went wrong.
Added a tokenizer and JSON parser for version 2. It is extendable to be useful into the future. Converted `layout_append_v1` to use `struct layout_string`.
Lots of memory leak/double frees.
Also moved away from individual allocations and implemented basic string views.
added the parse context with some bug fixes.
It now emits the correct client informatiom.
|
Okay, this is ready for review again. I have added a few additional functions to the api that combine functionality and return references to static values. |
Sorry, something went wrong.
|
OK some comments:
|
Sorry, something went wrong.
|
I believe I have addressed most things, but I have a few points of discussion:
Indexes are now being validated for uniqueness, but not strict sequential ordering because of the bottom right deletion fiting. Let me know how it looks! |
Sorry, something went wrong.
|
A few things: Try this: $ for i in `seq 30`; do tmux splitw \; selectl tiled; done
$ tmux selectl "$(tmux display -p '#{window_layout}')"
tokenization error: ...
Also this looks wrong - the floating pane ends up in a weird state... is it meant to be tiled at this point? $ ./tmux -Lx new -d \; new-pane -x100 -y30 \; a
$ ./tmux -C display -p '#{window_layout}'
%begin 1787565429 463 0
7b70,106x85,0,0[106x85,0,0,0]
%end 1787565429 463 0
%exit
$ ./tmux selectl '7b70,106x85,0,0[106x85,0,0,0]'
The example in tmux.1 doesn't work: $ tmux select-layout '{"V":2,"L":{"t":"h","w":159,"h":48,"x":0,"y":0,"c":[{"t":"p","w":79,"h":48,"x":0,"y":0,"l":0,"i":0,"I":"%0"},{"t":"p","w":79,"h":48,"x":80,"y":0,"a":true,"i":1","I":"%2"}]}}'
invalid number: 1","I":"...: {"V":2,"L":{"t":"h","w":159,"h":48,"x":0,"y":0,"c":[{"t":"p","w":79,"h":48,"x":0,"y":0,"l":0,"i":0,"I":"%0"},{"t":"p","w":79,"h":48,"x":80,"y":0,"a":true,"i":1","I":"%2"}]}}
|
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
I have written out the format here: #5135 (comment).
The new format is on by default in every mode other than control. In control mode, it needs to be enabled with refresh-client -f'new-layouts'