Skip to content

Commit

Permalink
fix(cursor): Fixes cursor save/get position/bookmarking
Browse files Browse the repository at this point in the history
  • Loading branch information
jamonholmgren committed Oct 12, 2023
1 parent 1bb6762 commit 7deadea
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 29 deletions.
2 changes: 2 additions & 0 deletions cli/commands/bluebun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ export default {
)
print(``)
print(await commandHelp(props))

console.log(props.arguments)
},
}
38 changes: 38 additions & 0 deletions cli/commands/demo/cursor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { cursor, inputKey, print, type Props } from "bluebun"

export default {
name: "cursor",
description: "Tests cursor movement and bookmarking.",
run: async (props: Props) => {
print(``)
print(`Testing cursor movement and bookmarking.`)
print(``)

while (true) {
const k = await inputKey()
if (k === "q") break
if (k === "ctrl-c") break
if (k === "esc") break
if (k === "up") cursor.up()
if (k === "down") cursor.down()
if (k === "left") cursor.back()
if (k === "right") cursor.forward()
if (k === "backspace") cursor.backspace()
if (k === "enter") cursor.moveDown()
// if alphabetical, write it
if (k.length === 1 && k.match(/[a-z]/i)) cursor.write(k)

// if it's a number, go to the bookmark
if (k.length === 1 && k.match(/[0-9]/)) {
// if it's already a bookmark, go to it
const pos = cursor.getBookmark(`bookmark-${k}`)
if (pos) {
cursor.goToPosition(pos.cols, pos.rows)
} else {
// save the position as a bookmark
await cursor.bookmark(`bookmark-${k}`)
}
}
}
},
}
11 changes: 11 additions & 0 deletions cli/commands/demo/demo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { cursor, inputKey, print, type Props } from "bluebun"

export default {
name: "demo",
description: "Lets you test various features of Bluebun.",
run: async (props: Props) => {
print(``)
print(`Try "bluebun demo cursor".`)
print(``)
},
}
52 changes: 25 additions & 27 deletions src/cursor.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { type ReadStream } from "tty"
import { type CursorPos } from "bluebun"
import { write } from "./print"

// ty https://github.com/sindresorhus/ansi-escapes/blob/main/index.js
const ESC = "\u001b["
// const ESC = "\x1b["
const ESC = "\u001B["
const isTerminalApp = process.env.TERM_PROGRAM === "Apple_Terminal"

/**
Expand Down Expand Up @@ -50,7 +50,7 @@ const c = (s: string, esc: string = ESC) => {
* Moving the cursor around the terminal. Needs testing on Windows.
*/
export const cursor = {
write: (s: string) => c(s),
write: (s: string) => c(s, ""),
up: (count: number = 1) => c(`${count}${cursorCodes.up}`),
down: (count: number = 1) => c(`${count}${cursorCodes.down}`),
forward: (count: number = 1) => c(`${count}${cursorCodes.forward}`),
Expand Down Expand Up @@ -97,33 +97,31 @@ export const cursor = {
// this is how we use the ansi queryPosition escape code.
// it returns the cursor position, which we can then parse
// and use to position the cursor.
let stream: ReadStream | undefined
// ty https://github.com/bubkoo/get-cursor-position/blob/master/index.js
export function queryPosition(): Promise<CursorPos> {
const code = "\u001B[6n"

return new Promise((resolve, reject) => {
const listener = (data: string) => {
const str = data.toString()
const match = str.match(/\d+/g)

process.stdin.setRawMode(false)
stream!.pause()

if (!match || match.length !== 2) {
reject(new Error("Could not get cursor position"))
} else {
const [rows, cols] = match.map((n) => parseInt(n, 10))
// Seems to resolve this issue: https://github.com/oven-sh/bun/issues/6279
setTimeout(() => resolve({ rows, cols }), 0)
process.stdin.resume()
process.stdin.setRawMode(true)

process.stdin.on("data", (data) => {
var match = /\[(\d+)\;(\d+)R$/.exec(data.toString())
if (match) {
var position = match.slice(1, 3).reverse().map(Number)

// cleanup and close stdin
process.stdin.setRawMode(false)
process.stdin.pause()

resolve({
rows: position[1],
cols: position[0],
})
}
}
})

process.stdin.setRawMode(true)
if (stream) {
// stream.resume()
stream.removeAllListeners("data")
stream.on("data", listener)
} else {
stream = process.stdin.on("data", listener)
}
process.stdout.write("\u001B[6n")
process.stdout.write(code)
process.stdout.emit("data", code)
})
}
4 changes: 2 additions & 2 deletions src/styles.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const ESC = "\u001B["

export const styleStart = (style: number) => `${ESC}${style}m`
export const styleEnd = (reset: number) => `${ESC}${reset}m`
export const styleStart = (style: number) => `${ESC}${style}`
export const styleEnd = (reset: number) => `${ESC}${reset}`

export const style = (style: number, reset: number) => (text: string) => {
return `${styleStart(style)}${text}${styleEnd(reset)}`
Expand Down

0 comments on commit 7deadea

Please sign in to comment.