| 84 | } |
| 85 | |
| 86 | std::optional<std::string_view> parseNode(const CommandRegistry::ParseToken &root) |
| 87 | { |
| 88 | // If there are no children, this is a leaf text node. |
| 89 | if (!root.child) { |
| 90 | if (root.length == 0) { |
| 91 | return std::nullopt; |
| 92 | } |
| 93 | if (root.type == CommandRegistry::HardNonTerminal::Id) { |
| 94 | return removeQuotes({root.text, root.length}); |
| 95 | } |
| 96 | return std::string_view{root.text, root.length}; |
| 97 | } |
| 98 | |
| 99 | // Otherwise: |
| 100 | const auto &child = *root.child; |
| 101 | const auto *begin = findFirstWithText(&child); |
| 102 | if (!begin) { |
| 103 | return std::nullopt; |
| 104 | } |
| 105 | |
| 106 | // (1) If this node has no next sibling, it's the last argument: consume all remaining text until the end |
| 107 | if (!root.next) { |
| 108 | const auto view = rstrip(begin->text); |
| 109 | if (child.type == CommandRegistry::HardNonTerminal::Id) { |
| 110 | return removeQuotes(view); |
| 111 | } |
| 112 | return view; |
| 113 | } |
| 114 | |
| 115 | // (2) Otherwise, find the start of the next argument and extract the substring between begin and end, then trim |
| 116 | // trailing whitespace. |
| 117 | const auto *end = findFirstWithText(root.next.get()); |
| 118 | if (!end) { |
| 119 | const auto view = rstrip(begin->text); |
| 120 | if (child.type == CommandRegistry::HardNonTerminal::Id) { |
| 121 | return removeQuotes(view); |
| 122 | } |
| 123 | return view; |
| 124 | } |
| 125 | |
| 126 | const auto view = rstrip({begin->text, end->text}); |
| 127 | if (child.type == CommandRegistry::HardNonTerminal::Id) { |
| 128 | return removeQuotes(view); |
| 129 | } |
| 130 | return view; |
| 131 | } |
| 132 | } // namespace |
| 133 | |
| 134 | template <> |
no test coverage detected