Skip to content

git add with numbered file paths #5

@simonlindholm

Description

@simonlindholm

Aron has the following for fish:

# From https://github.com/ErinCall/Dotfiles/tree/master/.config/fish/functions

function git
    set -l translated_argv

    if test (count $argv) -lt 1 >/dev/null
        command git
        return $status
    end

    # TODO: this won't detect commands with e.g. `git --git-dir ...`
    set -l cmd $argv[1]
    set -e argv[1]

    for arg in $argv
        set translated_argv $translated_argv (python3 ~/.config/fish/functions/git.py --translate "$arg" "$c")
    end

    switch $cmd
    case 'status'
        begin
            set -l IFS
            set -g last_git_output (command git status --short $translated_argv)
        end
        python3 ~/.config/fish/functions/git.py --status "$last_git_output"
        # split0 to make $c be a multiline string instead of a list
        set -g c (python3 ~/.config/fish/functions/git.py --list "$last_git_output" | string split0)
        return $status
    case '*'
        command git $cmd $translated_argv
        return $status
    end
end
# from subprocess import check_output
from colorama import Fore, Style
from sys import stdout, argv, stdin
import os


def acquire_changes(git_short_status):
    # lines = check_output(["git", "status", "--short"]).decode('utf-8').split('\n')
    lines = git_short_status.split('\n')

    result = []
    index = 1

    staged = [line for line in lines if len(line) > 0 and (line[0] != ' ' and line[0] != '?')]
    unstaged = [line for line in lines if len(line) > 0 and not (line[0] != ' ' and line[0] != '?')]

    for line in (staged + unstaged):
        if len(line) == 0:
            continue

        mode = line[0:2]
        if mode[0] == 'R':
            # 'R' in a short-status indicates a staged renamed file. In
            # this case we have two filenames to think about. This code
            # will break in the inexcusable case that the old filename
            # contained ' -> '.
            line = line[3:]
            files = line.split(" -> ")
            file_items = []
            for file in files:
                if file[0] == '"' and file[-1] == '"':
                    file = file[1:-1]

                file_items.append((file, index))
                index += 1

            result.append((mode[0], mode[1], file_items))
        else:
            file = line[3:]
            if file[0] == '"' and file[-1] == '"':
                file = file[1:-1]
            result.append((mode[0], mode[1], [(file, index)]))
            index += 1

    return result


def list(git_short_status):
    changes = acquire_changes(git_short_status)
    for item in changes:
        for file in item[2]:
            print(file[0])


def git_status(git_short_status):
    changes = acquire_changes(git_short_status)
    display([item for item in changes if item[0] not in ['?', ' ']], "Changes to be committed", Fore.GREEN, 0)
    print()
    display([item for item in changes if item[1] not in ['?', ' ']], "Unstaged changes", Fore.YELLOW, 1)
    print()
    display([item for item in changes if item[1] == '?'], "Untracked files", Fore.RED, 1)


def wrap_in_quotes(filename):
    if " " in filename:
        return '"' + filename + '"'
    else:
        return filename


def display(items, header, color, state_index):
    if len(items) == 0:
        return

    print(color + Style.BRIGHT + header + Style.RESET_ALL)

    state_names = {
        'M': '  modified',
        'A': '  new file',
        'D': '   deleted',
        'R': '   renamed',
        'C': '    copied',
        'T': 'typechange',
        '?': ' untracked',
        ' ': '         ?'
    }

    for item in items:
        padding(color)

        state = item[state_index]

        if state in state_names:
            stdout.write(state_names[state])
        else:
            stdout.write('         ' + state)

        # Special case for renamed files in the unstaged section
        # only show the new filename, not the renames
        if item[0] == 'R' and state_index == 1:
            files = item[2]
            stdout.write(": [" + str(files[1][1]) + "] ")
            stdout.write(color + wrap_in_quotes(files[1][0]))
        else:
            files = item[2]
            stdout.write(": [" + str(files[0][1]) + "] ")
            stdout.write(color + wrap_in_quotes(files[0][0]))

            if len(files) > 1:
                stdout.write(Fore.RESET + ' -> ' + '[' + str(files[1][1]) + '] ')
                stdout.write(color + wrap_in_quotes(files[1][0]))

        stdout.write('\n')

def translate(s: str, options: str):
    lines = options.strip().split("\n")
    
    try:
        if "-" in s:
            splits = s.split("-")
            if len(splits) != 2:
                print(s)
                return
            r = (int(splits[0]), int(splits[1]))
            if r[0] <= 0 or r[1] <= 0:
                print(s)
                return
            for i in range(r[0], r[1]+1):
                print(lines[i-1])
        else:
            v = int(s)
            if v <= 0:
                print(s)
                return

            print(lines[v-1])
    except:
        print(s)


def padding(color):
    stdout.write(color + Style.BRIGHT + '#' + Style.RESET_ALL + '      ')

if argv[1] == '--list':
    list(argv[2])
elif argv[1] == '--status':
    git_status(argv[2])
elif argv[1] == '--translate':
    translate(argv[2], argv[3])
else:
    print("Unknown command")

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions