Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions twinkle-ansi/src/main/java/org/codejive/twinkle/ansi/Ansi.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ public class Ansi {
public static final int COLORS_RGB = 2;
public static final int COLORS_INDEXED = 5;

// OSC 8 hyperlinks (BEL-terminated)
Copy link
Author

Choose a reason for hiding this comment

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

links are useful and osc-8 are commonly supported so i assume makes sense to add here?

public static String osc8Open(String url) {
return "\u001B]8;;" + url + "\u0007";
}

public static String osc8Close() {
return "\u001B]8;;\u0007";
}

public static String style(Object... styles) {
if (styles == null || styles.length == 0) {
return "";
Expand Down Expand Up @@ -100,19 +109,23 @@ public static String backgroundBright(int index) {
}

public static String foregroundIndexed(int index) {
return FOREGROUND_COLORS + ":" + COLORS_INDEXED + ":" + index;
// Standard SGR: 38;5;<n>
Copy link
Author

Choose a reason for hiding this comment

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

not sure who is right here - it does not seem to matter but online i find ; being used not : - which one is correct/expected?

return FOREGROUND_COLORS + ";" + COLORS_INDEXED + ";" + index;
}

public static String foregroundRgb(int r, int g, int b) {
return FOREGROUND_COLORS + ":" + COLORS_RGB + ":" + r + ":" + g + ":" + b;
// Standard SGR truecolor: 38;2;<r>;<g>;<b>
return FOREGROUND_COLORS + ";" + COLORS_RGB + ";" + r + ";" + g + ";" + b;
}

public static String backgroundIndexed(int index) {
return BACKGROUND_COLORS + ":" + COLORS_INDEXED + ":" + index;
// Standard SGR: 48;5;<n>
return BACKGROUND_COLORS + ";" + COLORS_INDEXED + ";" + index;
}

public static String backgroundRgb(int r, int g, int b) {
return BACKGROUND_COLORS + ":" + COLORS_RGB + ":" + r + ":" + g + ":" + b;
// Standard SGR truecolor: 48;2;<r>;<g>;<b>
return BACKGROUND_COLORS + ";" + COLORS_RGB + ";" + r + ";" + g + ";" + b;
}

private Ansi() {}
Expand Down
18 changes: 16 additions & 2 deletions twinkle-ansi/src/main/java/org/codejive/twinkle/ansi/Style.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.ArrayList;
import java.util.List;

import org.jspecify.annotations.NonNull;

public class Style {
Expand Down Expand Up @@ -421,11 +422,24 @@ public StringBuilder toAnsiString(StringBuilder sb, long currentStyleState) {
}
}
if ((currentStyleState & MASK_FG_COLOR) != (state & MASK_FG_COLOR)) {
styles.add(fgColor().toAnsiFg());
styles.add(extractSgrParams(fgColor().toAnsiFg()));
Copy link
Author

Choose a reason for hiding this comment

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

this extact call is super inefficient - but afacs its done to avoid getting style start ansi code added constantly so it strips it and leave just the style code?

}
if ((currentStyleState & MASK_BG_COLOR) != (state & MASK_BG_COLOR)) {
styles.add(bgColor().toAnsiBg());
styles.add(extractSgrParams(bgColor().toAnsiBg()));
}
return Ansi.style(sb, styles.toArray());
}

/**
* Converts a full SGR ANSI escape sequence (e.g. {@code ESC[38;2;255;0;0m}) into just the
* contained SGR parameters (e.g. {@code "38;2;255;0;0"}), so it can be safely embedded into
* another {@code ESC[...m} sequence without producing broken output.
*/
private static String extractSgrParams(String ansi) {
if (ansi == null || ansi.isEmpty()) return "";
if (ansi.startsWith(Ansi.CSI) && ansi.endsWith("m")) {
return ansi.substring(Ansi.CSI.length(), ansi.length() - 1);
}
return ansi;
}
}
Loading