Cleanup: simplify keyword recognition in text editor #108775

Closed
Guillermo Venegas wants to merge 38 commits from guishe:simplify-keywords into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
Contributor

Arrays are used to eliminate the use of many nested if else's that
compare a string value against to many other strings.

These arrays are sorted to be able to perform binary searches on these
string literals arrays.

Arrays are used to eliminate the use of many nested if else's that compare a string value against to many other strings. These arrays are sorted to be able to perform binary searches on these string literals arrays.
Guillermo Venegas added 1 commit 2023-06-08 20:07:33 +02:00
Guillermo Venegas added 1 commit 2023-06-08 20:09:46 +02:00
Author
Contributor

@ideasman42 following with your commit to move text editor files to C++, I simplified the way keywords are recognized, this way we get rid of the error made by many chained if else

@ideasman42 following with your commit to move text editor files to C++, I simplified the way keywords are recognized, this way we get rid of the error made by many chained if else
Iliya Katushenock added the
Interest
Text Editor
label 2023-06-08 20:20:56 +02:00
Iliya Katushenock added this to the Python API project 2023-06-08 20:21:01 +02:00

What do you think about making it a constexpr class/methods?

Edit: Although ... is it really necessary to do this not with arrays and simple loops?

What do you think about making it a constexpr class/methods? Edit: Although ... is it really necessary to do this not with arrays and simple loops?
Author
Contributor

KEYWORD_INFO is a macro to expand the string and its size in a keyword_info type structure, the lists of keywords will never be modified when executing the program, so I see that it is possible to calculate it at compile time the array of the keywords and their sizes

Although the constexpr specifier can be deduced by the compiler in this cases.

KEYWORD_INFO is a macro to expand the string and its size in a keyword_info type structure, the lists of keywords will never be modified when executing the program, so I see that it is possible to calculate it at compile time the array of the keywords and their sizes Although the constexpr specifier can be deduced by the compiler in this cases.
Author
Contributor

Edit: Although ... is it really necessary to do this not with arrays and simple loops?

In the end, the compiler would optimize and it would be the same to have it as an ifelse or a for loop in an array, but the array style is more maintainable over time.

Edit: And a 15.4 KB less space

> Edit: Although ... is it really necessary to do this not with arrays and simple loops? In the end, the compiler would optimize and it would be the same to have it as an ifelse or a for loop in an array, but the array style is more maintainable over time. Edit: And a 15.4 KB less space
Guillermo Venegas added 1 commit 2023-06-08 21:49:13 +02:00

While this change is an improvement, I think it would be better to further refactor the checks so the lookup is generalized.

  • Define literal strings in simple arrays.
  • Use a registration function to produce KeywordInfo arrays (for example).
  • Run this function on startup to generate the lookup tables.

This has the advantage that the method of looking up text can be changed (to a hash table for e.g.) else without large changes each time.

While this change is an improvement, I think it would be better to further refactor the checks so the lookup is generalized. - Define literal strings in simple arrays. - Use a registration function to produce `KeywordInfo` arrays (for example). - Run this function on startup to generate the lookup tables. This has the advantage that the method of looking up text can be changed (to a hash table for e.g.) else without large changes each time.
Guillermo Venegas added 1 commit 2023-06-09 02:29:37 +02:00
Guillermo Venegas added 1 commit 2023-06-09 08:27:38 +02:00
Guillermo Venegas added 1 commit 2023-06-09 16:02:50 +02:00
Guillermo Venegas added 1 commit 2023-06-09 16:29:51 +02:00
Guillermo Venegas added 1 commit 2023-06-09 16:31:53 +02:00
Guillermo Venegas added 1 commit 2023-06-09 16:35:52 +02:00
Author
Contributor

I think it's ready for you to take another look at it @ideasman42

I think it's ready for you to take another look at it @ideasman42
Guillermo Venegas added 1 commit 2023-06-09 16:51:18 +02:00

It possiblt to replace KeywordInfo by StringRef from bli?

It possiblt to replace `KeywordInfo` by `StringRef` from bli?
Author
Contributor

Yeah, much better

Yeah, much better
Guillermo Venegas added 1 commit 2023-06-09 18:26:36 +02:00

static Array<StringRef> texts = {"abc", "ddd", "fff"};?

`static Array<StringRef> texts = {"abc", "ddd", "fff"};`?
Guillermo Venegas added 1 commit 2023-06-09 19:28:41 +02:00
Author
Contributor

static Array<StringRef> texts = {"abc", "ddd", "fff"};?

It will be fine too

But if we are going to use other structures for look up it does not make much difference, but if it is by preference then I can make the change

> `static Array<StringRef> texts = {"abc", "ddd", "fff"};`? It will be fine too But if we are going to use other structures for look up it does not make much difference, but if it is by preference then I can make the change
Guillermo Venegas added 1 commit 2023-06-10 02:00:13 +02:00
Guillermo Venegas added 1 commit 2023-06-10 04:45:02 +02:00
Guillermo Venegas added 1 commit 2023-06-10 05:28:06 +02:00

Regarding the underlying data structure static Array<StringRef> is fine too, the main point is that we don't have to refactor the large lists every time a lookup method changes.

Other requests:

  • Don't use the term "keyword" this already has a special meaning in the context of formatting, suggest "string_literal" or "static_string".
  • Use a common suffix, for local variables e.g.
    text_format_py_keyword_literals
    text_format_py_builtinfunc_literals
    text_format_py_specialvar_literals

... same for other languages.

Regarding the underlying data structure `static Array<StringRef> ` is fine too, the main point is that we don't have to refactor the large lists every time a lookup method changes. Other requests: - Don't use the term "keyword" this already has a special meaning in the context of formatting, suggest "string_literal" or "static_string". - Use a common suffix, for local variables e.g. <br>`text_format_py_keyword_literals`<br> `text_format_py_builtinfunc_literals`<br> `text_format_py_specialvar_literals`<br> ... same for other languages.
Guillermo Venegas added 1 commit 2023-06-10 07:18:39 +02:00
Author
Contributor

I use the same static Array<StringRef> array to perform the lookups instead of creating a new Vector, I sort them too (on start up)
image

Also fixed a bug (happens in main branch), before if an elseif was written for example, it stopped comparing with else because it only compares the size of the literals, and since elseif has extra characters then with the evaluation of text_check_identifier(text[i]) it was discarded
image

I use the same `static Array<StringRef>` array to perform the `lookups` instead of creating a new `Vector`, I sort them too (on start up) ![image](/attachments/6d9e8752-f3bf-46e7-9ce3-2122438f3572) Also fixed a bug (happens in main branch), before if an `elseif` was written for example, it stopped comparing with `else` because it only compares the `size` of the literals, and since `elseif` has extra characters then with the evaluation of `text_check_identifier(text[i])` it was discarded ![image](/attachments/6b13d84c-322c-4668-b683-95a2cdffd8f4)
Guillermo Venegas added 1 commit 2023-06-10 07:39:29 +02:00
Author
Contributor

I don't know why some are formated like this
image
And other like this
image

Should I disable formatting and keep it in one column?

I don't know why some are formated like this ![image](/attachments/36df378e-4c9b-48bf-b8db-11fe2e6c973c) And other like this ![image](/attachments/52bfb074-4d5d-468b-8576-453f8c5eff1f) Should I disable formatting and keep it in one column?
Campbell Barton requested changes 2023-06-10 08:07:01 +02:00
Campbell Barton left a comment
Owner

Please keep the current functions in-place, the large else-if blocks containing STR_LITERAL_STARTSWITH(..) can be replaced with a generalized lookup but there is a check at the end text_check_identifier, which I think should stay in the control of the caller and not generalized (languages might have different definitions of what an identifier is).

Please keep the current functions in-place, the large else-if blocks containing `STR_LITERAL_STARTSWITH(..)` can be replaced with a generalized lookup but there is a check at the end `text_check_identifier`, which I think should stay in the control of the caller and not generalized (languages might have different definitions of what an identifier is).

Should I disable formatting and keep it in one column?

Prefer to force single column formatting, so changes to keywords produce usable diff's.

> Should I disable formatting and keep it in one column? Prefer to force single column formatting, so changes to keywords produce usable diff's.
Guillermo Venegas added 1 commit 2023-06-10 17:02:50 +02:00
Guillermo Venegas added 1 commit 2023-06-10 17:10:49 +02:00
Guillermo Venegas added 1 commit 2023-06-10 17:46:41 +02:00
Guillermo Venegas added 1 commit 2023-06-10 17:53:18 +02:00
Guillermo Venegas added 1 commit 2023-06-10 18:04:46 +02:00
Guillermo Venegas added 1 commit 2023-06-10 18:10:25 +02:00
Guillermo Venegas added 1 commit 2023-06-10 18:30:50 +02:00
Guillermo Venegas added 1 commit 2023-06-10 18:40:42 +02:00
Campbell Barton requested changes 2023-06-11 03:08:15 +02:00
@ -10,6 +10,8 @@
#include "MEM_guardedalloc.h"
#include "BKE_text.h"

This isn't needed.

This isn't needed.
guishe marked this conversation as resolved
@ -243,0 +251,4 @@
auto comp_func = [literal_startwith](const StringRef &string_literal, const char *text) {
int result = literal_startwith(string_literal, text);
return result < 0 || (result == 0 && text_check_identifier(text[string_literal.size()]));

The definition of an identifier should not be part of a general literal lookup, this function, I don't have such a strong opinion on how this is solved, only that spesific details shouldn't be in generic function shared by different languages.

A possible solution would be to add a callback to find_string_literal that takes the StringRef & and can check if it should be used or not.

The definition of an identifier should not be part of a general literal lookup, this function, I don't have such a strong opinion on how this is solved, only that spesific details shouldn't be in generic function shared by different languages. A possible solution would be to add a callback to `find_string_literal` that takes the `StringRef &` and can check if it should be used or not.
Author
Contributor

I did it this way in case we have something like [..."else","elseif",...]
if we write in the text editor elseif, comparing only with literal_startwith(string_literal, text) we can get else as result.

Edited: whit upper_bound solve the issue, and avoid the use of text_check_identifier.

I did it this way in case we have something like `[..."else","elseif",...]` if we write in the text editor `elseif`, comparing only with `literal_startwith(string_literal, text)` we can get `else` as result. Edited: whit `upper_bound` solve the issue, and avoid the use of `text_check_identifier`.
Author
Contributor

Just improved the method, it was easier than I expected

Just improved the method, it was easier than I expected
guishe marked this conversation as resolved
@ -117,3 +122,2 @@
#define STR_LITERAL_STARTSWITH(str, str_literal, len_var) \
(strncmp(str, str_literal, len_var = (sizeof(str_literal) - 1)) == 0)
/*

Use /** .. */ doxygen style comment, no need for blank line at the end.

Use `/** .. */` doxygen style comment, no need for blank line at the end.
guishe marked this conversation as resolved
Guillermo Venegas added 3 commits 2023-06-11 05:06:25 +02:00
Guillermo Venegas added 1 commit 2023-06-11 07:25:36 +02:00
Guillermo Venegas requested review from Campbell Barton 2023-06-11 07:29:35 +02:00
Guillermo Venegas reviewed 2023-06-11 08:05:17 +02:00
@ -243,0 +244,4 @@
const StringRef *find_string_literal(const Array<StringRef> &string_literals, const char *text)
{
auto string_literal = std::upper_bound(
string_literals.begin(), string_literals.end(), StringRef(text));
Author
Contributor

Should use StringRef(text, 0) to avoid calculating the string size with StringRef(text)?
size is not needed when comparing StringRef

Should use StringRef(text, 0) to avoid calculating the string size with StringRef(text)? size is not needed when comparing StringRef

I don't have a strong opinion on this although it seems like a mis-use of the API. I'd like to see the issue with blender asserting on startup solved first as it might change how the arrays are declared, although this is more likely to be related to Array use than StringRef.

I don't have a strong opinion on this although it seems like a mis-use of the API. I'd like to see the issue with blender asserting on startup solved first as it might change how the arrays are declared, although this is more likely to be related to `Array` use than `StringRef`.

Attached updated version of this patch with some opinionated changes.

  • Moved static literal deletions to the top of the top of each file.
  • Sorted alphabetically (as this runs through a sort function later always).
  • Minor renaming.

NOTE: This patch currently causes Blender not to start when launched with blender -d seems allocating before guarded-alloc is properly initialized is causing issues. This needs to be investigated / resolved.

Attached updated version of this patch with some opinionated changes. - Moved static literal deletions to the top of the top of each file. - Sorted alphabetically (as this runs through a sort function later always). - Minor renaming. ---- NOTE: This patch currently causes Blender not to start when launched with `blender -d` seems allocating before guarded-alloc is properly initialized is causing issues. This needs to be investigated / resolved.
Campbell Barton requested changes 2023-06-11 08:14:42 +02:00
Campbell Barton left a comment
Owner

blender -d asserting on startup needs to be resolved.

`blender -d` asserting on startup needs to be resolved.
Author
Contributor

Moved arrays from text_format_osl.cc to simple arrays fixes 2 memory blocks, i will try with Vector
image

image

Moved arrays from text_format_osl.cc to simple arrays fixes 2 memory blocks, i will try with Vector ![image](/attachments/e7567c3b-ac6c-4297-9daa-a22fae27afcf) ![image](/attachments/3dfb1de6-6cd4-467e-9594-b97a95d15f60)
Author
Contributor

Tested with vector and same issue

Almost all files moved to simple arrays and almost all errors fixed

image

Tested with vector and same issue Almost all files moved to simple arrays and almost all errors fixed ![image](/attachments/575e7eda-9497-4423-8eed-273531c59b80)

@guishe

static Span<StringRef> py_map_get()
{
  static Array<StringRef> map = {"aaa", "bbb", ...};
  return map;
}
@guishe ```Cpp static Span<StringRef> py_map_get() { static Array<StringRef> map = {"aaa", "bbb", ...}; return map; } ```

Also:
StringRef already have == operator.
Use Span to avoid passing containers for read (const Array<> &src -> const Span<> src).
StringRef is a ref type, can passed by value. For be optionaly, meybe std::optional<StringRef>?

Also: `StringRef` already have `==` operator. Use `Span` to avoid passing containers for read (`const Array<> &src` -> `const Span<> src`). `StringRef` is a ref type, can passed by value. For be optionaly, meybe `std::optional<StringRef>`?
Guillermo Venegas added 1 commit 2023-06-11 10:30:11 +02:00
f7fcb32681 changes
Co-authored-by: ideasman42
Co-authored-by: guishe
Author
Contributor

I converted it to a simple array, tomorrow I will be able to continue trying other ways
Now it not crash on start whit blender -d, and now I realize that before with Array blender last longer to start , like 3-5 seconds more

I converted it to a simple array, tomorrow I will be able to continue trying other ways Now it not crash on start whit `blender -d`, and now I realize that before with Array<StringRef> blender last longer to start , like 3-5 seconds more
Author
Contributor

@guishe

static Span<StringRef> py_map_get()
{
  static Array<StringRef> map = {"aaa", "bbb", ...};
  return map;
}

Would try this tomorrow

> @guishe > ```Cpp > static Span<StringRef> py_map_get() > { > static Array<StringRef> map = {"aaa", "bbb", ...}; > return map; > } > ``` Would try this tomorrow
Guillermo Venegas added 1 commit 2023-06-11 10:44:40 +02:00
Author
Contributor

Now these removed functions are templates in the .hh file

Now these removed functions are templates in the .hh file
Author
Contributor

With std::vector the error is not reproduced

The problem is with blender::vector and blender::array

With std::vector the error is not reproduced The problem is with blender::vector and blender::array
Author
Contributor

@guishe

static Span<StringRef> py_map_get()
{
  static Array<StringRef> map = {"aaa", "bbb", ...};
  return map;
}

in this way the Array must already be sorted, or:

static Span<StringRef> py_map_get()
{
  static bool sorted = false;
  static Array<StringRef> map = {"aaa", "bbb", ...};
  if(!sorted) {
      sort(map);
      sorted = true;
  }
  return map;
}
> @guishe > ```Cpp > static Span<StringRef> py_map_get() > { > static Array<StringRef> map = {"aaa", "bbb", ...}; > return map; > } > ``` in this way the Array must already be sorted, or: ```Cpp static Span<StringRef> py_map_get() { static bool sorted = false; static Array<StringRef> map = {"aaa", "bbb", ...}; if(!sorted) { sort(map); sorted = true; } return map; } ```

If runtime sort is so important, then:

static Span<StringRef> py_map_get()
{
  static const Array<StringRef> map = [](){ return sort({"aaa", "bbb", ...}); }();
  return map;
}
If runtime sort is so important, then: ```Cpp static Span<StringRef> py_map_get() { static const Array<StringRef> map = [](){ return sort({"aaa", "bbb", ...}); }(); return map; } ```
Author
Contributor
static Array<StringRef> py_map_get()
{
  static Array<StringRef> map = {"aaa", "bbb", ...};
  return map;
}

works, i use this way to be able to sort only on startup

And use Span<StringRef> as argument for text_format_string_literal_find

const StringRef *text_format_string_literal_find(const Span<StringRef> string_literals,
                                                 const char *text);

If runtime sort is so important, then:

In this way we can have in code groups of strings like in the imagen, and in startup we order them to make faster searches

image

``` cpp static Array<StringRef> py_map_get() { static Array<StringRef> map = {"aaa", "bbb", ...}; return map; } ``` works, i use this way to be able to sort only on startup And use `Span<StringRef>` as argument for `text_format_string_literal_find` ``` cpp const StringRef *text_format_string_literal_find(const Span<StringRef> string_literals, const char *text); ``` >> If runtime sort is so important, then: In this way we can have in code groups of strings like in the imagen, and in startup we order them to make faster searches ![image](/attachments/be940727-51d1-4212-8a9a-8a5cd8713a42)
Guillermo Venegas added 1 commit 2023-06-11 19:18:05 +02:00

Seems like the search speed would be better if you check the words by their popularity of usage in the language? There is a complicated heuristic here, is it necessary to pay attention to this now?
Also, are you in the blender chat?

Seems like the search speed would be better if you check the words by their popularity of usage in the language? There is a complicated heuristic here, is it necessary to pay attention to this now? Also, are you in the blender chat?
Author
Contributor

a binary search is done(possible because it is ordered), I think it's faster that way

Also, are you in the blender chat?

Yes

a binary search is done(possible because it is ordered), I think it's faster that way > Also, are you in the blender chat? Yes
Guillermo Venegas added 1 commit 2023-06-12 04:42:06 +02:00
Guillermo Venegas added 1 commit 2023-06-13 05:22:21 +02:00
Guillermo Venegas added 1 commit 2023-06-13 05:28:55 +02:00
buildbot/vexp-code-patch-coordinator Build done. Details
c7a3f666a6
remnove us of stringref
Guillermo Venegas requested review from Campbell Barton 2023-06-22 20:05:05 +02:00

@blender-bot build

@blender-bot build
Campbell Barton requested changes 2023-06-23 02:17:10 +02:00
Campbell Barton left a comment
Owner

Please rebase on main (there seems to be some conflicts), the buildbot fails to build it.

Please rebase on `main` (there seems to be some conflicts), the buildbot fails to build it.
Campbell Barton requested changes 2023-06-23 02:23:26 +02:00
Campbell Barton left a comment
Owner

Requesting changes, also, did you comapre the speed of syntax highlighting before after this change?

Requesting changes, also, did you comapre the speed of syntax highlighting before after this change?
@ -243,0 +244,4 @@
const int text_format_string_literal_find(const Span<const char *> string_literals,
const char *text)
{
auto predicate_func = [](const char *text, const char *string_literal) {

Prefer the shorter cmp_fn.

Prefer the shorter `cmp_fn`.
@ -243,0 +262,4 @@
return -1;
}
const bool text_format_string_literals_check_sorted_array(

As this function is only for debug builds it can be enclosed in

#ifndef NDEBUG (same for declaration).

As this function is only for debug builds it can be enclosed in `#ifndef NDEBUG` (same for declaration).
@ -7,6 +7,11 @@
*/
#pragma once
#include "BLI_array.hh"

array & string_ref headers aren't needed.

array & string_ref headers aren't needed.
@ -33,0 +91,4 @@
/** Python special name.*/
static const char *text_format_py_literals_specialvar_data[]{
/* Prevent wrapping onto multiple lines, avoid re-wrapping when values change. */

Best remove the Prevent wrapping onto multiple lines - as all clang-format off are meant to be noted why, use a short.

/* Force single column, sorted list. */
/* clang-format off */

No need for a detailed description.

Best remove the `Prevent wrapping onto multiple lines` - as all `clang-format off` are meant to be noted why, use a short. ``` /* Force single column, sorted list. */ /* clang-format off */ ``` No need for a detailed description.
Author
Contributor

did you compare the speed of syntax highlighting before after this change?

I tried and i force to run multiple times in a frame run but not makes enough difference, maybe arrays are not too large enough for a big improved in time, or the compiler is too good enough to make a simple search in the chained if/else.
But anyway, using an sorted array doesn't make performance worse.

> did you compare the speed of syntax highlighting before after this change? I tried and i force to run multiple times in a frame run but not makes enough difference, maybe arrays are not too large enough for a big improved in time, or the compiler is too good enough to make a simple search in the chained if/else. But anyway, using an sorted array doesn't make performance worse.
Guillermo Venegas added 2 commits 2023-06-23 04:45:37 +02:00
Guillermo Venegas added 1 commit 2023-06-23 04:46:15 +02:00
Guillermo Venegas requested review from Campbell Barton 2023-06-23 04:46:39 +02:00

@blender-bot build

If the build-bot doesn't show any errors, I'll commit with minor changes.

  • string_literal & string_literal was used to refer to both const char * and const char *const * types which is fairly confusing (obscured by auto, rename one to string_literal_p).
  • remove redundant strlen() call.
@blender-bot build If the build-bot doesn't show any errors, I'll commit with minor changes. - `string_literal` & `string_literal` was used to refer to both `const char *` and `const char *const *` types which is fairly confusing (obscured by `auto`, rename one to `string_literal_p`). - remove redundant `strlen()` call.

Committed 3f26bdf840.

Committed 3f26bdf840ab80f529905c3c865458c12f363111.
Campbell Barton closed this pull request 2023-06-23 12:13:38 +02:00
Guillermo Venegas deleted branch simplify-keywords 2023-06-24 06:01:03 +02:00
Some checks failed
buildbot/vexp-code-patch-coordinator Build done.

Pull request closed

Sign in to join this conversation.
No reviewers
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#108775
No description provided.