Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
breaking(ansi): re-write ansi_escape module and rename to ansi (#124)
- Loading branch information
Showing
25 changed files
with
883 additions
and
567 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
<h1 align="center">Cliffy ❯ Ansi</h1> | ||
|
||
<p align="center" class="badges-container"> | ||
<a href="https://github.com/c4spar/deno-cliffy/actions?query=workflow%3ATest"> | ||
<img alt="Build status" src="https://github.com/c4spar/deno-cliffy/workflows/Test/badge.svg?branch=master" /> | ||
</a> | ||
<a href="https://github.com/c4spar/deno-cliffy/releases"> | ||
<img alt="Version" src="https://img.shields.io/github/v/release/c4spar/deno-cliffy?logo=github&color=blue&label=latest" /> | ||
</a> | ||
<a href="https://github.com/c4spar/deno-cliffy/labels/module%3Aansi-escape"> | ||
<img alt="issues" src="https://img.shields.io/github/issues/c4spar/deno-cliffy/module:ansi-escape?label=issues&logo=github&color=yellow"> | ||
</a> | ||
<a href="https://deno.land/"> | ||
<img alt="Deno version" src="https://img.shields.io/badge/deno-^1.2.0-blue?logo=deno" /> | ||
</a> | ||
<a href="https://doc.deno.land/https/deno.land/x/cliffy/ansi/mod.ts"> | ||
<img alt="doc" src="https://img.shields.io/badge/deno-doc-yellow?logo=deno" /> | ||
</a> | ||
<a href="https://github.com/c4spar/deno-cliffy/blob/master/LICENSE"> | ||
<img alt="Licence" src="https://img.shields.io/github/license/c4spar/deno-cliffy?logo=github" /> | ||
</a> | ||
<a href="https://nest.land/package/cliffy"> | ||
<img src="https://nest.land/badge.svg" alt="nest.land badge"> | ||
</a> | ||
</p> | ||
|
||
<p align="center"> | ||
<b>Ansi escape sequences for Deno.</b><br> | ||
<sub>>_ Control cli cursor, erase output, scroll window and more.</sub> | ||
</p> | ||
|
||
## ❯ Content | ||
|
||
- [Install](#-install) | ||
- [Usage](#-usage) | ||
- [Tty](#tty) | ||
- [Ansi](#ansi) | ||
- [Functional](#functional) | ||
- [Contributing](#-contributing) | ||
- [License](#-license) | ||
|
||
## ❯ Install | ||
|
||
This module can be imported directly from the repo and from following registries. | ||
|
||
Deno Registry | ||
|
||
```typescript | ||
import { ansi, tty, cursorTo } from "https://deno.land/x/cliffy@<version>/ansi/mod.ts"; | ||
``` | ||
|
||
Nest Registry | ||
|
||
```typescript | ||
import { ansi, tty, cursorTo } from "https://x.nest.land/cliffy@<version>/ansi/mod.ts"; | ||
``` | ||
|
||
Github | ||
|
||
```typescript | ||
import { ansi, tty, cursorTo } from "https://raw.githubusercontent.com/c4spar/deno-cliffy/<version>/ansi/mod.ts"; | ||
``` | ||
|
||
## ❯ Usage | ||
|
||
The ansi module exports an `ansi` and a `tty` object which have chainable methods and properties for generating and writing ansi escape sequences. `ansi` and `tty` have allmost the same properties and methods.`ansi` generates and returns an ansi string, and `tty` writes the generated ansi escape sequence directly to stdout. | ||
|
||
Both objects can be also invoked as method to create a new instance from itself. | ||
|
||
### Tty | ||
|
||
Writes generated ansi escape sequences directly to stdout. | ||
|
||
```typescript | ||
import { tty } from "https://deno.land/x/cliffy/ansi/tty.ts"; | ||
|
||
tty.cursorSave | ||
.cursorHide | ||
.cursorTo(0, 0) | ||
.eraseScreen(); | ||
``` | ||
|
||
Create a new instance. | ||
|
||
```typescript | ||
import { tty } from "https://deno.land/x/cliffy/ansi/tty.ts"; | ||
|
||
const myTty = tty({ | ||
stdout: Deno.stdout, | ||
stdin: Deno.stdin | ||
}); | ||
|
||
myTty.cursorSave | ||
.cursorHide | ||
.cursorTo(0, 0) | ||
.eraseScreen(); | ||
``` | ||
|
||
### Ansi | ||
|
||
Returns generated ansi escape sequences. | ||
|
||
```typescript | ||
import { ansi } from "https://deno.land/x/cliffy/ansi/ansi.ts"; | ||
|
||
console.log( | ||
myAnsi.cursorUp.cursorLeft.eraseDown() | ||
); | ||
|
||
// or: | ||
Deno.stdout.writeSync( | ||
new TextEncoder().encode( | ||
ansi.cursorUp.cursorLeft.eraseDown() | ||
) | ||
); | ||
|
||
// or: | ||
Deno.stdout.writeSync( | ||
ansi.cursorUp.cursorLeft.eraseDown.toBuffer() | ||
); | ||
``` | ||
|
||
Create a new instance. | ||
|
||
```typescript | ||
import { ansi } from "https://deno.land/x/cliffy/ansi/ansi.ts"; | ||
|
||
const myAnsi = ansi(); | ||
|
||
console.log( | ||
myAnsi.cursorUp.cursorLeft.eraseDown() | ||
); | ||
``` | ||
|
||
### Functional | ||
|
||
```typescript | ||
import { cursorTo, eraseDown, image, link } from "https://deno.land/x/cliffy/ansi/ansi_escapes.ts"; | ||
|
||
const response = await fetch("https://deno.land/images/hashrock_simple.png"); | ||
const imageBuffer: ArrayBuffer = await response.arrayBuffer(); | ||
|
||
console.log( | ||
cursorTo(0, 0) + | ||
eraseDown() + | ||
image(imageBuffer, { | ||
width: 29, | ||
preserveAspectRatio: true, | ||
}) + | ||
"\n " + | ||
link("Deno Land", "https://deno.land") + | ||
"\n", | ||
); | ||
``` | ||
|
||
## ❯ Contributing | ||
|
||
Any kind of contribution is welcome! Please take a look at the [contributing guidelines](../CONTRIBUTING.md). | ||
|
||
## ❯ License | ||
|
||
[MIT](../LICENSE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import * as ansiEscapes from "./ansi_escapes.ts"; | ||
import { Chain } from "./chain.ts"; | ||
|
||
type Args = Array<unknown>; | ||
type Executor = (this: AnsiChain, ...args: Args) => string; | ||
type Property = string | Executor; | ||
type PropertyNames = keyof Chain<AnsiChain>; | ||
|
||
/** Ansi instance returned by all ansi escape properties. */ | ||
export interface AnsiChain extends Chain<AnsiChain> { | ||
/** Get ansi escape sequence. */ | ||
(): string; | ||
/** Get ansi escape sequence. */ | ||
toString(): string; | ||
/** Get ansi escape sequence as Uint8Array. */ | ||
toBuffer(): Uint8Array; | ||
} | ||
|
||
/** Create new `Ansi` instance. */ | ||
export type AnsiFactory = () => Ansi; | ||
|
||
/** | ||
* Chainable ansi escape sequence's. | ||
* If invoked as method, a new Ansi instance will be returned. | ||
*/ | ||
export type Ansi = AnsiFactory & AnsiChain; | ||
|
||
/** | ||
* Chainable ansi escape sequence's. | ||
* If invoked as method, a new Ansi instance will be returned. | ||
* ``` | ||
* await Deno.stdout.write( | ||
* new TextEncoder().encode( | ||
* ansi.cursorTo(0, 0).eraseScreen(), | ||
* ), | ||
* ); | ||
* ``` | ||
* Or shorter: | ||
* ``` | ||
* await Deno.stdout.write( | ||
* ansi.cursorTo(0, 0).eraseScreen.toBuffer(), | ||
* ); | ||
* ``` | ||
*/ | ||
export const ansi: Ansi = factory(); | ||
|
||
function factory(): Ansi { | ||
let result: Array<string> = []; | ||
let stack: Array<[Property, Args]> = []; | ||
|
||
const ansi: Ansi = function ( | ||
this: AnsiChain | undefined, | ||
...args: Args | ||
): string | AnsiChain { | ||
if (this) { | ||
if (args.length) { | ||
update(args); | ||
return this; | ||
} | ||
return this.toString(); | ||
} | ||
return factory(); | ||
} as Ansi; | ||
|
||
ansi.text = function (text: string): AnsiChain { | ||
stack.push([text, []]); | ||
return this; | ||
}; | ||
|
||
ansi.toString = function (): string { | ||
update(); | ||
const str: string = result.join(); | ||
result = []; | ||
return str; | ||
}; | ||
|
||
ansi.toBuffer = function (): Uint8Array { | ||
return new TextEncoder().encode(this.toString()); | ||
}; | ||
|
||
const methodList: Array<[PropertyNames, Property]> = Object.entries( | ||
ansiEscapes, | ||
) as Array<[PropertyNames, Property]>; | ||
|
||
for (const [name, method] of methodList) { | ||
Object.defineProperty(ansi, name, { | ||
get(this: AnsiChain) { | ||
stack.push([method, []]); | ||
return this; | ||
}, | ||
}); | ||
} | ||
|
||
return ansi; | ||
|
||
function update(args?: Args) { | ||
if (!stack.length) { | ||
return; | ||
} | ||
if (args) { | ||
stack[stack.length - 1][1] = args; | ||
} | ||
result.push( | ||
...stack.map(([prop, args]: [Property, Args]) => | ||
typeof prop === "string" ? prop : prop.call(ansi, ...args) | ||
), | ||
); | ||
stack = []; | ||
} | ||
} |
Oops, something went wrong.