Skip to content

Add search syntax to the editor's Output panel search filter#107223

Draft
FilipeAlexCosta wants to merge 1 commit intogodotengine:masterfrom
FilipeAlexCosta:output-dock-syntax
Draft

Add search syntax to the editor's Output panel search filter#107223
FilipeAlexCosta wants to merge 1 commit intogodotengine:masterfrom
FilipeAlexCosta:output-dock-syntax

Conversation

@FilipeAlexCosta
Copy link
Copy Markdown
Contributor

@FilipeAlexCosta FilipeAlexCosta commented Jun 6, 2025

Currently, you can only filter Godot's panel output logs by their category and whether or not they contain a given substring.

@rafaelgcruz and I implemented a filter that can do boolean operations (AND, OR and NOT) between search terms (this draft PR is a possible implementation of godotengine/godot-proposals#11244).

The syntax is similar to Google and GitHub, with a few differences. You can:

  1. match a term, excluding case, by writing it without spaces between each character (i.e. <Godot> will match <Godot>, <GODOT>, <gODOt>, etc..., but <Go dot> will match <Go> AND <dot> instead);
  2. exactly match a term, including case, by writing <"term"> or <'term'>. This also allows you to match spaces. You can escape nested quotation marks using \, or by just using a different quotation mark on the outside (i.e. <"\"term\"">, <'"term"'> will both exactly match <"term">);
  3. AND two expressions by writing a delimiter (like ", ', (, ), or a space), meaning <hello world>, <hello(world)>, <"hello"world> all match <hello> AND <world> (with the third example matching hello's case);
  4. OR two expressions by typing <expr || expr>. Note that || needs a delimiter before and after, otherwise it'll be joined with its neighbouring search term (i.e. <hello||world> will literally match <hello||world>, <hello ||world> will match <hello> AND <||world>. Only <hello || world>, <"hello"|| world>, <'hello'||'world'> will match <hello> OR <world>);
  5. negate an expression by typing <-expr>. The - token needs a delimiter right before it to match, meaning <hello-world> will match <hello-world> while <-hello> will match every log that does not contain <hello>. Note that the beginning and end of the input string are also delimiters, meaning you can write - at the beginning of the filter and it will correctly match the NOT operator;
  6. use (expr) to group operations (change their associativity).

Consecutive spaces are ignored.

Note: < and > are there just to distinguish the PR message and what the user searched for/what the filter is trying to match.

Also, NOT has the highest precedence, followed by AND and lastly OR.

Here are some more examples of how the parser would parse some inputs:

  1. <hello -(world godot)> will be parsed as (<hello> AND (NOT (<world> AND <godot>)));
  2. <hello -world || godot> will be parsed as ((<hello> AND (NOT <world>)) OR <godot>);
  3. <'foo "bar" baz'> will exactly match <foo "bar" baz> (i.e. you can use ' inside " and the other way around);
  4. <---> will be parsed as NOT <-->;
  5. <||(world)> will be parsed as (OR <world>), causing a syntax error;
  6. <> (the empty filter) will match every log.

Naturally, we're open to discussing and changing the syntax. We encourage everyone to try out the feature for themselves and give feedback on what to improve.

We also hope you can give us pointers on how to better adapt our design to match Godot's.

Finally, regarding the code itself, we essentially made two classes: EditorLogSearchFilter and EditorLogSearchParser (this one has a tokenizer class inside). As the names suggest, the latter parses the search text into an AST we then traverse it to accept/reject each message. The filter itself is just a thin refcounted wrapper over the root node of the AST. It essentially just has two tasks: own the entire tree and provide the empty filter functionality (i.e. accept everything if there are no nodes).

If you have any questions about the feature (i.e. something about the syntax we failed to explain, etc...), you're welcome to ask 😃

See also:

Currently the editor allows filtering log messages by whether or not
they contain a given substring.
This commit adds boolean operators (AND, OR, NOT) to this filter
through a Pratt parser (EditorLogSearchParser class) that builds an AST
(EditorLogSearchFilter class) which is then used to accept or reject
log messages.

The syntax is as follows:

expr:	LITERAL		(must contain LITERAL, ignoring case)
    |	QUOTED_LITERAL	(must contain QUOTED_LITERAL)
    |	expr || expr	(logical OR)
    |	'-' expr	(logical NOT)
    |	'(' expr ')'
    ;

Logical ANDs are implicit (i.e. the parser injects an AND when it
expects an infix operator but reads the FIRST of an expression instead).

A literal may be quoted using either " or ', and it is possible to nest
quotation marks by escaping with \.

OR has the lowest precedence, followed by AND, with NOT having the
highest.

As an example, searching for 'Godot "Engine"' -foo || bar"baz" should
match all logs that either contain Godot "Engine" but not foo, or that
contain bar and baz.

Co-authored-by: Rafael Cruz <rafael.gueifao.cruz@tecnico.ulisboa.pt>
@AThousandShips AThousandShips added this to the 4.x milestone Jun 7, 2025
@AThousandShips AThousandShips requested a review from a team June 7, 2025 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants