aboutsummaryrefslogblamecommitdiff
path: root/bin/oii.mi5
blob: 914d45f97ceba055bd3181f30346cd47b13f03e3 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                                                            






                                                                               
# Only run a command on input if there was at least one byte
self=oii

# Need at least a command name
if [ "$#" -eq 0 ] ; then
    printf >&2 '%s: Need a command\n' "$self"
    exit 2
fi

<%
include(`include/mktd.m4')
%>

# Read up to one byte and save it into temp file; discard stderr (stats)
tf=$td/input
dd bs=1 count=1 of="$tf" 2>/dev/null

# If there's now a byte in the file, spit it and the rest of the input into the
# requested command
[ -s "$tf" ] && cat -- "$tf" - | "$@"
: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
# Shortcut to switch to another directory with the same parent, i.e. a sibling
# of the current directory.
#
#     $ pwd
#     /home/you
#     $ sd friend
#     $ pwd
#     /home/friend
#     $ sd you
#     $ pwd
#     /home/you
#
# If no arguments are given and there's only one other sibling, switch to that;
# nice way to quickly toggle between two siblings.
#
#     $ cd -- "$(mktemp -d)"
#     $ pwd
#     /tmp/tmp.ZSunna5Eup
#     $ mkdir a b
#     $ ls
#     a b
#     $ cd a
#     pwd
#     /tmp/tmp.ZSunna5Eup/a
#     $ sd
#     $ pwd
#     /tmp/tmp.ZSunna5Eup/b
#     $ sd
#     $ pwd
#     /tmp/tmp.ZSunna5Eup/a
#
# Seems to work for symbolic links.
sd() {

    # Check argument count
    if [ "$#" -gt 1 ] ; then
        printf >&2 'sd(): Too many arguments\n'
        return 2
    fi

    # Strip trailing slashes
    while : ; do
        case $1 in
            *?/) set -- "${1%/}" ;;
            *) break ;;
        esac
    done

    # Read sole optional argument
    case $1 in

        # Root has no siblings
        /)
            printf >&2 'sd(): Radical misunderstanding\n'
            return 2
            ;;

        # Slashes aren't allowed
        */*)
            printf >&2 'sd(): Illegal slash\n'
            return 2
            ;;

        # If blank, we try to find if there's just one sibling, and change to
        # that if so
        '')
            # First a special case: root dir
            case $PWD in
                *[!/]*) ;;
                *)
                    printf >&2 'sd(): No siblings\n'
                    return 1
                    ;;
            esac

            # Get a full list of directories at this level; include dotfiles,
            # but not the . and .. entries, using glob tricks to avoid Bash
            # ruining things with `dotglob`
            set -- ../[!.]*/
            [ -e "$1" ] || shift
            set -- ../.[!.]*/ "$@"
            [ -e "$1" ] || shift
            set -- ../..?*/ "$@"
            [ -e "$1" ] || shift

            # Check the number of matches
            case $# in

                # One match?  Must be $PWD, so no siblings--throw in 0 just in
                # case, but that Shouldn't Happen (TM)
                0|1)
                    printf >&2 'sd(): No siblings\n'
                    return 1
                    ;;

                # Two matches; hopefully just one sibling, but which is it?
                2)

                    # Push PWD onto the stack, strip trailing slashes
                    set -- "$1" "$2" "$PWD"
                    while : ; do
                        case $3 in
                            */) set -- "$1" "$2" "${3%/}" ;;
                            *) break ;;
                        esac
                    done

                    # Pick whichever of our two parameters doesn't look like
                    # PWD as our sole parameter
                    case $1 in
                        ../"${3##*/}"/) set -- "$2" ;;
                        *) set -- "$1" ;;
                    esac
                    ;;

                # Anything else?  Multiple siblings--user will need to specify
                *)
                    printf >&2 'sd(): Multiple siblings\n'
                    return 1
                    ;;
            esac
            ;;

        # If not, simply set our target to that directory, and let `cd` do the
        # complaining if it doesn't exist
        *) set -- ../"$1" ;;
    esac

    # Try and change into the first parameter
    # shellcheck disable=SC2164
    cd -- "$1"
}