From 96b09edbe4732141946a368b5736e8347a4999ba Mon Sep 17 00:00:00 2001 From: Christian Nieves Date: Tue, 9 Aug 2022 18:38:53 +0000 Subject: [PATCH] hgshort --- hgshort/hgshort/OWNERS | 2 + hgshort/hgshort/README.md | 7 +++ hgshort/hgshort/aliases.sh | 21 +++++++++ hgshort/hgshort/hgd.sh | 12 +++++ hgshort/hgshort/hgshort.hgrc | 73 +++++++++++++++++++++++++++++++ hgshort/hgshort/hgshort.py | 82 +++++++++++++++++++++++++++++++++++ hgshort/hgshort/hgshort.sh | 20 +++++++++ hgshort/hgshort/tobashargs.py | 35 +++++++++++++++ hgshort/hgshort/tobashargs.sh | 11 +++++ 9 files changed, 263 insertions(+) create mode 100644 hgshort/hgshort/OWNERS create mode 100644 hgshort/hgshort/README.md create mode 100644 hgshort/hgshort/aliases.sh create mode 100755 hgshort/hgshort/hgd.sh create mode 100644 hgshort/hgshort/hgshort.hgrc create mode 100644 hgshort/hgshort/hgshort.py create mode 100755 hgshort/hgshort/hgshort.sh create mode 100755 hgshort/hgshort/tobashargs.py create mode 100755 hgshort/hgshort/tobashargs.sh diff --git a/hgshort/hgshort/OWNERS b/hgshort/hgshort/OWNERS new file mode 100644 index 0000000..1cd4e3c --- /dev/null +++ b/hgshort/hgshort/OWNERS @@ -0,0 +1,2 @@ +parren +yurilev diff --git a/hgshort/hgshort/README.md b/hgshort/hgshort/README.md new file mode 100644 index 0000000..18e1bc2 --- /dev/null +++ b/hgshort/hgshort/README.md @@ -0,0 +1,7 @@ +# hgshort - Single Letter Shorthands for Fig + +hgshort makes it really easy to work with files and revisions in Fig. Use +**single letter** shorthand names, instead of long paths and hash codes. + +Documentation can be found +[here](http://g3doc/experimental/fig_contrib/g3doc/hgshort). diff --git a/hgshort/hgshort/aliases.sh b/hgshort/hgshort/aliases.sh new file mode 100644 index 0000000..400a1c8 --- /dev/null +++ b/hgshort/hgshort/aliases.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Creates the recommended alias definitions for hgshort when sourced. + +HGSHORT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-${(%):-%x}}}")" && pwd)" + +alias hg="source $HGSHORT_DIR/hgshort.sh" + +# There are two ways to customize: +# - define HGSHORT_CMDS_ADDITIONAL in your shell configuration to augment the +# following list. +# - define HGSHORT_CMDS directly in your shell configuration to override the +# following list. +if [[ -z "$HGSHORT_CMDS" ]]; then + HGSHORT_CMDS="$HGSHORT_CMDS_ADDITIONAL ls cat head tail mv cp rm chmod g4 diff merge patch meld vim emacs edit trim less more" +fi + +# Doing the variable expansion with an 'echo' makes this compatible with zsh. +for c in $(echo "$HGSHORT_CMDS"); do + alias $c="source $HGSHORT_DIR/tobashargs.sh $c" +done diff --git a/hgshort/hgshort/hgd.sh b/hgshort/hgshort/hgd.sh new file mode 100755 index 0000000..0b85cae --- /dev/null +++ b/hgshort/hgshort/hgd.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +HGSHORT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-${(%):-%x}}}")" && pwd)" + +source $HGSHORT_DIR/aliases.sh +cd $(hg hgd "$@") + +CITC="${PWD#/google/src/cloud/$USER/}" +CITC="${CITC%/google3}" +echo "CitC $CITC" + +hg l --color=always diff --git a/hgshort/hgshort/hgshort.hgrc b/hgshort/hgshort/hgshort.hgrc new file mode 100644 index 0000000..02ecb79 --- /dev/null +++ b/hgshort/hgshort/hgshort.hgrc @@ -0,0 +1,73 @@ +# .hgrc for use with hgshort. +# +# Adds generated single letter revision and file shorthand names to the outputs +# of 'hg l/xl/ll' and 'hg status'. +# +# * For hg l/xl/ll, modifies the defaults set by: +# http://google3/devtools/piper/hgfission/client/config/google-ui-tweaks.rc +# +# * For hg status, overrides the default template (no extensible template +# available), but with one that looks the same. +# +# To use, add the following line to your ~/.hgrc: +# %include /google/src/head/depot/google3/experimental/fig_contrib/hgshort/hgshort.hgrc +# +# To make hg and other commands actually recognize the outputted shorthand +# names, follow go/hgshort#initial-setup. +# +# If you have already customized the outputs of 'hg l/xl/ll' or 'hg status', +# including this file would override them. Instead: +# +# * If you only aliased or added default arguments for 'hg status', add the +# following argument: +# --template=hgshort_status +# +# * If you customized the outputs themselves, copy the "extensions" and +# optionally the "color" sections and use: +# +# + hgshort_revision_shorthand — in your log templates. +# + hgshort_file_shorthand — in your status templates. + +[extensions] +hgshort = /google/src/head/depot/google3/experimental/fig_contrib/hgshort/hgshort.py + +[color] +# The color used for hgshort's single letter aliases. +hgshort.alias = red bold + +[color256] +# The color used for hgshort's single letter aliases. +hgshort.alias = orange bold + +##### hg l/xl/ll configuration ##### + +[templatealias] +# Get an alias for the current revision (node) with an uppercase letter. +hgshort_revision_shorthand='{hgshort(node,"A")}' +# Add the revision hgshort shorthand name to the output of 'hg l/xl/ll'. +google_compact_line_1_part_1 = '{hgshort_revision_shorthand}{google_compact_uniq_id}' + +##### hg status configuration ##### + +[templatealias] +# Get an alias for the current file with a lowercase letter. +hgshort_file_shorthand='{hgshort(relpath(path),"a")}' +# Get the right built-in label (style) for the file's status. +# See http://screen/8A5ynkOdEED.png for an example output, +# and 'hg help status' for details. +hgshort_status_label(status) = '{ifeq(status, "?", "status.unknown", ifeq(status, "!", "status.deleted", get(dict(A="status.added", M="status.modified", R="status.removed", I="status.ignored", C="status.clean"), status)))}' +hgshort_status_line1 = '{hgshort_file_shorthand}{label(hgshort_status_label(status), '{status} {relpath(path)}')}' +hgshort_status_line2 = '{if(source, " {label("status.copied", " {relpath(source)}")}")}' + +[templates] +# Add the hgshort file shorthand name to the output of 'hg status'. +# In conflict resolution mode, we get empty entries. Filter them out. +hgshort_status = '{if(path,"{separate("\n", hgshort_status_line1, hgshort_status_line2)}\n","")}' + +[defaults] +# Override the default 'hg status' command, but keep -n working. +status = --template=hgshort_status + +[alias] +# Override the default 'hg pstatus' template. +pstatus = pstatus --template=hgshort_status diff --git a/hgshort/hgshort/hgshort.py b/hgshort/hgshort/hgshort.py new file mode 100644 index 0000000..fd9c93c --- /dev/null +++ b/hgshort/hgshort/hgshort.py @@ -0,0 +1,82 @@ +'''"shorthand" template filter to emit bash shorthand accessors.''' + +import os +import sys + +from mercurial import error +from mercurial import i18n +from mercurial import registrar +from mercurial import templateutil + +# dict of template built-in functions +funcs = {} +templatefunc = registrar.templatefunc(funcs) +templatefilter = registrar.templatefilter() + +evalboolean = templateutil.evalboolean +evalstring = templateutil.evalstring + +bashvarsfile = None +if sys.stdout.isatty(): + if 'HGSHORT_BASH_VARS' in os.environ: + bashvarsfile = os.environ['HGSHORT_BASH_VARS'] + +nextaliasidbytype = { + b'a': ord(b'a'), + b'A': ord(b'A')} + + +def writealias(name, value): + if not bashvarsfile: + return + with open(bashvarsfile, 'a') as f: + f.write("export %s='%s'\n" % (name.decode('utf-8'), value.decode('utf-8'))) + + +def nextaliaschar(aliastype): + if not bashvarsfile: + return None + aliasid = nextaliasidbytype[aliastype] + if aliasid < ord(aliastype) + 26: + nextaliasidbytype[aliastype] += 1 + return chr(aliasid).encode('utf-8') + return None + + +def maybealias(value, aliastype): + """Export as next bash alias and return id, or None.""" + aliaschar = nextaliaschar(aliastype) + if not aliaschar: return None + writealias(b'hgshort%s' % aliaschar, value) + return aliaschar + + +@templatefilter(b'shorthand', intype=bytes) +def shorthand(text): + """Export as next bash alias.""" + if not bashvarsfile: + return b'' + aliaschar = maybealias(text, b'a') + if not aliaschar: + return b' ' + return b'%s ' % aliaschar + + +@templatefunc( + b'hgshort(text, aliastype)', + argspec=b'text aliastype', + requires={b'ui'}) +def hgshort(context, mapping, args): + """Export as next bash alias and return id, or None.""" + if not bashvarsfile: + return b'' + if b'text' not in args or b'aliastype' not in args: + raise error.ParseError(i18n._(b'hgshort() expects one to three arguments')) + text = evalstring(context, mapping, args[b'text']) + aliastype = evalstring(context, mapping, args[b'aliastype']) + aliaschar = maybealias(text, aliastype) + if not aliaschar: + return b' ' + aliastext = b'%s ' % aliaschar + ui = context.resource(mapping, b'ui') + return ui.label(aliastext, b'hgshort.alias') diff --git a/hgshort/hgshort/hgshort.sh b/hgshort/hgshort/hgshort.sh new file mode 100755 index 0000000..904cdaa --- /dev/null +++ b/hgshort/hgshort/hgshort.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +HGSHORT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-${(%):-%x}}}")" && pwd)" + +export HGSHORT_BASH_VARS="/tmp/hgshort-bash-vars-$$.sh" +export HGSHORT_BASH_ARGS="/tmp/hgshort-bash-args-$$.sh" + +if [[ -f $HGSHORT_BASH_VARS ]]; then + \rm $HGSHORT_BASH_VARS # don't call rm to avoid alias loop +fi + +HGSHORT_IS_HG=1 $HGSHORT_DIR/tobashargs.py "$@" > $HGSHORT_BASH_ARGS +xargs --null --arg-file=$HGSHORT_BASH_ARGS \ + hg --config extensions.hgshort=$HGSHORT_DIR/hgshort.py +\rm $HGSHORT_BASH_ARGS # don't call rm to avoid alias loop + +if [[ -f $HGSHORT_BASH_VARS ]]; then + source $HGSHORT_BASH_VARS + \rm $HGSHORT_BASH_VARS # don't call rm to avoid alias loop +fi diff --git a/hgshort/hgshort/tobashargs.py b/hgshort/hgshort/tobashargs.py new file mode 100755 index 0000000..1e7860b --- /dev/null +++ b/hgshort/hgshort/tobashargs.py @@ -0,0 +1,35 @@ +#! /usr/bin/python3 +"""Converts single letters like X to bash variable references like $hgshortX.""" + +import os +import re +import sys + +# Shortands can be prefixed with an 'r', in which case several can be used in +# one argument. This is useful for revsets, for example: 'rA::rD'. +ALIAS_RE = re.compile(r'^([a-zA-Z])$|\br([A-Z])\b') + + +def subst(match): + char = match.group(1) or match.group(2) + + var = 'hgshort%s' % char + if var in os.environ: + return os.getenv(var, '') + + return match.group(0) + + +def substall(s): + return ALIAS_RE.sub(subst, s) + + +# Don't process first argument for `hg`, since it's often a command abbreviated +# to a single letter. +if 'HGSHORT_IS_HG' in os.environ: + args = sys.argv[1:2] + list(substall(a) for a in sys.argv[2:]) +else: + args = list(substall(a) for a in sys.argv[1:]) + +# sys.stderr.write('%s\n' % repr(args)) # debug only +sys.stdout.write(chr(0).join(args)) diff --git a/hgshort/hgshort/tobashargs.sh b/hgshort/hgshort/tobashargs.sh new file mode 100755 index 0000000..182c79a --- /dev/null +++ b/hgshort/hgshort/tobashargs.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +HGSHORT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-${(%):-%x}}}")" && pwd)" + +export HGSHORT_BASH_CMD="$1" +export HGSHORT_BASH_ARGS="/tmp/HGSHORT-bash-args-$$.sh" + +shift +$HGSHORT_DIR/tobashargs.py "$@" > $HGSHORT_BASH_ARGS +xargs --null --arg-file=$HGSHORT_BASH_ARGS $HGSHORT_BASH_CMD +\rm $HGSHORT_BASH_ARGS # don't call rm to avoid alias loop