max / quasi
4 files changed,
+72 insertions,
-11 deletions
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | [package] | |
| 2 | 2 | name = "quasi-router" | |
| 3 | - | version = "0.101.7" | |
| 3 | + | version = "0.101.8" | |
| 4 | 4 | description = "Host-agnostic router: a request in, a renderer-agnostic description out" | |
| 5 | 5 | edition.workspace = true | |
| 6 | 6 | rust-version.workspace = true |
| @@ -605,11 +605,12 @@ | |||
| 605 | 605 | quote!(.act(#held)), | |
| 606 | 606 | )) | |
| 607 | 607 | } | |
| 608 | - | (Container::Cell, other) => Err(syn::Error::new( | |
| 609 | - | emission_span(other), | |
| 610 | - | "a cell holds controls and says what opening it does: write \ | |
| 611 | - | `act <label> to <action>;`, `include <shape>;` or `activate to <action>;`", | |
| 612 | - | )), | |
| 608 | + | // A cell is a run of leaves, which is what `Cell::part` is for. | |
| 609 | + | // `git_blame`'s commit cell carries the short oid and, when the commit | |
| 610 | + | // has annotations, a second link to its notes; its code cell carries the | |
| 611 | + | // line. A control is still `.act`, so a supplier reached by `include` | |
| 612 | + | // stays a control and a node member is a part. | |
| 613 | + | (Container::Cell, other) => Ok((node(other)?, quote!(.part(#held)))), | |
| 613 | 614 | ( | |
| 614 | 615 | Container::Node, | |
| 615 | 616 | Emission::Offering { |
| @@ -22,9 +22,12 @@ | |||
| 22 | 22 | ||
| 23 | 23 | /// The modifiers, and how many arguments each takes. | |
| 24 | 24 | /// | |
| 25 | - | /// `filling` is deliberately not here. It is `Act::filling`, a setting on the | |
| 26 | - | /// control, and listing it as a modifier of the action made `media_picker`'s | |
| 27 | - | /// tiles fail against `Action` instead of reading as the setting they are. | |
| 25 | + | /// **Two words were here that are settings on the control rather than modifiers | |
| 26 | + | /// of the action, and both were caught by a screen rather than by reading.** | |
| 27 | + | /// `filling` is `Act::filling` and made `media_picker`'s tiles fail against | |
| 28 | + | /// `Action`; `copying` is `Act::copying`, which sets the destination to | |
| 29 | + | /// `Action::local` itself, and `collections`' Copy link is the site. A word | |
| 30 | + | /// belongs here only if `Action` has the method. | |
| 28 | 31 | const MODIFIERS: &[(&str, usize)] = &[ | |
| 29 | 32 | ("navigating", 0), | |
| 30 | 33 | ("awaiting", 0), | |
| @@ -34,7 +37,6 @@ | |||
| 34 | 37 | ("replacing_enclosing", 0), | |
| 35 | 38 | ("saving", 1), | |
| 36 | 39 | ("replacing", 1), | |
| 37 | - | ("copying", 1), | |
| 38 | 40 | ("carrying", 2), | |
| 39 | 41 | ]; | |
| 40 | 42 | ||
| @@ -51,6 +53,15 @@ | |||
| 51 | 53 | ||
| 52 | 54 | /// The members that are one of `Node`'s own constructors, called by its name. | |
| 53 | 55 | /// Growing this list is the whole of adding one. | |
| 56 | + | /// | |
| 57 | + | /// **A name that is a setting on any container cannot go here.** An ident inside | |
| 58 | + | /// a body is a member if it is in one of these two lists and a setting if it is | |
| 59 | + | /// not, and that is the whole of how the two are told apart, so one name cannot | |
| 60 | + | /// mean both. `token` is the measured case: `Node::Token` looks like a member, | |
| 61 | + | /// and `Row::token` and `Cell::token` are settings at four converted sites. A | |
| 62 | + | /// screen wanting a tag standing on its own reaches `Node::token` through a | |
| 63 | + | /// supplier, which is the remedy the deferred table already names, and | |
| 64 | + | /// `project_analytics`'s `chip` is that supplier. | |
| 54 | 65 | const NODE_MEMBERS: &[&str] = &[ | |
| 55 | 66 | "text", | |
| 56 | 67 | "page", | |
| @@ -530,7 +541,18 @@ | |||
| 530 | 541 | }; | |
| 531 | 542 | Ok(Self::Row { primary, body }) | |
| 532 | 543 | } | |
| 533 | - | "list" if input.peek(token::Brace) => Ok(Self::List(block(input)?)), | |
| 544 | + | // The guard goes after the body here rather than before it, because | |
| 545 | + | // the body is what tells this `list` from the node member of the | |
| 546 | + | // same name. `user_projects` draws its list only when there is | |
| 547 | + | // something in it. | |
| 548 | + | "list" if input.peek(token::Brace) => { | |
| 549 | + | let rows = block(input)?; | |
| 550 | + | let guard = guard(input)?; | |
| 551 | + | if guard.is_some() { | |
| 552 | + | input.parse::<Token![;]>()?; | |
| 553 | + | } | |
| 554 | + | Ok(guarded(guard, Self::List(rows))) | |
| 555 | + | } | |
| 534 | 556 | "table" => Ok(Self::Table(block(input)?)), | |
| 535 | 557 | "column" => { | |
| 536 | 558 | let name: Arg = input.parse()?; |
| @@ -4193,6 +4193,17 @@ | |||
| 4193 | 4193 | Self::Handover { name: name.into() } | |
| 4194 | 4194 | } | |
| 4195 | 4195 | ||
| 4196 | + | /// A place the app fills itself, that no host is owed a fill for. | |
| 4197 | + | /// | |
| 4198 | + | /// [`Slot::ceded`]'s kind on its own, for the same reason [`handover`] has | |
| 4199 | + | /// one. | |
| 4200 | + | /// | |
| 4201 | + | /// [`handover`]: Self::handover | |
| 4202 | + | #[must_use] | |
| 4203 | + | pub fn ceded(name: impl Into<String>) -> Self { | |
| 4204 | + | Self::Ceded { name: name.into() } | |
| 4205 | + | } | |
| 4206 | + | ||
| 4196 | 4207 | /// Borrow as the description layer's own type. | |
| 4197 | 4208 | #[must_use] | |
| 4198 | 4209 | pub fn as_layout(&self) -> layout::Region<'_> { | |
| @@ -8835,6 +8846,33 @@ | |||
| 8835 | 8846 | } | |
| 8836 | 8847 | } | |
| 8837 | 8848 | ||
| 8849 | + | /// One more figure, beside [`stats`](Self::stats). | |
| 8850 | + | /// | |
| 8851 | + | /// `stats` takes the whole list, and every other container in this | |
| 8852 | + | /// vocabulary accretes: `Table::column`, `Cells::cell` and `Field::options` | |
| 8853 | + | /// were all added for that reason and this is the fourth. A caller building | |
| 8854 | + | /// figures one at a time, or conditionally, has nowhere to hold the list. | |
| 8855 | + | /// | |
| 8856 | + | /// Does nothing to a node that is not [`Stats`](Self::Stats), on | |
| 8857 | + | /// [`trust`](Self::trust)'s rule. | |
| 8858 | + | #[must_use] | |
| 8859 | + | pub fn figure(mut self, figure: Figure) -> Self { | |
| 8860 | + | if let Self::Stats { figures } = &mut self { | |
| 8861 | + | figures.push((figure, None)); | |
| 8862 | + | } | |
| 8863 | + | self | |
| 8864 | + | } | |
| 8865 | + | ||
| 8866 | + | /// A tag standing on its own, rather than inside a row or a cell. | |
| 8867 | + | /// | |
| 8868 | + | /// [`Token`](Self::Token) was the last node variant with no constructor of | |
| 8869 | + | /// its own once [`literal`](Self::literal) landed. A chip that is a control | |
| 8870 | + | /// carries its action and its latched state on the tag. | |
| 8871 | + | #[must_use] | |
| 8872 | + | pub fn token(tag: Tag) -> Self { | |
| 8873 | + | Self::Token(tag) | |
| 8874 | + | } | |
| 8875 | + | ||
| 8838 | 8876 | /// Time counting up from an instant. | |
| 8839 | 8877 | #[must_use] | |
| 8840 | 8878 | pub const fn since(at: std::time::SystemTime) -> Self { |