-
-
Notifications
You must be signed in to change notification settings - Fork 86
Allow escape sequences to span multiple lines and support default fg/bg colors #137
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
Conversation
|
This test seems to have passed ... |
| } | ||
|
|
||
| @Test | ||
| @Ignore |
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.
@dblock The test is ignored, so it never even ran.
|
I am working on a fix for this which may help with JENKINS-34019 because the fix here will close open tags at the end of each line and reopen them on the next line, which seems to be the suggested approach to fix that ticket. |
src/main/java/hudson/plugins/ansicolor/AnsiAttributeElement.java
Outdated
Show resolved
Hide resolved
src/main/java/hudson/plugins/ansicolor/AnsiHtmlOutputStream.java
Outdated
Show resolved
Hide resolved
| return this; | ||
| return openTags == nextOpenTags | ||
| ? this | ||
| : new ColorConsoleAnnotator(colorMapName, charset, nextOpenTags); |
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.
Based on my reading of the ConsoleAnnotator Javadocs, if we want to track state from line-to-line then we need to handle it by returning a new instance like this. Maybe wrong to return this instead of creating a new state when the open tags match.
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.
I thought the suggested fix for JENKINS-34019 was just to close all outstanding tags at the end of a line, as if this were a user error, not to try to make them apply across lines.
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.
When a style continues to the next line, the ConsoleAnnotatorFactory can insert a closing tag at the end of the line and an opening tag at the beginning of the next line. This prevents the timestamps from being affected.
Full comment. What you propose would certainly be simpler, but I'm not sure what the expected behavior is. What do you think should be the behavior for the test case I added?
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.
I feel like it does not matter much, since it is unlikely people would have multiline formatting intentionally, so it is OK to keep the implementation simpler.
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.
#145 shows a problem with output of terraform at the command line, and based on a screenshot of the text it looks like it might be using multiline formatting, but I'm not sure. I'll leave this as-is for now until I have time to investigate in more depth.
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.
Confirmed via
docker run --rm hashicorp/terraform plan 2>&1 | od -a(Though it also looks like the Terraform output is buggy—ANSI sequences are not nestable, and it is emitting several esc [ 0 m sequences in a row.)
src/main/java/hudson/plugins/ansicolor/ColorConsoleAnnotator.java
Outdated
Show resolved
Hide resolved
src/main/java/hudson/plugins/ansicolor/ColorConsoleAnnotator.java
Outdated
Show resolved
Hide resolved
| System.out.print(html); | ||
| assertThat(html.replaceAll("<span style=\"display: none\">.+?</span>", ""), | ||
| allOf( | ||
| containsString("<b><span style=\"color: #1E90FF;\">This text should be bold and blue\n</span></b>"), |
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.
The literal \n characters in these tests would probably cause them to fail on Windows.
| }); | ||
| } | ||
|
|
||
| @Test |
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.
I should create a JIRA issue for these and add @Issue.
|
Needs to be merged with master after the change to use comments instead of |
src/main/java/hudson/plugins/ansicolor/ColorConsoleAnnotator.java
Outdated
Show resolved
Hide resolved
|
@jglick Can I leave this to you to review/merge/comment? |
| try (AnsiHtmlOutputStream ansiOs = new AnsiHtmlOutputStream(outgoing, colorMap, emitter, openTags); | ||
| CountingOutputStream incoming = new CountingOutputStream(ansiOs)) { | ||
| emitter.incoming = incoming; | ||
| // We need to write one UTF-16 code unit at a time so that byte offsets match Java character offsets when inserting HTML. |
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.
Needs to be resolved in favor of #143, right?
jglick
left a comment
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.
Not sure the extra complexity is worth it for a relatively uncommon use case, but maybe users would consider lack of multiline support a regression from the old implementation.
Anyway, it has test coverage, so (other than the logging buglet) go for it.
| this.colorMapName = colorMapName; | ||
| LOGGER.fine("creating annotator with colorMapName=" + colorMapName); | ||
| this.openTags = openTags; | ||
| LOGGER.log(Level.FINE, "creating annotator with colorMapName={0} openTags={2}", new Object[] { colorMapName, openTags }); |
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.
{1} not {2}
| AnsiColorMap colorMap = Jenkins.get().getDescriptorByType(AnsiColorBuildWrapper.DescriptorImpl.class).getColorMap(colorMapName); | ||
| List<AnsiAttributeElement> nextOpenTags = openTags; | ||
| // TODO: As a performance improvement, we could create a branch where `s.indexOf('\u001B') == -1` but other | ||
| // conditions are true that surrounds the text in the appropriate tags without going through AnsiHtmlOutputStream. |
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.
Unnecessary—this case is likely quite rare.
| int outCount = outgoing.getCount() + adjustment; | ||
| // All ANSI escapes sequences contain at least 2 bytes on modern platforms, so any HTML emitted | ||
| // directly after the first character is received is due to the initialization process of the stream and | ||
| // belongs at position 0 (i.e. default background/foreground colors). |
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.
I think I need more caffeine to understand this. :-)
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.
Yeah this code was and still is quite confusing to me. Thankfully, the if statement is covered by the newly added tests, and if it is removed the tests fail, so we should be able to avoid future regressions.
| if (colorMap.getDefaultBackground() != null || colorMap.getDefaultForeground() != null) { | ||
| // The default color scheme will be opened automatically at the beginning of the stream on the next | ||
| // line, so we don't want to duplicate it. | ||
| nextOpenTags.remove(0); |
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.
.subList(1) might be less scary to readers, though I see that the getter does make a fresh copy.
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.
Good point. I tried switching to sublist, but the implementation is not serializable so it would require another copy, which seems excessive, so I added a comment to help clarify for future readers but left the original code.
Fixes #135.
This PR currently adds tests and fixes for 2 issues: