Skip to content

Commit 2034c38

Browse files
committed
fix #36: Stream outputs don't show backspace characters sometimes
1 parent 6856e08 commit 2034c38

File tree

2 files changed

+56
-4
lines changed

2 files changed

+56
-4
lines changed

__tests__/index.spec.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,43 @@ describe("Ansi", () => {
6464
expect(el.text()).toBe("that sentence\nwill make you pause");
6565
});
6666

67+
test("can handle backspace symbol", () => {
68+
const el = shallow(
69+
React.createElement(
70+
Ansi,
71+
null,
72+
"01hello\b goodbye"
73+
)
74+
);
75+
expect(el).not.toBeNull();
76+
expect(el.text()).toBe("01hell goodbye");
77+
});
78+
79+
// see https://stackoverflow.com/questions/55440152/multiple-b-doesnt-work-as-expected-in-jupyter#
80+
test("handles backspace symbol in same funny way as Jupyter Classic -- 1/2", () => {
81+
const el = shallow(
82+
React.createElement(
83+
Ansi,
84+
null,
85+
"02hello\b\b goodbye"
86+
)
87+
);
88+
expect(el).not.toBeNull();
89+
expect(el.text()).toBe("02hel goodbye");
90+
});
91+
92+
test("handles backspace symbol in same funny way as Jupyter Classic -- 2/2", () => {
93+
const el = shallow(
94+
React.createElement(
95+
Ansi,
96+
null,
97+
"03hello\b\b\b goodbye"
98+
)
99+
);
100+
expect(el).not.toBeNull();
101+
expect(el.text()).toBe("03hell goodbye");
102+
});
103+
67104
test("can linkify", () => {
68105
const el = shallow(
69106
React.createElement(

src/index.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ function ansiToJSON(
1515
input: string,
1616
use_classes: boolean = false
1717
): AnserJsonEntry[] {
18-
input = escapeCarriageReturn(input);
18+
input = escapeCarriageReturn(fixBackspace(input));
1919
return Anser.ansiToJson(input, {
2020
json: true,
2121
remove_empty: true,
22-
use_classes
22+
use_classes,
2323
});
2424
}
2525

@@ -106,7 +106,7 @@ function convertBundleIntoReact(
106106
let index = 0;
107107
let match: RegExpExecArray | null;
108108
while ((match = linkRegex.exec(bundle.content)) !== null) {
109-
const [ , pre, url ] = match;
109+
const [, pre, url] = match;
110110

111111
const startIndex = match.index + pre.length;
112112
if (startIndex > index) {
@@ -122,7 +122,7 @@ function convertBundleIntoReact(
122122
{
123123
key: index,
124124
href,
125-
target: "_blank"
125+
target: "_blank",
126126
},
127127
`${url}`
128128
)
@@ -155,3 +155,18 @@ export default function Ansi(props: Props): JSX.Element {
155155
)
156156
);
157157
}
158+
159+
// This is copied from the Jupyter Classic source code
160+
// notebook/static/base/js/utils.js to handle \b in a way
161+
// that is **compatible with Jupyter classic**. One can
162+
// argue that this behavior is questionable:
163+
// https://stackoverflow.com/questions/55440152/multiple-b-doesnt-work-as-expected-in-jupyter#
164+
function fixBackspace(txt: string) {
165+
let tmp = txt;
166+
do {
167+
txt = tmp;
168+
// Cancel out anything-but-newline followed by backspace
169+
tmp = txt.replace(/[^\n]\x08/gm, "");
170+
} while (tmp.length < txt.length);
171+
return txt;
172+
}

0 commit comments

Comments
 (0)