twpayne/chezmoi

Visual colored "tree" of managed files

Closed this issue · 1 comments

Is your feature request related to a problem? Please describe.

It's easy to create a new file or directory but forget to add it to chezmoi so it's nice to be able to verify which files are currently managed by chezmoi and which aren't.

Describe the solution you'd like

Update the chezmoi managed command to loop over directories and files and show encrypted files in yellow, managed files in green and un-managed files in white in a tree like structure. If colors aren't available it could use * or other punctuation to prefix the files.

If a directory contains no managed files it should only print the directory name but shouldn't traverse it recursively; this is so you will see if you missed a directory that should be included but keeps the output short enough to be readable. It should also skip certain directories like .cache/ and .local/state/ and .local/share to keep the output short enough to be readable.

I wrote a script that implements most of this in zsh:

chez-managed() {
    local green='\033[0;32m'
    local yellow='\033[1;33m'
    local white='\033[0;37m'
    local no_color='\033[0m'
    local home_dir="$HOME"

    # Generate the list of encrypted and managed files

    local encrypted_files=$(diff <(chezmoi managed --source-path | sed "s|^$home_dir/||") <(chezmoi managed --exclude=encrypted --source-path | sed "s|^$home_dir/||") | grep '^<' | sed 's/^< //' | sed "s|^$home_dir/||")
    local managed_files=$(chezmoi managed --source-path | sed "s|^$home_dir/||")

    print-colored() {
        local file="$1"
        local color="$2"
        echo -e "${color}${file#${home_dir}/}${no_color}"
    }


    directory-has-managed-or-encrypted-files() {
        local dir="$1"
        for file in "$dir"/* "$dir"/.*; do
            [[ -e "$file" ]] || continue
            local relative_path=${file#$home_dir/}
            [[ "$relative_path" == "." || "$relative_path" == ".." ]] && continue
            if echo "$managed_files" | grep -Fxq "$relative_path" || echo "$encrypted_files" | grep -Fxq "$relative_path"; then
                return 0
            fi
        done
        return 1

    }

    print-tree() {
        local directory="$1"
        local prefix="$2"


        # Enable null_glob and glob_dots for zsh
        setopt local_options null_glob glob_dots


        # Exclude specific directories
        case "$directory" in
            *".local/share"* | *".local/state"* | *".cache"*) return ;;
        esac


        # Check if the directory has managed or encrypted files
        if directory-has-managed-or-encrypted-files "$directory"; then

            if [[ "$directory" != "$home_dir" ]]; then
                echo -e "${white}${directory#${home_dir}/}/${no_color}"
            fi
            # Get and sort the list of files and directories
            local items=("${(@f)$(ls -A1d "$directory"/*(DN) "$directory"/.*(DN) | sort)}")

            for item in "${items[@]}"; do

                local item_name=$(basename "$item")
                local relative_item_path=${item#$home_dir/}

                [[ "$item_name" == "." || "$item_name" == ".." ]] && continue

                local display_item="$prefix$item_name"

                [[ -d "$item" ]] && display_item+="/"

                if [[ -d "$item" ]]; then
                    # Recurse into subdirectories
                    print-tree "$item" "$prefix    "
                else
                    # Print files with color-coding
                    if echo "$encrypted_files" | grep -Fxq "$relative_item_path"; then
                        print-colored "$display_item" "$yellow"
                    elif echo "$managed_files" | grep -Fxq "$relative_item_path"; then
                        print-colored "$display_item" "$green"
                    else
                        print-colored "$display_item" "$white"
                    fi
                fi
            done
        else
            echo -e "${white}${directory#${home_dir}/}/${no_color}"

        fi
    }

    print-tree "$home_dir" ""
}

Describe alternatives you've considered

I've written a script to do this since it's not built into chezmoi.

Additional context

I can add screenshots once my chezmoi install is working again.

EDIT: looks like there is a bug in my script causing duplicates but here's what it looks like to give an idea:

image

Great idea!

Notes to self for implementation:

  • Add a --tree flag to chezmoi unmanaged (and all other commands that produce a list of files) that produces output in this format.
  • Respect the existing --color flag.