Skip to content

Commit

Permalink
Rework bold / underline attribute support on windows #219
Browse files Browse the repository at this point in the history
  • Loading branch information
gnodet committed Jan 26, 2018
1 parent 2973cec commit 0bff330
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.fusesource.jansi.internal.Kernel32.*;
import org.fusesource.jansi.internal.WindowsSupport;
import org.jline.utils.AnsiWriter;
import org.jline.utils.Colors;

import java.io.IOException;
import java.io.Writer;
Expand Down Expand Up @@ -74,6 +75,8 @@ public final class WindowsAnsiWriter extends AnsiWriter {
private final short originalColors;

private boolean negative;
private boolean bold;
private boolean underline;
private short savedX = -1;
private short savedY = -1;

Expand All @@ -96,6 +99,14 @@ private void getConsoleInfo() throws IOException {
private void applyAttribute() throws IOException {
out.flush();
short attributes = info.attributes;
// bold is simulated by high foreground intensity
if (bold) {
attributes |= FOREGROUND_INTENSITY;
}
// underline is simulated by high foreground intensity
if (underline) {
attributes |= BACKGROUND_INTENSITY;
}
if (negative) {
attributes = invertAttributeColors(attributes);
}
Expand Down Expand Up @@ -254,16 +265,18 @@ protected void processCursorToColumn(int x) throws IOException {
}

@Override
protected void processSetForegroundColor(int color, boolean bright) throws IOException {
info.attributes = (short) ((info.attributes & ~0x0007) | ANSI_FOREGROUND_COLOR_MAP[color]);
info.attributes = (short) ((info.attributes & ~FOREGROUND_INTENSITY) | (bright ? FOREGROUND_INTENSITY : 0));
protected void processSetForegroundColorExt(int paletteIndex) throws IOException {
int color = Colors.roundColor(paletteIndex, 16);
info.attributes = (short) ((info.attributes & ~0x0007) | ANSI_FOREGROUND_COLOR_MAP[color & 0x07]);
info.attributes = (short) ((info.attributes & ~FOREGROUND_INTENSITY) | (color > 8 ? FOREGROUND_INTENSITY : 0));
applyAttribute();
}

@Override
protected void processSetBackgroundColor(int color, boolean bright) throws IOException {
protected void processSetBackgroundColorExt(int paletteIndex) throws IOException {
int color = Colors.roundColor(paletteIndex, 16);
info.attributes = (short) ((info.attributes & ~0x0070) | ANSI_BACKGROUND_COLOR_MAP[color]);
info.attributes = (short) ((info.attributes & ~BACKGROUND_INTENSITY) | (bright ? BACKGROUND_INTENSITY : 0));
info.attributes = (short) ((info.attributes & ~BACKGROUND_INTENSITY) | (color > 8 ? BACKGROUND_INTENSITY : 0));
applyAttribute();
}

Expand All @@ -285,29 +298,29 @@ protected void processDefaultBackgroundColor() throws IOException {
protected void processAttributeRest() throws IOException {
info.attributes = (short) ((info.attributes & ~0x00FF) | originalColors);
this.negative = false;
this.bold = false;
this.underline = false;
applyAttribute();
}

@Override
protected void processSetAttribute(int attribute) throws IOException {
switch (attribute) {
case ATTRIBUTE_INTENSITY_BOLD:
info.attributes = (short) (info.attributes | FOREGROUND_INTENSITY);
bold = true;
applyAttribute();
break;
case ATTRIBUTE_INTENSITY_NORMAL:
info.attributes = (short) (info.attributes & ~FOREGROUND_INTENSITY);
bold = false;
applyAttribute();
break;

// Yeah, setting the background intensity is not underlining.. but it's best we can do
// using the Windows console API
case ATTRIBUTE_UNDERLINE:
info.attributes = (short) (info.attributes | BACKGROUND_INTENSITY);
underline = true;
applyAttribute();
break;
case ATTRIBUTE_UNDERLINE_OFF:
info.attributes = (short) (info.attributes & ~BACKGROUND_INTENSITY);
underline = false;
applyAttribute();
break;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import org.jline.utils.AnsiWriter;
import org.jline.utils.Colors;

import static org.jline.terminal.impl.jna.win.Kernel32.BACKGROUND_BLUE;
import static org.jline.terminal.impl.jna.win.Kernel32.BACKGROUND_GREEN;
Expand Down Expand Up @@ -77,6 +78,8 @@ public final class WindowsAnsiWriter extends AnsiWriter {
private final short originalColors;

private boolean negative;
private boolean bold;
private boolean underline;
private short savedX = -1;
private short savedY = -1;

Expand All @@ -98,6 +101,14 @@ private void getConsoleInfo() throws IOException {
private void applyAttribute() throws IOException {
out.flush();
short attributes = info.wAttributes;
// bold is simulated by high foreground intensity
if (bold) {
attributes |= FOREGROUND_INTENSITY;
}
// underline is simulated by high foreground intensity
if (underline) {
attributes |= BACKGROUND_INTENSITY;
}
if( negative ) {
attributes = invertAttributeColors(attributes);
}
Expand All @@ -120,16 +131,6 @@ private void applyCursorPosition() throws IOException {
Kernel32.INSTANCE.SetConsoleCursorPosition(console, info.dwCursorPosition);
}

protected void processDefaultTextColor() throws IOException {
info.wAttributes = (short)((info.wAttributes & ~0x000F ) | (originalColors & 0x000F));
applyAttribute();
}

protected void processDefaultBackgroundColor() throws IOException {
info.wAttributes = (short)((info.wAttributes & ~0x00F0 ) | (originalColors & 0x00F0));
applyAttribute();
}

protected void processEraseScreen(int eraseOption) throws IOException {
getConsoleInfo();
IntByReference written = new IntByReference();
Expand Down Expand Up @@ -242,43 +243,56 @@ protected void processCursorToColumn(int x) throws IOException {
applyCursorPosition();
}

protected void processSetForegroundColor(int color, boolean bright) throws IOException {
info.wAttributes = (short)((info.wAttributes & ~0x0007 ) | ANSI_FOREGROUND_COLOR_MAP[color]);
info.wAttributes = (short) ((info.wAttributes & ~FOREGROUND_INTENSITY) | (bright ? FOREGROUND_INTENSITY : 0));
@Override
protected void processSetForegroundColorExt(int paletteIndex) throws IOException {
int color = Colors.roundColor(paletteIndex, 16);
info.wAttributes = (short) ((info.wAttributes & ~0x0007) | ANSI_FOREGROUND_COLOR_MAP[color & 0x07]);
info.wAttributes = (short) ((info.wAttributes & ~FOREGROUND_INTENSITY) | (color > 8 ? FOREGROUND_INTENSITY : 0));
applyAttribute();
}

protected void processSetBackgroundColor(int color, boolean bright) throws IOException {
protected void processSetBackgroundColorExt(int paletteIndex) throws IOException {
int color = Colors.roundColor(paletteIndex, 16);
info.wAttributes = (short)((info.wAttributes & ~0x0070 ) | ANSI_BACKGROUND_COLOR_MAP[color]);
info.wAttributes = (short) ((info.wAttributes & ~BACKGROUND_INTENSITY) | (bright ? BACKGROUND_INTENSITY : 0));
info.wAttributes = (short) ((info.wAttributes & ~BACKGROUND_INTENSITY) | (color > 8 ? BACKGROUND_INTENSITY : 0));
applyAttribute();
}

protected void processDefaultTextColor() throws IOException {
info.wAttributes = (short)((info.wAttributes & ~0x000F ) | (originalColors & 0x000F));
applyAttribute();
}

protected void processDefaultBackgroundColor() throws IOException {
info.wAttributes = (short)((info.wAttributes & ~0x00F0 ) | (originalColors & 0x00F0));
applyAttribute();
}

protected void processAttributeRest() throws IOException {
info.wAttributes = (short)((info.wAttributes & ~0x00FF ) | originalColors);
this.negative = false;
this.bold = false;
this.underline = false;
applyAttribute();
}

protected void processSetAttribute(int attribute) throws IOException {
switch(attribute) {
case ATTRIBUTE_INTENSITY_BOLD:
info.wAttributes = (short)(info.wAttributes | FOREGROUND_INTENSITY );
bold = true;
applyAttribute();
break;
case ATTRIBUTE_INTENSITY_NORMAL:
info.wAttributes = (short)(info.wAttributes & ~FOREGROUND_INTENSITY );
bold = false;
applyAttribute();
break;

// Yeah, setting the background intensity is not underlining.. but it's best we can do
// using the Windows console API
case ATTRIBUTE_UNDERLINE:
info.wAttributes = (short)(info.wAttributes | BACKGROUND_INTENSITY );
underline = true;
applyAttribute();
break;
case ATTRIBUTE_UNDERLINE_OFF:
info.wAttributes = (short)(info.wAttributes & ~BACKGROUND_INTENSITY );
underline = false;
applyAttribute();
break;

Expand Down
4 changes: 4 additions & 0 deletions terminal/src/main/java/org/jline/utils/AnsiWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ protected void processSetForegroundColor(int color) throws IOException {
* @throws IOException
*/
protected void processSetForegroundColor(int color, boolean bright) throws IOException {
processSetForegroundColorExt(bright ? color + 8 : color);
}

/**
Expand All @@ -588,6 +589,7 @@ protected void processSetForegroundColorExt(int paletteIndex) throws IOException
* @throws IOException
*/
protected void processSetForegroundColorExt(int r, int g, int b) throws IOException {
processSetForegroundColorExt(Colors.roundRgbColor(r, g, b, 16));
}

/**
Expand All @@ -607,6 +609,7 @@ protected void processSetBackgroundColor(int color) throws IOException {
* @throws IOException
*/
protected void processSetBackgroundColor(int color, boolean bright) throws IOException {
processSetBackgroundColorExt(bright ? color + 8 : color);
}

/**
Expand All @@ -627,6 +630,7 @@ protected void processSetBackgroundColorExt(int paletteIndex) throws IOException
* @throws IOException
*/
protected void processSetBackgroundColorExt(int r, int g, int b) throws IOException {
processSetBackgroundColorExt(Colors.roundRgbColor(r, g, b, 16));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,12 @@ public String toAnsi(Terminal terminal) {
int rounded = roundColor(fg, colors);
if (rounded < 8) {
first = attr(sb, "3" + Integer.toString(rounded), first);
// small hack to force setting bold again after a foreground color change
d |= (s & F_BOLD);
} else if (rounded < 16) {
first = attr(sb, "9" + Integer.toString(rounded - 8), first);
// small hack to force setting bold again after a foreground color change
d |= (s & F_BOLD);
} else {
first = attr(sb, "38;5;" + Integer.toString(rounded), first);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ public void testBold() throws IOException {
new ByteArrayOutputStream(),
StandardCharsets.UTF_8);

assertEquals("\33[34;47;1mblue on white\33[31;42;1mred on green\33[0m", AttributedString.fromAnsi("\33[34m\33[47m\33[1mblue on white\33[0m\33[31m\33[42m\33[1mred on green\33[0m").toAnsi(terminal));

assertEquals("\33[32;1mtest\33[0m", AttributedString.fromAnsi("\33[32m\33[1mtest\33[0m").toAnsi(terminal));
assertEquals("\33[32;1mtest\33[0m", AttributedString.fromAnsi("\33[1m\33[32mtest\33[0m").toAnsi(terminal));

}

}

0 comments on commit 0bff330

Please sign in to comment.