-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
fix: fix exception in custom preview layout change #7539
Conversation
This is just one approach of this issue. Although it works, I still consider that it's a bad implementation and lack of elegance. |
Hi @yinpeiqi , thanks for your interest in this issue. |
I think suspense parsing the code can't solve this problem. It will cause a time-wait when 'save' is clicked which is unnecessary. Besides, only suspense parsing may not work because users may edit it for a long time. |
I really think we are talking about two different things... The original issue never said anything about saving. @Siedlerchr suggested, that changes should only be evaluated when pressing save. As I looked into a code a bit, a saw several problems: first if all, we have two different ways to evaluate the code: One thing is syntax highlighting in the GUI, the other is parsing it in logic to create a usable layout. This is needed to create the preview of the changes, if you switch tabs from So my suggestion would be to change the listener on every text change (PreviewTabViewModel line 94-99) to when someone changes to the preview tab and to parse it when the layout is to be saved. |
I think I got what you mean. So the listener should not be bind there and we don't need that listener. We should call the setText function only when we click 'preview' or 'save', am I right? |
I guess so. |
I think we can add try-catch when we use parse() in getLayoutFromText(). Then we can handle the StringIndexOutOfBoundsException when the text changed. After discussing with yinpeiqi, we think this way can fix this issue. |
No, please don't touch the TextLayout. |
You are right. If I use try-catch in getLayoutFromText() just to hide this error from the user, it does not prevent it from happening, and it may affect other places where this method is used. I think the modification logic you mentioned is feasible. I think we have two different logic to fix this issue: One is to keep the original change monitoring method, but do not call setText when a possible error situation is encountered during monitoring, and the other is to call the setText method when leaving the But as a user, I think I would prefer the second way because such repeated calls are not very perceptive, and important error prompts will not be missed. What do you think about it? @calixtus **update: ** sorry, the second problem does not exist. I can override the method |
I believe a try-catch clause isn't necessary. The problem is imho the changelistener parsing the whole text after every text change. This isn't necessary at all, but requires a lot of processing power. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Three small problems
@@ -304,6 +316,7 @@ public void selectedInChosenDown() { | |||
|
|||
public void resetDefaultLayout() { | |||
PreviewLayout defaultLayout = findLayoutByName("Preview"); | |||
System.out.println("resetDefaultLayout"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use our logger infrastructure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, just for debug. I will remove it.
@@ -110,6 +114,13 @@ public PreviewTabViewModel(DialogService dialogService, PreferencesService prefe | |||
); | |||
} | |||
|
|||
public void checkParseWhenSave() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why public?
public void checkParseWhenSave() { | ||
var currentLayout = getCurrentLayout(); | ||
if (currentLayout instanceof TextBasedPreviewLayout) { | ||
((TextBasedPreviewLayout) currentLayout).setText(sourceTextProperty.getValue().replace("\n", "__NEWLINE__")); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code duplication
I don't know why I failed some fetcher test. I think I have roughly fixed this issue, what else can I do now? @calixtus |
The failing fetcher tests are currently a known problem. You can ignore them. |
@@ -260,6 +260,7 @@ private void parseField() throws IOException { | |||
} | |||
throw new StringIndexOutOfBoundsException( | |||
"Backslash parsing error near \'" + lastFive.toString().replace("\n", " ") + '\''); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not add an empty line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This quick fix fixes the issue, but leads to less maintainble code. Please introduce
public Optional<Layout> getLayoutFromText() {
try { | ||
layoutParse(); | ||
} catch (StringIndexOutOfBoundsException e) { | ||
// catch this error but not give to user [when typing] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Catching runtime excpetions is a very bad thing. Where exactly is the StringIndexOutOfBoundsException
thrown? Exceptions should be catched as early as possible.
In this case, it is thrown at parse()
in LayoutHelper.java line 191.
The real fix is that org.jabref.logic.layout.LayoutHelper#getLayoutFromText
should return Optional<Layout>
and not throw any exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello, sir. I am also following this issue. Do you think this exception StringIndexOutOfBoundsException
is unnecessary? This StringIndexOutOfBoundsException
will be thrown when '\' is entered(in editing stage).
What if it's in the saving stage? If user click the save
button, and there is only a '\', should the exception still be thrown?
If we do not throw any exception, the user may not be aware that there is a wrong '\'. If you insist that throwing no exception is a better choice, I can help you implement it. Don't worry about @yinpeiqi and @zc-BEAR. I have communicated with them. Looking forward to your reply.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After my investigation, Layout
could not be null. Therefore LayoutHelper#getLayoutFromText
seems not effective. In my opinion, we can delete the code
throw new StringIndexOutOfBoundsException( "Backslash parsing error near \'" + lastFive.toString().replace("\n", " ") + '\'');
in LayoutHelper#parseField
.
I also found that Layout
's constructor will warn "Nested field/group entries are not implemented!" in logger if the user input's invalid. In this case, does the error message need to be presented to the user? @koppor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not about Layout
being null
, its about getting rid of the exception. Using exceptions for control flow is a bad thing (see also Java-by-Comparison). Please refactor LayoutHelper
not to throw any exception at parse()
or getLayoutFromText()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@EricLee543 I am not sure how to present that to the user. In the long run, we should switch to Apache Velocity as this shifts maintenance effort from JabRef to another project. See koppor#392 for details.
Thank you for working on this and the discussion on Optionals vs. Exceptions. I took the freedom to take over. First of all, I created test cases to really debug the cause and be sure that future changes do not break the contracts. To free your energy for other work, I take the freedom to close this PR. Follow-up at #7851. |
This problem is cause by unexpected exception trigger that listening to value change. In layoutHelper, this function is call by both button click 'save', init loading and value change of text. Actually the last one do not need trigger this exception. So I add a flag from the separation of these three conditions.
Fixses #7526
CHANGELOG.md
described in a way that is understandable for the average user (if applicable)