aboutsummaryrefslogtreecommitdiff
path: root/iTerm/wal-iterm.py
blob: 6e9b44373f00484e10fa06d8762616ba5a517f30 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/usr/bin/env python3
"""
Script to run pywal and apply colors to iTerm2 automatically.
Usage: python3 wal-iterm.py [path_to_image]
"""

import subprocess
import sys
import os
import json
import tempfile
from pathlib import Path
import plistlib

HOME = Path.home()
WAL_CACHE = HOME / ".cache" / "wal"
ITERM_COLORS_DIR = WAL_CACHE / "itermcolors"
COLORS_JSON = WAL_CACHE / "colors.json"


def run_command(cmd, check=True):
    """Run a shell command and return the result."""
    try:
        result = subprocess.run(
            cmd, shell=True, capture_output=True, text=True, check=check
        )
        return result.stdout.strip(), result.stderr.strip(), result.returncode
    except subprocess.CalledProcessError as e:
        print(f"Error running command: {cmd}")
        print(f"Error: {e.stderr}")
        sys.exit(1)


def hex_to_rgb(hex_color):
    """Convert hex color to RGB values (0-1 range)."""
    hex_color = hex_color.lstrip('#')
    r = int(hex_color[0:2], 16) / 255.0
    g = int(hex_color[2:4], 16) / 255.0
    b = int(hex_color[4:6], 16) / 255.0
    return r, g, b


def run_wal(image_path=None, backend="haishoku"):
    """Run pywal to generate colors."""
    if image_path:
        if not os.path.exists(image_path):
            print(f"Error: Image file not found: {image_path}")
            sys.exit(1)
        print(f"Running wal on image: {image_path} (backend: {backend})")
        cmd = f'wal -i "{image_path}" --backend {backend}'
    else:
        print("Running wal to regenerate colors from last image...")
        cmd = "wal -n"
    
    stdout, stderr, returncode = run_command(cmd, check=False)
    
    if returncode != 0:
        print(f"\nError: wal failed to process the image.")
        if stderr:
            print(f"Details: {stderr}")
        
        if not image_path:
            print("Cannot retry without image path. Please specify an image.")
            sys.exit(1)
        
        # Try alternative backends as fallback
        fallback_backends = ["colorthief", "colorz", "wal"]
        
        for fallback_backend in fallback_backends:
            if fallback_backend == backend:
                continue
            print(f"\nTrying with {fallback_backend} backend...")
            cmd_fallback = f'wal -i "{image_path}" --backend {fallback_backend}'
            stdout, stderr, returncode = run_command(cmd_fallback, check=False)
            
            if returncode == 0:
                print(f"✓ Successfully generated colors using {fallback_backend} backend")
                break
            else:
                print(f"  {fallback_backend} backend also failed")
        else:
            print(f"\nError: wal failed with all attempted backends.")
            print("This may be a pywal bug with this specific image.")
            print("Suggestions:")
            print("  - Try a different image")
            print("  - Update pywal: pip install --upgrade pywal")
            print("  - Try manually: wal -i <image> --backend <backend>")
            sys.exit(1)
    
    if stderr and "error" not in stderr.lower():
        print(stderr)
    
    print("✓ Colors generated by wal")





def create_dynamic_profile():
    """Create/update a dynamic profile with pywal colors."""
    print("Creating/updating dynamic profile...")

    if not COLORS_JSON.exists():
        print(f"Error: colors.json not found at {COLORS_JSON}")
        sys.exit(1)

    # Read pywal colors
    with open(COLORS_JSON) as f:
        colors = json.load(f)

    colors_dict = colors.get("colors", {})
    special = colors.get("special", {})

    # Create dynamic profile structure
    dynamic_profile = {
        "Profiles": [
            {
                "Name": "wal",
                "Guid": "wal-dynamic-profile-uuid",
                "Rewritable": True,
            }
        ]
    }

    profile = dynamic_profile["Profiles"][0]

    # Add ANSI colors (0-15)
    for i in range(16):
        color_key = f"color{i}"
        hex_color = colors_dict.get(color_key, "#000000")
        r, g, b = hex_to_rgb(hex_color)
        profile[f"Ansi {i} Color"] = {
            "Color Space": "sRGB",
            "Red Component": r,
            "Green Component": g,
            "Blue Component": b,
            "Alpha Component": 1.0,
        }

    # Add special colors
    profile["Background Color"] = {
        "Color Space": "sRGB",
        "Red Component": hex_to_rgb(special.get("background", "#000000"))[0],
        "Green Component": hex_to_rgb(special.get("background", "#000000"))[1],
        "Blue Component": hex_to_rgb(special.get("background", "#000000"))[2],
        "Alpha Component": 1.0,
    }

    profile["Foreground Color"] = {
        "Color Space": "sRGB",
        "Red Component": hex_to_rgb(special.get("foreground", "#ffffff"))[0],
        "Green Component": hex_to_rgb(special.get("foreground", "#ffffff"))[1],
        "Blue Component": hex_to_rgb(special.get("foreground", "#ffffff"))[2],
        "Alpha Component": 1.0,
    }

    profile["Cursor Color"] = {
        "Color Space": "sRGB",
        "Red Component": hex_to_rgb(special.get("cursor", "#ffffff"))[0],
        "Green Component": hex_to_rgb(special.get("cursor", "#ffffff"))[1],
        "Blue Component": hex_to_rgb(special.get("cursor", "#ffffff"))[2],
        "Alpha Component": 1.0,
    }

    # Write the dynamic profile
    dynamic_profiles_dir = Path.home() / "Library/Application Support/iTerm2/DynamicProfiles"
    dynamic_profiles_dir.mkdir(parents=True, exist_ok=True)
    profile_file = dynamic_profiles_dir / "wal-profile.json"

    with open(profile_file, 'w') as f:
        json.dump(dynamic_profile, f, indent=2)

    print(f"✓ Dynamic profile created/updated: {profile_file}")
    print("✓ iTerm2 will automatically detect the changes")
    print("\nTo use: Switch to the 'wal' profile in iTerm2")
    print("Future runs will update the 'wal' profile automatically")


def main():
    """Main function."""
    image_path = sys.argv[1] if len(sys.argv) > 1 else None

    run_wal(image_path, backend="haishoku")
    create_dynamic_profile()

    print("\n✓ Done! Dynamic profile 'wal' updated with new colors.")


if __name__ == "__main__":
    main()