Skip to content

Instantly share code, notes, and snippets.

@kyldvs
Last active January 24, 2018 22:09
Show Gist options
  • Save kyldvs/24793e33e0d88f7396e50a6aedcbda87 to your computer and use it in GitHub Desktop.
Save kyldvs/24793e33e0d88f7396e50a6aedcbda87 to your computer and use it in GitHub Desktop.
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*/
/* Uses Ansi.re from: https://gist.github.com/kyldvs/63430656217a39b0143d01704ccf6b5f */
module IntMap =
Map.Make(
{
type t = int;
let compare = compare;
}
);
module IntSet =
Set.Make(
{
type t = int;
let compare = compare;
}
);
type chalker = string => string;
type part = {
value: string,
isModifier: bool,
modifiers: IntSet.t
};
let escapeCodeRegex = {
let start = "\027\\[";
let codesStart = "\\(";
let codesList = IntSet.elements(Ansi.starts) @ IntSet.elements(Ansi.stops);
let codesMiddle =
List.fold_left(
(s, code) => s ++ "\\|" ++ string_of_int(code),
string_of_int(List.hd(codesList)),
List.tl(codesList)
);
let codesStop = "\\)";
let stop = "m";
let regexString = start ++ codesStart ++ codesMiddle ++ codesStop ++ stop;
Str.regexp(regexString);
};
let nonDigitRegex = Str.regexp("[^0-9]");
let parseString = (s: string) : list(part) => {
let parts = Str.full_split(escapeCodeRegex, s);
let (parts, _) =
parts
|> List.fold_left(
((result, modifiers), part) =>
switch part {
| Str.Text(value) => (
result @ [{value, modifiers, isModifier: false}],
modifiers
)
| Str.Delim(value) =>
let codeString = Str.global_replace(nonDigitRegex, "", value);
let code = int_of_string(codeString);
let modifiers =
if (IntSet.mem(code, Ansi.starts)) {
IntSet.add(code, modifiers);
} else if (IntSet.mem(code, Ansi.stops)) {
let startsToRemove = IntMap.find(code, Ansi.stopToStarts);
IntSet.filter(
code => ! IntSet.mem(code, startsToRemove),
modifiers
);
} else {
failwith(
"Unknown escape code matched escapeCodeRegex: "
++ codeString
);
};
(result @ [{value, modifiers, isModifier: true}], modifiers);
},
([], IntSet.empty)
);
parts;
};
let createChalker = (style: Ansi.style) : chalker => {
let chalker = (s: string) => {
let parts = parseString(s);
/* Now we apply the style to all parts with non-conflicting modifiers */
List.fold_left(
(result, part) =>
if (part.isModifier) {
result ++ part.value;
} else {
let myStopCode = style.stopCode;
let conflictingStarts = IntMap.find(myStopCode, Ansi.stopToStarts);
let next =
if (IntSet.exists(
code => IntSet.mem(code, conflictingStarts),
part.modifiers
)) {
part.value;
} else {
style.start ++ part.value ++ style.stop;
};
result ++ next;
},
"",
parts
);
};
chalker;
};
type modifier = {
bold: chalker,
dim: chalker,
italic: chalker,
underline: chalker,
inverse: chalker,
hidden: chalker,
strikethrough: chalker
};
type color = {
black: chalker,
red: chalker,
green: chalker,
yellow: chalker,
blue: chalker,
magenta: chalker,
cyan: chalker,
white: chalker,
gray: chalker,
grey: chalker,
redBright: chalker,
greenBright: chalker,
yellowBright: chalker,
blueBright: chalker,
magentaBright: chalker,
cyanBright: chalker,
whiteBright: chalker
};
type bg = {
black: chalker,
red: chalker,
green: chalker,
yellow: chalker,
blue: chalker,
magenta: chalker,
cyan: chalker,
white: chalker,
blackBright: chalker,
redBright: chalker,
greenBright: chalker,
yellowBright: chalker,
blueBright: chalker,
magentaBright: chalker,
cyanBright: chalker,
whiteBright: chalker
};
let modifier: modifier = {
bold: createChalker(Ansi.modifier.bold),
dim: createChalker(Ansi.modifier.dim),
italic: createChalker(Ansi.modifier.italic),
underline: createChalker(Ansi.modifier.underline),
inverse: createChalker(Ansi.modifier.inverse),
hidden: createChalker(Ansi.modifier.hidden),
strikethrough: createChalker(Ansi.modifier.strikethrough)
};
let bold = modifier.bold;
let dim = modifier.dim;
let italic = modifier.italic;
let underline = modifier.underline;
let inverse = modifier.inverse;
let hidden = modifier.hidden;
let strikethrough = modifier.strikethrough;
let color: color = {
black: createChalker(Ansi.color.black),
red: createChalker(Ansi.color.red),
green: createChalker(Ansi.color.green),
yellow: createChalker(Ansi.color.yellow),
blue: createChalker(Ansi.color.blue),
magenta: createChalker(Ansi.color.magenta),
cyan: createChalker(Ansi.color.cyan),
white: createChalker(Ansi.color.white),
gray: createChalker(Ansi.color.gray),
grey: createChalker(Ansi.color.grey),
redBright: createChalker(Ansi.color.redBright),
greenBright: createChalker(Ansi.color.greenBright),
yellowBright: createChalker(Ansi.color.yellowBright),
blueBright: createChalker(Ansi.color.blueBright),
magentaBright: createChalker(Ansi.color.magentaBright),
cyanBright: createChalker(Ansi.color.cyanBright),
whiteBright: createChalker(Ansi.color.whiteBright)
};
let black = color.black;
let red = color.red;
let green = color.green;
let yellow = color.yellow;
let blue = color.blue;
let magenta = color.magenta;
let cyan = color.cyan;
let white = color.white;
let gray = color.gray;
let grey = color.grey;
let redBright = color.redBright;
let greenBright = color.greenBright;
let yellowBright = color.yellowBright;
let blueBright = color.blueBright;
let magentaBright = color.magentaBright;
let cyanBright = color.cyanBright;
let whiteBright = color.whiteBright;
let bg: bg = {
black: createChalker(Ansi.bg.black),
red: createChalker(Ansi.bg.red),
green: createChalker(Ansi.bg.green),
yellow: createChalker(Ansi.bg.yellow),
blue: createChalker(Ansi.bg.blue),
magenta: createChalker(Ansi.bg.magenta),
cyan: createChalker(Ansi.bg.cyan),
white: createChalker(Ansi.bg.white),
blackBright: createChalker(Ansi.bg.blackBright),
redBright: createChalker(Ansi.bg.redBright),
greenBright: createChalker(Ansi.bg.greenBright),
yellowBright: createChalker(Ansi.bg.yellowBright),
blueBright: createChalker(Ansi.bg.blueBright),
magentaBright: createChalker(Ansi.bg.magentaBright),
cyanBright: createChalker(Ansi.bg.cyanBright),
whiteBright: createChalker(Ansi.bg.whiteBright)
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment