Skip to content

Instantly share code, notes, and snippets.

@anhkhoakz
Last active June 9, 2025 18:12
Show Gist options
  • Save anhkhoakz/8f872a78efb9a281290d0e375fdf3781 to your computer and use it in GitHub Desktop.
Save anhkhoakz/8f872a78efb9a281290d0e375fdf3781 to your computer and use it in GitHub Desktop.

Revisions

  1. anhkhoakz revised this gist Jun 9, 2025. 1 changed file with 244 additions and 35 deletions.
    279 changes: 244 additions & 35 deletions prezto-plugins-timer.sh
    Original file line number Diff line number Diff line change
    @@ -1,71 +1,280 @@
    #!/usr/bin/env zsh
    #
    # Plugin loader for zprezto that measures loading time for each plugin.
    # zprezto-plugin-timer - Measures loading time for zprezto plugins
    #
    # Sources plugins from either ~/.zprezto/modules or ~/.zprezto-contrib
    # and reports the time taken to load each plugin.
    # and reports the time taken to load each plugin with performance-based
    # color coding.

    set -e

    typeset -r RED='\033[0;31m'
    typeset -r GREEN='\033[0;32m'
    typeset -r YELLOW='\033[1;33m'
    typeset -r BLUE='\033[0;34m'
    typeset -r NC='\033[0m'
    # Color constants for output formatting
    readonly COLOR_RED='\033[0;31m'
    readonly COLOR_GREEN='\033[0;32m'
    readonly COLOR_YELLOW='\033[1;33m'
    readonly COLOR_BLUE='\033[0;34m'
    readonly COLOR_RESET='\033[0m'

    typeset -r MODULES_PATH="$HOME/.zprezto/modules"
    typeset -r CONTRIB_PATH="$HOME/.zprezto-contrib"
    # Path constants for plugin directories
    readonly ZPREZTO_MODULES_PATH="${HOME}/.zprezto/modules"
    readonly ZPREZTO_CONTRIB_PATH="${HOME}/.zprezto-contrib"

    # Performance thresholds in milliseconds
    readonly FAST_THRESHOLD=15
    readonly MODERATE_THRESHOLD=25

    typeset -a plugins=(
    # Plugin list to load and measure
    readonly PLUGINS_TO_LOAD=(
    "environment"
    "editor"
    "history"
    "directory"
    "utility"
    "completion"
    "fast-syntax-highlighting"
    "zsh-syntax-highlighting"
    "autosuggestions"
    "osx"
    "git"
    "eza"
    )

    # Global array to store plugin load times as "time plugin_name"
    measured_plugin_times=()

    #######################################
    # Print error message to stderr with red color formatting
    # Globals:
    # COLOR_RED, COLOR_RESET
    # Arguments:
    # $1 - Error message to display
    # Outputs:
    # Writes formatted error message to stderr
    #######################################
    err() {
    print -u2 "${RED}Error: $*${NC}"
    local message="$1"
    printf '%bError: %s%b\n' \
    "${COLOR_RED}" "${message}" "${COLOR_RESET}" >&2
    }

    #######################################
    # Print loading status to stderr with blue color formatting
    # Globals:
    # COLOR_BLUE, COLOR_RESET
    # Arguments:
    # $1 - Plugin path being loaded
    # Outputs:
    # Writes formatted loading message to stderr
    #######################################
    print_loading_status() {
    local plugin_path="$1"
    printf '%bLoading %s%b\n' \
    "${COLOR_BLUE}" "${plugin_path}" "${COLOR_RESET}" >&2
    }

    #######################################
    # Get current time in milliseconds
    # Returns:
    # Current timestamp in milliseconds
    #######################################
    get_current_time_ms() {
    echo $(( $(date +%s%N) / 1000000 ))
    }

    #######################################
    # Calculate elapsed time between two timestamps
    # Arguments:
    # $1 - Start time in milliseconds
    # $2 - End time in milliseconds
    # Returns:
    # Elapsed time in milliseconds
    #######################################
    calculate_elapsed_time() {
    local start_time="$1"
    local end_time="$2"
    echo $(( end_time - start_time ))
    }

    #######################################
    # Find plugin file in zprezto directories
    # Globals:
    # ZPREZTO_MODULES_PATH, ZPREZTO_CONTRIB_PATH
    # Arguments:
    # $1 - Plugin name to search for
    # Outputs:
    # Plugin file path if found
    # Returns:
    # 0 if plugin found, 1 if not found
    #######################################
    find_plugin_file() {
    local plugin_name="$1"
    local zprezto_path="${ZPREZTO_MODULES_PATH}/${plugin_name}/init.zsh"
    local contrib_path="${ZPREZTO_CONTRIB_PATH}/${plugin_name}/${plugin_name}.plugin.zsh"

    if [[ -f "${zprezto_path}" ]]; then
    echo "${zprezto_path}"
    return 0
    elif [[ -f "${contrib_path}" ]]; then
    echo "${contrib_path}"
    return 0
    else
    return 1
    fi
    }

    #######################################
    # Source plugin file safely with error filtering
    # Arguments:
    # $1 - Plugin file path to source
    # Outputs:
    # Filtered error messages to stderr (excludes "command not found")
    #######################################
    source_plugin_safely() {
    local plugin_file="$1"
    local error_output

    # Separate declaration and assignment for command substitution
    error_output="$(source "${plugin_file}" 2>&1 >/dev/null | \
    grep -v "command not found" || true)"

    if [[ -n "${error_output}" ]]; then
    printf '%s\n' "${error_output}" >&2
    fi
    }

    #######################################
    # Load a single plugin and measure its loading time
    # Args:
    # $1: Plugin name
    # Globals:
    # measured_plugin_times (modified)
    # Arguments:
    # $1 - Plugin name to load and measure
    # Returns:
    # 0 on success, 1 on failure
    load_plugin() {
    local plugin="$1"
    local timer now elapsed

    timer=$(( $(date +%s%N)/1000000 ))

    if [[ -f "$MODULES_PATH/$plugin/init.zsh" ]]; then
    print -u2 "${BLUE}Loading $MODULES_PATH/$plugin${NC}"
    source "$MODULES_PATH/$plugin/init.zsh" || err "Failed to load $plugin"
    elif [[ -f "$CONTRIB_PATH/$plugin/$plugin.plugin.zsh" ]]; then
    print -u2 "${BLUE}Loading $CONTRIB_PATH/$plugin${NC}"
    source "$CONTRIB_PATH/$plugin/$plugin.plugin.zsh" || err "Failed to load $plugin"
    # 0 if successful, 1 if plugin not found
    #######################################
    measure_plugin_load_time() {
    local plugin_name="$1"
    local plugin_file
    local start_time
    local end_time
    local elapsed_time

    start_time="$(get_current_time_ms)"

    if plugin_file="$(find_plugin_file "${plugin_name}")"; then
    print_loading_status "${plugin_file}"
    source_plugin_safely "${plugin_file}"
    else
    err "Plugin $plugin not found"
    err "Plugin ${plugin_name} not found"
    return 1
    fi

    now=$(( $(date +%s%N)/1000000 ))
    elapsed=$(( now - timer ))
    print "${GREEN}$plugin${NC} ${YELLOW}${elapsed}ms${NC}"
    end_time="$(get_current_time_ms)"
    elapsed_time="$(calculate_elapsed_time "${start_time}" "${end_time}")"

    measured_plugin_times+=("${elapsed_time} ${plugin_name}")
    }

    main() {
    local plugin
    #######################################
    # Determine color based on loading time performance
    # Globals:
    # FAST_THRESHOLD, MODERATE_THRESHOLD, COLOR_*
    # Arguments:
    # $1 - Load time in milliseconds
    # Returns:
    # Appropriate color code for the load time
    #######################################
    get_performance_color() {
    local load_time="$1"

    if (( load_time <= FAST_THRESHOLD )); then
    echo "${COLOR_GREEN}"
    elif (( load_time <= MODERATE_THRESHOLD )); then
    echo "${COLOR_YELLOW}"
    else
    echo "${COLOR_RED}"
    fi
    }

    #######################################
    # Print formatted table row with performance-based coloring
    # Globals:
    # COLOR_BLUE, COLOR_RESET
    # Arguments:
    # $1 - Plugin name
    # $2 - Load time in milliseconds
    # Outputs:
    # Formatted table row to stdout
    #######################################
    print_plugin_result() {
    local plugin_name="$1"
    local load_time="$2"
    local time_color

    time_color="$(get_performance_color "${load_time}")"
    printf '%b%-30s%b %b%10s%b\n' \
    "${COLOR_BLUE}" "${plugin_name}" "${COLOR_RESET}" \
    "${time_color}" "${load_time}" "${COLOR_RESET}"
    }

    #######################################
    # Print results table header
    # Outputs:
    # Table header to stdout
    #######################################
    print_results_header() {
    printf '\n%-30s %10s\n' "NAME" "TIME (ms)"
    printf '%-30s %10s\n' "----" "----------"
    }

    #######################################
    # Display plugin loading results sorted by time
    # Globals:
    # measured_plugin_times
    # Outputs:
    # Formatted results table to stdout
    #######################################
    display_plugin_results() {
    local sorted_times
    local entry
    local load_time
    local plugin_name

    # Sort by time in descending order (slowest first)
    # Note: Using ZSH-specific array sorting syntax
    # shellcheck disable=SC2296
    sorted_times=("${(On)measured_plugin_times[@]}")

    for plugin in "${plugins[@]}"; do
    load_plugin "$plugin"
    print_results_header

    for entry in "${sorted_times[@]}"; do
    load_time="${entry%% *}"
    plugin_name="${entry#* }"
    print_plugin_result "${plugin_name}" "${load_time}"
    done
    }

    main "$@"
    #######################################
    # Load all plugins and measure their performance
    # Globals:
    # PLUGINS_TO_LOAD
    #######################################
    load_and_measure_all_plugins() {
    local plugin_name

    for plugin_name in "${PLUGINS_TO_LOAD[@]}"; do
    measure_plugin_load_time "${plugin_name}"
    done
    }

    #######################################
    # Main function - orchestrates the plugin loading and measurement process
    # Arguments:
    # All command line arguments (currently unused)
    #######################################
    main() {
    load_and_measure_all_plugins
    display_plugin_results
    }

    # Entry point
    main "$@"
  2. anhkhoakz created this gist Jun 9, 2025.
    71 changes: 71 additions & 0 deletions prezto-plugins-timer.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,71 @@
    #!/usr/bin/env zsh
    #
    # Plugin loader for zprezto that measures loading time for each plugin.
    # Sources plugins from either ~/.zprezto/modules or ~/.zprezto-contrib
    # and reports the time taken to load each plugin.

    set -e

    typeset -r RED='\033[0;31m'
    typeset -r GREEN='\033[0;32m'
    typeset -r YELLOW='\033[1;33m'
    typeset -r BLUE='\033[0;34m'
    typeset -r NC='\033[0m'

    typeset -r MODULES_PATH="$HOME/.zprezto/modules"
    typeset -r CONTRIB_PATH="$HOME/.zprezto-contrib"


    typeset -a plugins=(
    "environment"
    "editor"
    "history"
    "directory"
    "utility"
    "completion"
    "fast-syntax-highlighting"
    "autosuggestions"
    "osx"
    "git"
    "eza"
    )

    err() {
    print -u2 "${RED}Error: $*${NC}"
    }

    # Load a single plugin and measure its loading time
    # Args:
    # $1: Plugin name
    # Returns:
    # 0 on success, 1 on failure
    load_plugin() {
    local plugin="$1"
    local timer now elapsed

    timer=$(( $(date +%s%N)/1000000 ))

    if [[ -f "$MODULES_PATH/$plugin/init.zsh" ]]; then
    print -u2 "${BLUE}Loading $MODULES_PATH/$plugin${NC}"
    source "$MODULES_PATH/$plugin/init.zsh" || err "Failed to load $plugin"
    elif [[ -f "$CONTRIB_PATH/$plugin/$plugin.plugin.zsh" ]]; then
    print -u2 "${BLUE}Loading $CONTRIB_PATH/$plugin${NC}"
    source "$CONTRIB_PATH/$plugin/$plugin.plugin.zsh" || err "Failed to load $plugin"
    else
    err "Plugin $plugin not found"
    fi

    now=$(( $(date +%s%N)/1000000 ))
    elapsed=$(( now - timer ))
    print "${GREEN}$plugin${NC} ${YELLOW}${elapsed}ms${NC}"
    }

    main() {
    local plugin

    for plugin in "${plugins[@]}"; do
    load_plugin "$plugin"
    done
    }

    main "$@"