Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autofill comment when inserting a new line in documentation #95955

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

Cronos87
Copy link

@Cronos87 Cronos87 commented Aug 22, 2024

This PR implements the following proposal godotengine/godot-proposals#8244.

Here it is in action:

CleanShot.2024-08-22.at.18.06.52.mp4

Please keep in mind that this is my first contribution and my first step into the C++ world, but I really want to contribute to Godot :)

Any feedback, help, or advice is very welcome!

Comment on lines 1158 to 1184
// Insert a documentation comment if the caret was previously on a comment block.
String prev_line = get_line(get_caret_line(i) - 1);

if (prev_line.strip_edges().begins_with("##")) {
insert_text_at_caret("## ", i);
}
Copy link
Contributor

@Mickeon Mickeon Aug 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a feature specific to GDScript and the Editor. I am not savvy enough to say where this should go, but definitely not in the CodeEdit class, which is designed to be much more generalized.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the initial purpose of this PR was to gather information on how to do it best and to learn the codebase. @kitbdev gave me a clue about it; see #95955 (comment). I can enhance it now :)

Thank you for your feedback!

@kitbdev
Copy link
Contributor

kitbdev commented Aug 22, 2024

CodeEdit should be language independent, so we can't use ## in it.
The delimiter system is how we check for regular comments, so it looks like it needs to know about doc comments and the String to insert on a new line.

Then it can probably be set here:

List<String> doc_comments;
script->get_language()->get_doc_comment_delimiters(&doc_comments);
for (const String &doc_comment : doc_comments) {
String beg = doc_comment.get_slice(" ", 0);
String end = doc_comment.get_slice_count(" ") > 1 ? doc_comment.get_slice(" ", 1) : String();
text_edit->add_comment_delimiter(beg, end, end.is_empty());
if (!end.is_empty() && !text_edit->has_auto_brace_completion_open_key(beg)) {
text_edit->add_auto_brace_completion_pair(beg, end);
}
}

@Cronos87
Copy link
Author

Cronos87 commented Aug 23, 2024

CodeEdit should be language independent, so we can't use ## in it. The delimiter system is how we check for regular comments, so it looks like it needs to know about doc comments and the String to insert on a new line.

It totally makes sense. I'll give it a try as soon as I can in the file you just pointed out.

Thank you for your feedback!

Edit: I took a look at the file you told me, @kitbdev. I can get the delimiters in the code_edit.cpp by doing get_comment_delimiters(). However, in my case in GDScript, the array will be ['##', '#']. It doesn't inform me which one is the doc comment, and I didn't find a way to identify it. Maybe you have a clue regarding this?

I continue to search for the answer in any case :)

@dalexeev
Copy link
Member

Perhaps this makes sense not only for doc comments, but for regular ones too. Kate has interesting behavior:

  1. Enter copies the indentation of the previous line. If it ends with {, :, etc. (depending on the language), the indentation level is increased.
  2. Shift+Enter copies the indentation of the previous line with leading symbols/spaces up to the first letter/number.
  3. Ctrl+Enter inserts only a line break, like in simple text editors like Notepad.

Shift+Enter is also useful for Markdown and YAML lists.

@RedMser
Copy link
Contributor

RedMser commented Aug 23, 2024

I can get the delimiter in the code_edit.cpp by doing get_comment_delimiters().

Why not use get_doc_comment_delimiters() which returns only ## for GDScript? That's also what's used in the code that kitbdev linked to.

@Cronos87
Copy link
Author

Why not use get_doc_comment_delimiters() which returns only ## for GDScript? That's also what's used in the code that kitbdev linked to.

I agree, but this method is only available in script_text_editor.cpp as far as I know. I suppose I can add a method to code_edit.cpp to retrieve the data, but I don't know if this is a good practice.

I'm digging into the codebase; I need time to get used to it, I suppose 😊

@Cronos87 Cronos87 changed the title Autofill comment when inserting a new line in documentation [DRAFT] Autofill comment when inserting a new line in documentation Aug 24, 2024
@Cronos87 Cronos87 force-pushed the feature/auto-fill-documentation-comment-on-new-line branch from bdb21c6 to fb52d24 Compare August 24, 2024 22:36
@Cronos87 Cronos87 requested a review from a team as a code owner August 24, 2024 22:37
@Cronos87
Copy link
Author

Cronos87 commented Aug 24, 2024

I did my best to enhance it and to be more flexible. Feedback is very welcome 🙏

@Cronos87 Cronos87 marked this pull request as draft August 24, 2024 23:13
@Cronos87 Cronos87 changed the title [DRAFT] Autofill comment when inserting a new line in documentation Autofill comment when inserting a new line in documentation Aug 25, 2024
@Cronos87 Cronos87 marked this pull request as ready for review August 25, 2024 10:06
@Cronos87 Cronos87 requested a review from a team as a code owner August 25, 2024 12:32
@Cronos87 Cronos87 force-pushed the feature/auto-fill-documentation-comment-on-new-line branch from b644c56 to b85b8a3 Compare August 25, 2024 12:48
Copy link
Contributor

@kitbdev kitbdev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some tests in tests\scene\test_code_edit.h for testing the newline functionality would be nice too.

@@ -1863,6 +1879,35 @@ int CodeEdit::is_in_comment(int p_line, int p_column) const {
return _is_in_delimiter(p_line, p_column, TYPE_COMMENT);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return _is_in_delimiter(p_line, p_column, TYPE_COMMENT);
return _is_in_delimiter(p_line, p_column, TYPE_COMMENT) || _is_in_delimiter(p_line, p_column, TYPE_DOC_COMMENT) ;

Maybe this should also return true for doc comments, so its behavior doesn't change. Or the uses of is_in_comment need to be updated to also check for doc comments.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, it makes sense! Thanks for pointing this out!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hum… for some reason I don't know yet, adding this check breaks the tests and some features too, like line folding.

I'll take a closer look at it after work.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I understood! _is_in_delimiter returns an integer and not a boolean, so it can be used this way.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just pushed the fix :)

@@ -1154,6 +1154,22 @@ void CodeEdit::_new_line(bool p_split_current_line, bool p_above) {
set_caret_line(get_caret_line(i) - 1, false, true, 0, i);
set_caret_column(get_line(get_caret_line(i)).length(), i == 0, i);
}

// Insert a documentation comment if the caret was previously on a comment block.
int prev_line = get_caret_line(i) - 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should adapt if p_above is true (ctrl+shift+enter).

Copy link
Author

@Cronos87 Cronos87 Aug 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix has been pushed :)

@Cronos87
Copy link
Author

Perhaps this makes sense not only for doc comments, but for regular ones too. Kate has interesting behavior:

  1. Enter copies the indentation of the previous line. If it ends with {, :, etc. (depending on the language), the indentation level is increased.
  2. Shift+Enter copies the indentation of the previous line with leading symbols/spaces up to the first letter/number.
  3. Ctrl+Enter inserts only a line break, like in simple text editors like Notepad.

Shift+Enter is also useful for Markdown and YAML lists.

Sorry for the delayed answer, @dalexeev! Yes, indeed, that would be nice, but the proposal is limited to the documentation comment. I don't know what people think about it and if we should extend the feature to comments too.

I am open to discussion.

@@ -1154,6 +1154,22 @@ void CodeEdit::_new_line(bool p_split_current_line, bool p_above) {
set_caret_line(get_caret_line(i) - 1, false, true, 0, i);
set_caret_column(get_line(get_caret_line(i)).length(), i == 0, i);
}

// Insert a documentation comment if the caret was previously on a documentation comment block.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that a doc comment can be multiline (like /** */).

@dalexeev
Copy link
Member

Yes, indeed, that would be nice, but the proposal is limited to the documentation comment. I don't know what people think about it and if we should extend the feature to comments too.

Regarding the Kate-like behavior, I agree that it's too much and requires a separate proposal. But I think it would be reasonable to discuss extending the feature to regular comments as part of this proposal/PR.

In fact, it would even simplify the implementation. When I added doc comment highlighting, I didn't add a new API to CodeEdit, since it was not necessary. The "doc comment" term was only introduced in the editor, not the scene.

Also, this can break compatibility in some ways. Previously, doc comments were considered comments, so is_in_comment() returned true for them. Now doc comments are separated into a new category, although it would be more logical to consider them a subset of comments.

@Cronos87
Copy link
Author

Cronos87 commented Aug 27, 2024

Regarding the Kate-like behavior, I agree that it's too much and requires a separate proposal. But I think it would be reasonable to discuss extending the feature to regular comments as part of this proposal/PR.

I totally agreed with you. I can start working on this.

In fact, it would even simplify the implementation.

Yes, it would be easier to implement it for both.

Also, this can break compatibility in some ways. Previously, doc comments were considered comments, so is_in_comment() returned true for them. Now doc comments are separated into a new category, although it would be more logical to consider them a subset of comments.

Sadly, my knowledge regarding the Godot codebase is limited; that's why I tried to implement this proposal to gain experience in both the Godot codebase and C++.

I would be glad to have some clues about how to implement it—just a clue, not the full implementation—and I will give it a try to respect the best practices in this codebase.

For example, is Code Edit the right place to implement it? And can you develop your idea to consider them as a subset, please?

By the way, what do you think, is it necessary to add an option to enable / disable this feature?

Many thanks for the help!

@Cronos87 Cronos87 marked this pull request as draft August 27, 2024 19:39
Comment on lines 1164 to 1268
for (const String doc_comment : get_doc_comment_delimiters()) {
const String beg = doc_comment.get_slice(" ", 0);

if (prev_line_content.begins_with(beg)) {
insert_text_at_caret(doc_comment + " ", i);
break;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a separate kind of key for the delimiters, since other styles have a different characters for start /**, end */, and in between new lines *.

Maybe the presence of this new line key can be what enables this behavior, and then we may not need a separate doc comment type?

@kitbdev
Copy link
Contributor

kitbdev commented Aug 29, 2024

I think this behavior should only be on doc comments as initially proposed, if it is on regular comments it may be annoying to add new lines for regular code around comments. Though the implementation can be generalized for all types of delimiters if it is easier.

Also this shouldn't cause compatibility issues, CodeEdits behavior should stay the same, since the user hasn't specified to add doc comments instead of regular comments, so all the regular comment delimiter functions should work the same.

By the way, what do you think, is it necessary to add an option to enable / disable this feature?

It shouldn't be needed to have a dedicated enable option, a user can just not use doc comments, or not have a newline delimiter key, depending on how it is implemented.

@Cronos87
Copy link
Author

It seems like opinions are divided regarding expanding this behavior to regular comments. Originally, my idea was to reproduce the VSCode behavior that I used for years, and I always missed the autofill for the documentation block.

I'm new to Godot Core development, so how is this kind of situation resolved? How do we decide which way to take?

I'm waiting for new opinions before start working on this PR again :)

@Cronos87
Copy link
Author

Cronos87 commented Oct 7, 2024

If the current implementation for the doc comment is fine for everyone, I will add some tests, but I prefer to be sure at the moment it is fine before digging into the tests world.

@Cronos87 Cronos87 force-pushed the feature/auto-fill-documentation-comment-on-new-line branch 2 times, most recently from 36e42e2 to 6b67dd6 Compare October 11, 2024 12:05
@Cronos87 Cronos87 force-pushed the feature/auto-fill-documentation-comment-on-new-line branch from 6b67dd6 to f3526b2 Compare October 18, 2024 16:04
@Cronos87 Cronos87 force-pushed the feature/auto-fill-documentation-comment-on-new-line branch from f3526b2 to d12aa00 Compare November 1, 2024 13:32
@Cronos87 Cronos87 force-pushed the feature/auto-fill-documentation-comment-on-new-line branch from d12aa00 to ab64319 Compare November 16, 2024 11:13
Copy link
Member

@AThousandShips AThousandShips left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will try to test the functionality next week

@@ -457,6 +460,9 @@ class CodeEdit : public TextEdit {
Point2 get_delimiter_start_position(int p_line, int p_column) const;
Point2 get_delimiter_end_position(int p_line, int p_column) const;

Vector<String> get_block_key_delimiters() const;
void set_block_key_delimiters(const List<String> *p_delimiters);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
void set_block_key_delimiters(const List<String> *p_delimiters);
void set_block_key_delimiters(const List<String> &p_delimiters);

No reason to pass it as a pointer unless it's optional, in that case it needs a null check

But this should really use Vector<String> IMO, it transfers to a Vector anyway so there's going to be a conversion anyway, so I'd say:

Suggested change
void set_block_key_delimiters(const List<String> *p_delimiters);
void set_block_key_delimiters(const Vector<String> &p_delimiters);

Copy link
Author

@Cronos87 Cronos87 Nov 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if it is viable to convert it to a Vector, as the API requires a List from the key delimiters. So I need to convert it to a Vector and then pass it to the method. It seems to complicate it a little bit. What do you think?

See the update here: https://github.com/godotengine/godot/pull/95955/files#diff-fa2cafb4b2d8b59e5baeba0b861f7f2f6bf6c213d6387254fee5a7682478e588R264-R273

scene/gui/code_edit.h Outdated Show resolved Hide resolved
scene/gui/code_edit.cpp Outdated Show resolved Hide resolved
@Cronos87
Copy link
Author

Cronos87 commented Nov 16, 2024

Many thanks for the review 🙏 I'm pushing soon the feedbacks!

Edit: Once again, I'm too used to Gitlab 😅

@Cronos87 Cronos87 closed this Nov 16, 2024
@Cronos87 Cronos87 reopened this Nov 16, 2024
@AThousandShips
Copy link
Member

Tested and works as expected generally, but I still hold that it's unintuitive and confusing to not have any way to abort this, but to me it's not necessarily a dealbreaker, but I'd suggest having some way to stop the doc comment and return to normal

At minimum though I think this should be controlled by a setting as it is pretty annoying to get stuck in this mode, and either add support for exiting somehow (possibly using Shift+Enter to insert a normal line, or that enter on a second consecutive entered line makes it a normal line), or making it a dedicated key to do this (again Shift+Enter was suggested above)

But adding an option to control this would be sufficient for me, but I do think that's a necessity

@kitbdev
Copy link
Contributor

kitbdev commented Dec 3, 2024

After thinking about it, I think this should only be for multi-line comments and maybe splitting single line comments. This would help match other editors too.
For single line comments, the "Smart newline" behavior on a separate shortcut would be better so it has to be done intentionally. ui_text_newline_continue_comment or something.
This way it works for regular comments as well as doc comments.

Doc comments that are only a single line are pretty common, probably more common than ones that are multiple lines. So having this behavior by default on single line doc comments can be unwanted and surprising.

Edit: Pressing enter again to remove the comment instead could also work, but the script editor hasn't done stuff like that before, so it may be more work.

@Cronos87
Copy link
Author

Cronos87 commented Dec 4, 2024

Thank you for the review and the thoughts shared about this proposal 🙏
It seems that the behavior chosen is the one closest to Kate. That's totally fine for me 😊

I will come back with a new implementation as soon as I am satisfied with what I did!

Edit: I have no words, yeah, same shortcut again… 😅

@Cronos87 Cronos87 closed this Dec 4, 2024
@Cronos87 Cronos87 reopened this Dec 4, 2024
@Cronos87 Cronos87 force-pushed the feature/auto-fill-documentation-comment-on-new-line branch from d68a18d to 2216cf7 Compare December 4, 2024 14:58
@kitbdev
Copy link
Contributor

kitbdev commented Dec 4, 2024

Just to be clear, the current approach is still good for multi-line comments, so the new implementation can be in a new PR.

@Cronos87
Copy link
Author

Cronos87 commented Dec 4, 2024

You mean doc comments and regular comments, but only multiline like /** */, right?

If that is the case, it will only be triggered for C# in the current implementation.

@kitbdev
Copy link
Contributor

kitbdev commented Dec 4, 2024

It will also work on the shader editor.

@Cronos87
Copy link
Author

Cronos87 commented Dec 19, 2024

I didn't abandon this MR; I've been quite busy with my work lately. I'll come back to it soon 😊

@AThousandShips
Copy link
Member

Don't worry take your time!

@Cronos87 Cronos87 force-pushed the feature/auto-fill-documentation-comment-on-new-line branch from 2216cf7 to 846d8d8 Compare December 23, 2024 22:27
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.

Autofill documentation comment block when returning to a new line
7 participants