diff --git a/src/app.ts b/src/app.ts index 2431b2164..75a2507c5 100644 --- a/src/app.ts +++ b/src/app.ts @@ -6,11 +6,12 @@ import parse_pkg_str from "./prefab/parse-pkg-str.ts" import InstallLogger from "./utils/InstallLogger.ts" import internal_use from "./modes/internal.use.ts" import { Args as BaseArgs } from "./parse-args.ts" -import Logger, { teal } from "./utils/Logger.ts" import integrate from "./modes/integrate.ts" import shellcode from "./modes/shellcode.ts" +import install from "./modes/install.ts" import version from "./modes/version.ts" -import install from './modes/install.ts' +import { teal } from "./utils/color.ts" +import Logger from "./utils/Logger.ts" import which from "./modes/which.ts" import help from "./modes/help.ts" import repl from "./modes/repl.ts" @@ -51,7 +52,6 @@ export default async function({ flags, ...opts }: Args, logger_prefix?: string) const rv = await internal_use({ ...xopts, logger }) if (rv) { console.log(rv.shellcode) - console.error('tea:', rv.pkgenv.map(x => `+${utils.pkg.str(x)}`).join(' ')) } } break case 'internal.activate': { diff --git a/src/modes/help.ts b/src/modes/help.ts index fba974ca5..f991270e4 100644 --- a/src/modes/help.ts +++ b/src/modes/help.ts @@ -1,5 +1,5 @@ +import { dim } from "../utils/color.ts" import undent from "outdent" -import { gray } from "../utils/Logger.ts" export default function(verbosity = 0) { @@ -18,7 +18,7 @@ export default function(verbosity = 0) { 10 more: $ tea --help --verbose $ open https://docs.tea.xyz - `.replaceAll('$', gray('$')).replaceAll(/#.*/g, gray) + `.replaceAll('$', dim('$')).replaceAll(/#.*/g, dim) } else { // 10| 20| 30| 40| 50| 60| 70| | 80| return undent` @@ -61,6 +61,6 @@ export default function(verbosity = 0) { environmental influencers: CI #defaults verbosity to -1 (--quiet) CLICOLOR #see https://bixense.com/clicolors - `.replaceAll(/#(.*)/g, (_,x) => gray(` ${x}`)) + `.replaceAll(/#(.*)/g, (_,x) => dim(` ${x}`)) } } diff --git a/src/modes/internal.activate.test.ts b/src/modes/internal.activate.test.ts index 65a401507..f50ed700b 100644 --- a/src/modes/internal.activate.test.ts +++ b/src/modes/internal.activate.test.ts @@ -1,4 +1,4 @@ -// deno-lint-ignore-file require-await +// deno-lint-ignore-file require-await no-explicit-any import { fixturesd, null_logger as logger } from "../utils/test-utils.ts" import { _internals as _devenv_internals } from "../utils/devenv.ts" import specimen0, { _internals } from "./internal.activate.ts" @@ -43,7 +43,7 @@ Deno.test("internal.activate.ts", async runner => { await runner.step("existing env matches", async () => { const stub = mock.stub(_internals, "getenv", key => { - if (key == 'FOO') { + if (key == 'FOO' || key == 'PS1') { return 'BAR' } else { return Deno.env.get(key) diff --git a/src/modes/internal.activate.ts b/src/modes/internal.activate.ts index 5aa2614ec..fdb56cb23 100644 --- a/src/modes/internal.activate.ts +++ b/src/modes/internal.activate.ts @@ -2,6 +2,7 @@ import { PackageRequirement, Path, TeaError, hooks, utils } from "tea" import escape_if_necessary from "../utils/sh-escape.ts" import construct_env from "../prefab/construct-env.ts" import install, { Logger } from "../prefab/install.ts" +import { teal } from "../utils/color.ts" import devenv from "../utils/devenv.ts" import undent from "outdent" @@ -49,11 +50,34 @@ export default async function(dir: Path, opts: { logger: Logger }) { rv += `export ${key}=${escape_if_necessary(value)}\n` } - //FIXME doesn't work with warp.dev for fuck knows why reasons - // https://github.com/warpdotdev/Warp/issues/3492 - rv += `export PS1="(tea) $PS1"\n\n` + if (/\(tea\)/.test(getenv("PS1") ?? '') == false) { + //FIXME doesn't work with warp.dev for fuck knows why reasons + // https://github.com/warpdotdev/Warp/issues/3492 + rv += `export PS1="(tea) $PS1"\n` + } + + rv += `export TEA_POWDER="${installations.pkgenv.map(utils.pkg.str).join(' ')}"\n` + rv += `export TEA_PKGENV="${installations.installations.map(({pkg}) => utils.pkg.str(pkg)).join(' ')}"\n\n` + + rv += "_tea_reset() {\n" + for (const key in env) { + const old = getenv(key) + if (old !== undefined) { + //TODO don’t export if not currently exported! + rv += ` export ${key}=${escape_if_necessary(old)}\n` + } else { + rv += ` unset ${key}\n` + } + } + const ps1 = getenv('PS1') + rv += ps1 ? ` export PS1="${ps1}"\n` : " unset PS1\n" + rv += " unset -f _tea_reset\n" + rv += "}\n" + + rv += "\n" - const off_string = installations.pkgenv.map(x => `-${utils.pkg.str(x)}`).join(' ') + const raw_off_string = installations.pkgenv.map(x => `-${utils.pkg.str(x)}`).join(' ') + const off_string = installations.pkgenv.map(x => `-${escape_if_necessary(utils.pkg.str(x))}`).join(' ') rv += undent` _tea_should_deactivate_devenv() { @@ -61,33 +85,29 @@ export default async function(dir: Path, opts: { logger: Logger }) { test "$PWD" != "${dir}$suffix" } - _tea_deactivate() { - echo 'tea ${off_string}' >&2 + _tea_dev_off() { + echo '${teal('tea')} ${raw_off_string}' >&2 - export PS1="${getenv('PS1')}" + tea ${off_string} - if test "$1" != --shy; then + if [ "$1" != --shy ]; then rm "${persistence}" fi - unset -f _tea_deactivate + unset -f _tea_dev_off _tea_should_deactivate_devenv ` - for (const key in env) { + for (const key in userenv) { const value = getenv(key) - if (value !== undefined) { + if (value) { rv += ` export ${key}=${escape_if_necessary(value)}\n` } else { rv += ` unset ${key}\n` } } - rv += "\n" - rv += " _tea_should_deactivate_devenv() {\n" - rv += " return 1\n" - rv += " }\n" - rv += "}\n" + rv += "}" return [rv, installations.pkgenv] as [string, PackageRequirement[]] } diff --git a/src/modes/internal.use.test.ts b/src/modes/internal.use.test.ts index 7581b3dbb..99d9303a7 100644 --- a/src/modes/internal.use.test.ts +++ b/src/modes/internal.use.test.ts @@ -1,10 +1,7 @@ // deno-lint-ignore-file require-await -import { AmbiguityError, ProvidesError } from "../utils/error.ts" -import { assertRejects, assertThrows } from "deno/assert/mod.ts" import { semver, SemVer, Path, Installation, utils } from "tea" import { null_logger as logger } from "../utils/test-utils.ts" import specimen0, { _internals } from "./internal.use.ts" -import usePantry from "tea/hooks/usePantry.ts" import * as mock from "deno/testing/mock.ts" Deno.test("internal.use.ts", async runner => { @@ -54,7 +51,7 @@ Deno.test("internal.use.ts", async runner => { await runner.step("existing env matches", async () => { const stub4 = mock.stub(_internals, "getenv", key => { - if (key == 'FOO') { + if (key == 'FOO' || key == 'PS1') { return 'BAR' } else { return Deno.env.get(key) diff --git a/src/modes/internal.use.ts b/src/modes/internal.use.ts index f12ed7152..a686f0720 100644 --- a/src/modes/internal.use.ts +++ b/src/modes/internal.use.ts @@ -1,9 +1,7 @@ import escape_if_necessary from "../utils/sh-escape.ts" import construct_env from "../prefab/construct-env.ts" import install, { Logger } from "../prefab/install.ts" -import { hooks, PackageRequirement, utils } from "tea" - -const { usePantry } = hooks +import { PackageRequirement, utils } from "tea" interface Pkgs { plus: PackageRequirement[] @@ -16,12 +14,15 @@ export default async function(opts: { pkgs: Pkgs, logger: Logger, pkgenv?: Recor const pkgs = consolidate(opts.pkgs) - let rv = '' - const print = (x: string) => rv += x + '\n' - if (pkgs.length == 0) { - print('unset TEA_POWDER TEA_PKGENV _tea_reset') + return { + shellcode: 'unset TEA_POWDER TEA_PKGENV', + pkgenv: [] + } } else { + let rv = '' + const print = (x: string) => rv += x + '\n' + const pkgenv = await install(pkgs, opts) const env = await construct_env(pkgenv) @@ -50,7 +51,8 @@ export default async function(opts: { pkgs: Pkgs, logger: Logger, pkgenv?: Recor print(` unset ${key}`) } } - print(` export PS1="${getenv("PS1")}"`) + const ps1 = getenv('PS1') + print(ps1 ? ` export PS1="${ps1}"` : ' unset PS1') print(' unset -f _tea_reset _tea_install') print('}') diff --git a/src/modes/repl.ts b/src/modes/repl.ts index 8a9739625..ad05bd6de 100644 --- a/src/modes/repl.ts +++ b/src/modes/repl.ts @@ -2,7 +2,7 @@ import construct_env from "../prefab/construct-env.ts" import install, { Logger } from "../prefab/install.ts" import { PackageRequirement, Path, TeaError, utils } from "tea" import { basename } from "deno/path/mod.ts" -import { gray } from "../utils/Logger.ts" +import { dim } from "../utils/color.ts" import exec from "../utils/execve.ts" export default async function(args: string[], { pkgs, ...opts }: { pkgs: PackageRequirement[], update: boolean | Set, logger: Logger }): Promise { @@ -10,7 +10,7 @@ export default async function(args: string[], { pkgs, ...opts }: { pkgs: Package const pkgenv = await install(pkgs, opts) const env = await construct_env(pkgenv) - const pkgs_str = () => pkgenv.installations.map(({pkg}) => gray(utils.pkg.str(pkg))).join(", ") + const pkgs_str = () => pkgenv.installations.map(({pkg}) => dim(utils.pkg.str(pkg))).join(", ") console.error('this is a temporary shell containing the following packages:') console.error(pkgs_str()) diff --git a/src/modes/shellcode.ts b/src/modes/shellcode.ts index 0558d006f..247669c19 100644 --- a/src/modes/shellcode.ts +++ b/src/modes/shellcode.ts @@ -34,7 +34,7 @@ export default function() { if type _tea_reset >/dev/null 2>&1; then _tea_reset fi - unset -f _tea_chpwd_hook _tea_should_deactivate_devenv _tea_activate_devenv_if_desired tea t command_not_found_handler tea@latest _tea_commit _tea_deactivate >&2 2>/dev/null + unset -f _tea_chpwd_hook _tea_should_deactivate_devenv tea t command_not_found_handler tea@latest _tea_commit _tea_dev_off >/dev/null 2>&1 echo "tea: shellcode unloaded" >&2;; "") if [ -f "${prefix}/tmp/shellcode/x.$$" ]; then @@ -78,11 +78,14 @@ export default function() { dev() { if [ "$1" = 'off' ]; then - _tea_deactivate - elif type _tea_deactivate >/dev/null 2>&1; then + _tea_dev_off + elif type _tea_dev_off >/dev/null 2>&1; then echo 'dev: environment already active' >&2 return 1 else + if type _tea_reset >/dev/null 2>&1; then + _tea_reset + fi eval "$(command tea --internal.activate "$PWD" "$@")" fi } @@ -109,29 +112,21 @@ export default function() { } _tea_chpwd_hook() { - if _tea_should_deactivate_devenv; then - _tea_deactivate --shy + if _tea_should_deactivate_devenv >/dev/null 2>&1; then + _tea_dev_off --shy fi - if ! type _tea_deactivate >/dev/null 2>&1; then - _tea_activate_devenv_if_desired + if ! type _tea_dev_off >/dev/null 2>&1; then + dir="$PWD" + while [ "$dir" != "/" ]; do + if [ -f "${prefix}/var/devenv/$dir/xyz.tea.activated" ]; then + eval "$(command tea --internal.activate "$dir")" + break + fi + dir="$(dirname "$dir")" + done fi } - _tea_should_deactivate_devenv() { - return 1 - } - - _tea_activate_devenv_if_desired() { - dir="$PWD" - while [ "$dir" != "/" ]; do - if [ -f "${prefix}/var/devenv/$dir/xyz.tea.activated" ]; then - eval "$(command tea --internal.activate "$dir")" - break - fi - dir="$(dirname "$dir")" - done - } - if test -n "$ZSH_VERSION"; then eval 'typeset -ag chpwd_functions diff --git a/src/utils/InstallLogger.ts b/src/utils/InstallLogger.ts index 48c01f04e..b3fc8f54f 100644 --- a/src/utils/InstallLogger.ts +++ b/src/utils/InstallLogger.ts @@ -1,6 +1,7 @@ import { PackageSpecification, Package, utils, Path, Installation } from "tea" import { Logger as BaseInstallLogger } from "tea/plumbing/install.ts" -import Logger, { teal,inverse_teal,gray } from "./Logger.ts" +import { teal, inverse_teal, dim } from "./color.ts" +import Logger from "./Logger.ts" import useConfig from "tea/hooks/useConfig.ts" export default class implements BaseInstallLogger { @@ -82,13 +83,13 @@ export default class implements BaseInstallLogger { const total = Object.values(this.totals).reduce((a, b) => a + b, 0) const speed = this.total_rcvd() / (Date.now() - this.start) * 1000 - str += gray(`${pretty_size(speed)[0]}/s`) + str += dim(`${pretty_size(speed)[0]}/s`) if (rcvd && total) { const [pretty_total, divisor] = pretty_size(total, 0) const n = rcvd / divisor const pretty_rcvd = n.toFixed(precision(n)) - str += gray(` ${pretty_rcvd}/${pretty_total}`) + str += dim(` ${pretty_rcvd}/${pretty_total}`) } this.logger.replace(`${prefix} ${str}`) @@ -116,10 +117,10 @@ function precision(n: number) { const log_installed_msg = (pkg: Package, title: string, logger: Logger) => { const { prefix } = useConfig() const pkg_prefix_str = (pkg: Package) => [ - gray(prefix.prettyString()), + dim(prefix.prettyString()), pkg.project, - `${gray('v')}${pkg.version}` - ].join(gray('/')) + `${dim('v')}${pkg.version}` + ].join(dim('/')) const str = pkg_prefix_str(pkg) logger!.replace(`${title} ${str}`, { prefix: false }) diff --git a/src/utils/Logger.ts b/src/utils/Logger.ts index 8314af665..f122bccd4 100644 --- a/src/utils/Logger.ts +++ b/src/utils/Logger.ts @@ -1,10 +1,6 @@ -import { dim as gray, rgb8, bgRgb8, stripColor } from "deno/fmt/colors.ts" +import { stripAnsiCode } from "deno/fmt/colors.ts" import { ansi } from "cliffy/ansi/ansi.ts" - -export const teal = (x: string) => rgb8(x, 86) -export { gray } - -export const inverse_teal = (x: string) => bgRgb8(x, 86) +import { dim } from "./color.ts" export default class Logger { lines = 0 @@ -17,7 +13,7 @@ export default class Logger { //TODO don’t erase whole lines, just erase the part that is different replace(line: string, opts: { prefix: boolean } = {prefix: true}) { if (opts.prefix && this.prefix) { - line = `${gray(this.prefix)}${line}` + line = `${dim(this.prefix)}${line}` } Deno.stderr.writeSync(this._clear().text(line).bytes()) @@ -52,7 +48,7 @@ function ln(s: string) { const { columns } = Deno.consoleSize() if (columns == 0) return 0 // remove ansi escapes to get actual length - const n = stripColor(s).length + const n = stripAnsiCode(s).length return Math.floor(n / columns) } catch { // consoleSize() throws if not a tty diff --git a/src/utils/color.test.ts b/src/utils/color.test.ts new file mode 100644 index 000000000..f2b093b51 --- /dev/null +++ b/src/utils/color.test.ts @@ -0,0 +1,20 @@ +import { assertEquals } from "deno/assert/mod.ts"; +import { teal, dim, inverse_teal } from "./color.ts"; + +Deno.test("color", async runner => { + + await runner.step("teal", () => { + assertEquals(teal("Hello"), "\x1b[38;5;86mHello\x1b[39m") + }) + + await runner.step("dim", () => { + const input = "Hello"; + const expected = "\x1b[2mHello\x1b[22m"; + + assertEquals(dim(input), expected); + }) + + await runner.step("inverse_teal", () => { + assertEquals(inverse_teal("Hello"), "\x1b[48;5;86mHello\x1b[49m"); + }) +}) diff --git a/src/utils/color.ts b/src/utils/color.ts new file mode 100644 index 000000000..8957b9630 --- /dev/null +++ b/src/utils/color.ts @@ -0,0 +1,5 @@ +import { dim, rgb8, bgRgb8 } from "deno/fmt/colors.ts" + +export const teal = (x: string) => rgb8(x, 86) +export { dim } +export const inverse_teal = (x: string) => bgRgb8(x, 86)