diff --git a/package-lock.json b/package-lock.json index c9e56720ab..3a854864e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12130,6 +12130,7 @@ "dependencies": { "@pkgjs/parseargs": "^0.11.0", "buffer": "^6.0.3", + "chalk": "^5.3.0", "diff": "^5.2.0", "isomorphic-git": "^1.25.10" }, @@ -12165,6 +12166,18 @@ "ieee754": "^1.2.1" } }, + "packages/git/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "packages/git/node_modules/diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", diff --git a/packages/git/package.json b/packages/git/package.json index 9b52a8b782..e446dbf884 100644 --- a/packages/git/package.json +++ b/packages/git/package.json @@ -20,6 +20,7 @@ "dependencies": { "@pkgjs/parseargs": "^0.11.0", "buffer": "^6.0.3", + "chalk": "^5.3.0", "diff": "^5.2.0", "isomorphic-git": "^1.25.10" } diff --git a/packages/git/src/color.js b/packages/git/src/color.js new file mode 100644 index 0000000000..24188b17b4 --- /dev/null +++ b/packages/git/src/color.js @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +import chalk from 'chalk'; + +export const color_options = { + 'color': { + // TODO: '--color[=]' syntax, once we have an args parser that supports optional string option-arguments. + description: 'Force colored output.', + type: 'boolean', + }, + 'no-color': { + description: 'Disable colored output.', + type: 'boolean', + }, +} + +/** + * Process command-line options related to color, and modify them in place. + * Sets the chalk color level based on whether color is enabled or disabled. + * @param options Parsed command-line options, which will be modified in place. + */ +export const process_color_options = (options) => { + + if (!options['color'] && !options['no-color']) { + // TODO: Default to whether we're running in a TTY, once we have that concept. + options['color'] = true; + } + + if (options['no-color']) { + options['color'] = false; + delete options['no-color']; + } + + chalk.level = options.color ? 3 : 0; +} diff --git a/packages/git/src/format.js b/packages/git/src/format.js index da3d320af8..db9f2868c0 100644 --- a/packages/git/src/format.js +++ b/packages/git/src/format.js @@ -17,6 +17,7 @@ * along with this program. If not, see . */ import { shorten_hash } from './git-helpers.js'; +import chalk from 'chalk'; export const commit_formatting_options = { 'abbrev-commit': { @@ -428,15 +429,15 @@ export const format_diffs = (diffs, options) => { s += `+++ ${b_path}\n`; for (const hunk of diff.hunks) { - s += `\x1b[36;1m@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@\x1b[0m\n`; + s += chalk.blueBright(`@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@\n`); for (const line of hunk.lines) { switch (line[0]) { case '+': - s += `\x1b[32;1m${line}\x1b[0m\n`; + s += chalk.greenBright(`${line}\n`); break; case '-': - s += `\x1b[31;1m${line}\x1b[0m\n`; + s += chalk.redBright(`${line}\n`); break; default: s += `${line}\n`; diff --git a/packages/git/src/subcommands/branch.js b/packages/git/src/subcommands/branch.js index 3174d6b996..257db29985 100644 --- a/packages/git/src/subcommands/branch.js +++ b/packages/git/src/subcommands/branch.js @@ -19,6 +19,8 @@ import git from 'isomorphic-git'; import { find_repo_root, shorten_hash } from '../git-helpers.js'; import { SHOW_USAGE } from '../help.js'; +import { color_options, process_color_options } from '../color.js'; +import chalk from 'chalk'; const BRANCH = { name: 'branch', @@ -64,7 +66,8 @@ const BRANCH = { description: 'Perform the action forcefully. For --delete, ignores whether the branches are fully merged. For --move, --copy, and creating new branches, ignores whether a branch already exists with that name.', type: 'boolean', short: 'f', - } + }, + ...color_options, }, }, execute: async (ctx) => { @@ -108,6 +111,8 @@ const BRANCH = { } } + process_color_options(options); + const { dir, gitdir } = await find_repo_root(fs, env.PWD); const get_current_branch = async () => git.currentBranch({ @@ -266,7 +271,7 @@ const BRANCH = { for (const branch of branches) { if (branch === current_branch) { - stdout(`\x1b[32;1m* ${branch}\x1b[0m`); + stdout(chalk.greenBright(`* ${branch}`)); } else { stdout(` ${branch}`); } diff --git a/packages/git/src/subcommands/diff.js b/packages/git/src/subcommands/diff.js index 88862c411c..0775de2021 100644 --- a/packages/git/src/subcommands/diff.js +++ b/packages/git/src/subcommands/diff.js @@ -23,6 +23,7 @@ import * as Diff from 'diff'; import path from 'path-browserify'; import { diff_formatting_options, format_diffs, process_diff_formatting_options } from '../format.js'; import { diff_git_trees } from '../diff.js'; +import { color_options, process_color_options } from '../color.js'; export default { name: 'diff', @@ -55,6 +56,7 @@ export default { description: 'Compare files, ignoring git.', type: 'boolean', }, + ...color_options, }, }, execute: async (ctx) => { @@ -63,6 +65,8 @@ export default { const { options, positionals, tokens } = args; const cache = {}; + process_color_options(options); + const diff_options = process_diff_formatting_options(options); if (diff_options.no_patch && !options['exit-code']) return; diff --git a/packages/git/src/subcommands/log.js b/packages/git/src/subcommands/log.js index 470f8d8dcb..6ad523b1bd 100644 --- a/packages/git/src/subcommands/log.js +++ b/packages/git/src/subcommands/log.js @@ -28,6 +28,7 @@ import { import path from 'path-browserify'; import { SHOW_USAGE } from '../help.js'; import { diff_git_trees } from '../diff.js'; +import { color_options, process_color_options } from '../color.js'; export default { name: 'log', @@ -39,6 +40,7 @@ export default { options: { ...commit_formatting_options, ...diff_formatting_options, + ...color_options, 'max-count': { description: 'Maximum number of commits to output.', type: 'string', @@ -54,6 +56,7 @@ export default { process_commit_formatting_options(options); const diff_options = process_diff_formatting_options(options, { show_patch_by_default: false }); + process_color_options(options); const depth = Number(options['max-count']) || undefined; diff --git a/packages/git/src/subcommands/push.js b/packages/git/src/subcommands/push.js index 30b862f9a7..fe0f30b12c 100644 --- a/packages/git/src/subcommands/push.js +++ b/packages/git/src/subcommands/push.js @@ -21,6 +21,8 @@ import http from 'isomorphic-git/http/web'; import { determine_fetch_remote, find_repo_root, shorten_hash } from '../git-helpers.js'; import { SHOW_USAGE } from '../help.js'; import { authentication_options, Authenticator } from '../auth.js'; +import { color_options, process_color_options } from '../color.js'; +import chalk from 'chalk'; export default { name: 'push', @@ -37,6 +39,7 @@ export default { short: 'f', }, ...authentication_options, + ...color_options, }, }, execute: async (ctx) => { @@ -45,6 +48,8 @@ export default { const { options, positionals } = args; const cache = {}; + process_color_options(options); + const { dir, gitdir } = await find_repo_root(fs, env.PWD); const remotes = await git.listRemotes({ @@ -265,12 +270,13 @@ export default { stdout(`To ${remote_url}`); let any_failed = false; for (const { flag, summary, source, dest, reason } of results) { - stdout(`${flag === '!' ? '\x1b[31;1m' : ''} ${flag} ${summary.padEnd(19, ' ')}\x1b[0m ${source} -> ${dest}${reason ? ` (${reason})` : ''}`); + const flag_and_summary = `${flag} ${summary.padEnd(19, ' ')}`; + stdout(` ${ (flag === '!') ? chalk.redBright(flag_and_summary) : flag_and_summary } ${source} -> ${dest}${reason ? ` (${reason})` : ''}`); if (reason) any_failed = true; } if (any_failed) { - stderr(`\x1b[31;1merror: Failed to push some refs to '${remote_url}'\x1b[0m`); + stderr(chalk.redBright(`error: Failed to push some refs to '${remote_url}'`)); } }, }; diff --git a/packages/git/src/subcommands/show.js b/packages/git/src/subcommands/show.js index b14c538894..a6bbdf13d9 100644 --- a/packages/git/src/subcommands/show.js +++ b/packages/git/src/subcommands/show.js @@ -28,6 +28,7 @@ import { process_diff_formatting_options, } from '../format.js'; import { diff_git_trees } from '../diff.js'; +import { color_options, process_color_options } from '../color.js'; export default { name: 'show', @@ -38,6 +39,7 @@ export default { options: { ...commit_formatting_options, ...diff_formatting_options, + ...color_options, }, }, execute: async (ctx) => { @@ -47,6 +49,7 @@ export default { process_commit_formatting_options(options); const diff_options = process_diff_formatting_options(options); + process_color_options(options); const { dir, gitdir } = await find_repo_root(fs, env.PWD);