Skip to content

Commit 7d4e0d3

Browse files
committed
fix(cursor): Change cursor to a class for better chaining
1 parent 874d6e9 commit 7d4e0d3

File tree

3 files changed

+124
-80
lines changed

3 files changed

+124
-80
lines changed

bun.lockb

0 Bytes
Binary file not shown.

src/_types.d.ts

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -182,34 +182,38 @@ export declare const cursorCodes: {
182182
/**
183183
* Moving the cursor around the terminal. Needs testing on Windows.
184184
*/
185-
export declare const cursor: {
186-
write: (s: string) => any;
187-
up: (count?: number) => any;
188-
down: (count?: number) => any;
189-
forward: (count?: number) => any;
190-
back: (count?: number) => any;
191-
moveDown: (count?: number) => any;
192-
moveUp: (count?: number) => any;
193-
backToStart: () => any;
194-
horizontalAbsolute: (count?: number) => any;
195-
eraseBefore: (count?: number) => any;
196-
eraseLine: () => any;
197-
erase: (count?: number) => any;
198-
clearScreen: () => any;
199-
scrollUp: (count?: number) => any;
200-
scrollDown: (count?: number) => any;
201-
goto: (pos: CursorPos) => any;
202-
savePosition: () => any;
203-
restorePosition: () => any;
204-
hide: () => any;
205-
show: () => any;
206-
backspace: (count?: number) => any;
207-
alternate: (enabled: boolean) => any;
208-
queryPosition: typeof queryPosition;
209-
bookmark: (name: string, pos?: CursorPos) => Promise<CursorPos>;
210-
getBookmark: (name: string) => CursorPos;
211-
jump: (name: string) => any;
212-
};
185+
export declare class Cursor {
186+
bookmarks: {
187+
[key: string]: CursorPos;
188+
};
189+
c(s: string, esc?: string): this;
190+
write(s: string): this;
191+
up(count?: number): this;
192+
down(count?: number): this;
193+
forward(count?: number): this;
194+
back(count?: number): this;
195+
moveDown(count?: number): this;
196+
moveUp(count?: number): this;
197+
backToStart(): this;
198+
horizontalAbsolute(count?: number): this;
199+
eraseBefore(count?: number): this;
200+
eraseLine(): this;
201+
erase(count?: number): this;
202+
clearScreen(): this;
203+
scrollUp(count?: number): this;
204+
scrollDown(count?: number): this;
205+
goto(pos: CursorPos): this;
206+
savePosition(): this;
207+
restorePosition(): this;
208+
hide(): this;
209+
show(): this;
210+
backspace(count?: number): this;
211+
alternate(enabled: boolean): this;
212+
queryPosition(): Promise<CursorPos>;
213+
bookmark(name: string, pos?: CursorPos): Promise<CursorPos>;
214+
jump(name: string): this;
215+
}
216+
export declare const cursor: Cursor;
213217
export declare function queryPosition(): Promise<CursorPos>;
214218
/**
215219
* Start a spinner. Returns a Timer object that can be used to stop the spinner.

src/cursor.ts

Lines changed: 92 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -34,70 +34,110 @@ export const cursorCodes = {
3434
show: "?25h",
3535
} as const
3636

37-
/**
38-
* For storing bookmarks
39-
*/
40-
const positions: { [key: string]: CursorPos } = {}
41-
42-
/**
43-
* For chaining cursor methods.
44-
*/
45-
const c = (s: string, esc: string = ESC) => {
46-
write(esc + s)
47-
return cursor
48-
}
49-
5037
/**
5138
* Moving the cursor around the terminal. Needs testing on Windows.
5239
*/
53-
export const cursor = {
54-
write: (s: string) => c(s, ""),
55-
up: (count: number = 1) => c(`${count}${cursorCodes.up}`),
56-
down: (count: number = 1) => c(`${count}${cursorCodes.down}`),
57-
forward: (count: number = 1) => c(`${count}${cursorCodes.forward}`),
58-
back: (count: number = 1) => c(`${count}${cursorCodes.back}`),
59-
moveDown: (count: number = 1) => c(`${count}${cursorCodes.nextLine}`),
60-
moveUp: (count: number = 1) => c(`${count}${cursorCodes.previousLine}`),
61-
backToStart: () => c(`${cursorCodes.horizontalAbsolute}`),
62-
horizontalAbsolute: (count = 1) => c(`${count}${cursorCodes.horizontalAbsolute}`),
63-
eraseBefore: (count = 1) => c(`${count}${cursorCodes.eraseData}`),
64-
eraseLine: () => c(`${cursorCodes.eraseLine}`),
65-
erase: (count = 1) => c(`${count}${cursorCodes.eraseCharacter}`),
66-
clearScreen: () => c(`${cursorCodes.clearScreen}`),
67-
scrollUp: (count = 1) => c(`${count}${cursorCodes.scrollUp}`),
68-
scrollDown: (count = 1) => c(`${count}${cursorCodes.scrollDown}`),
69-
goto: (pos: CursorPos) => c(cursorCodes.goToPosition(pos.cols, pos.rows), ""),
40+
export class Cursor {
41+
bookmarks: { [key: string]: CursorPos } = {}
42+
43+
// for chaining easily
44+
c(s: string, esc: string = ESC) {
45+
write(esc + s)
46+
return this
47+
}
48+
49+
write(s: string) {
50+
return this.c(s, "")
51+
}
52+
up(count: number = 1) {
53+
return this.c(`${count}${cursorCodes.up}`)
54+
}
55+
down(count: number = 1) {
56+
return this.c(`${count}${cursorCodes.down}`)
57+
}
58+
forward(count: number = 1) {
59+
return this.c(`${count}${cursorCodes.forward}`)
60+
}
61+
back(count: number = 1) {
62+
return this.c(`${count}${cursorCodes.back}`)
63+
}
64+
moveDown(count: number = 1) {
65+
return this.c(`${count}${cursorCodes.nextLine}`)
66+
}
67+
moveUp(count: number = 1) {
68+
return this.c(`${count}${cursorCodes.previousLine}`)
69+
}
70+
backToStart() {
71+
return this.c(`${cursorCodes.horizontalAbsolute}`)
72+
}
73+
horizontalAbsolute(count = 1) {
74+
return this.c(`${count}${cursorCodes.horizontalAbsolute}`)
75+
}
76+
eraseBefore(count = 1) {
77+
return this.c(`${count}${cursorCodes.eraseData}`)
78+
}
79+
eraseLine() {
80+
return this.c(`${cursorCodes.eraseLine}`)
81+
}
82+
erase(count = 1) {
83+
return this.c(`${count}${cursorCodes.eraseCharacter}`)
84+
}
85+
clearScreen() {
86+
return this.c(`${cursorCodes.clearScreen}`)
87+
}
88+
scrollUp(count = 1) {
89+
return this.c(`${count}${cursorCodes.scrollUp}`)
90+
}
91+
scrollDown(count = 1) {
92+
return this.c(`${count}${cursorCodes.scrollDown}`)
93+
}
94+
goto(pos: CursorPos) {
95+
return this.c(cursorCodes.goToPosition(pos.cols, pos.rows), "")
96+
}
7097

7198
// basic save & restore position
72-
savePosition: () => c(`${cursorCodes.savePosition}`, ""),
73-
restorePosition: () => c(`${cursorCodes.restorePosition}`, ""),
74-
75-
hide: () => c(`${cursorCodes.hide}`),
76-
show: () => c(`${cursorCodes.show}`),
77-
78-
backspace: (count = 1) => cursor.back(count).erase(count),
79-
80-
alternate: (enabled: boolean) =>
81-
c(`${enabled ? cursorCodes.enterAlternativeScreen : cursorCodes.exitAlternativeScreen}`),
82-
83-
// advanced save & restore positions -- these can't be chained
84-
queryPosition,
85-
bookmark: async (name: string, pos?: CursorPos) => {
99+
savePosition() {
100+
return this.c(`${cursorCodes.savePosition}`, "")
101+
}
102+
restorePosition() {
103+
return this.c(`${cursorCodes.restorePosition}`, "")
104+
}
105+
106+
hide() {
107+
return this.c(`${cursorCodes.hide}`)
108+
}
109+
show() {
110+
return this.c(`${cursorCodes.show}`)
111+
}
112+
113+
backspace(count = 1) {
114+
return this.back(count).erase(count)
115+
}
116+
117+
alternate(enabled: boolean) {
118+
return this.c(`${enabled ? cursorCodes.enterAlternativeScreen : cursorCodes.exitAlternativeScreen}`)
119+
}
120+
121+
// advanced save & restore bookmarks -- these can't be chained
122+
queryPosition() {
123+
return queryPosition()
124+
}
125+
async bookmark(name: string, pos?: CursorPos) {
86126
const cpos = pos || (await queryPosition())
87-
positions[name] = cpos
127+
this.bookmarks[name] = cpos
88128
return cpos
89-
},
90-
getBookmark: (name: string) => positions[name],
129+
}
91130

92131
// can be chained, since we don't have to wait for the queryPosition
93-
jump: (name: string) => {
94-
const pos = positions[name]
132+
jump(name: string) {
133+
const pos = this.bookmarks[name]
95134
if (!pos) throw new Error(`No cursor bookmark found with name ${name}`)
96-
cursor.goto(pos)
97-
return cursor
98-
},
135+
return this.goto(pos)
136+
}
99137
}
100138

139+
export const cursor = new Cursor()
140+
101141
// this is how we use the ansi queryPosition escape code.
102142
// it returns the cursor position, which we can then parse
103143
// and use to position the cursor.

0 commit comments

Comments
 (0)