Created
January 21, 2026 19:53
-
-
Save scjudd/927f74bb348a7b636c3c07165ebb03d0 to your computer and use it in GitHub Desktop.
iTerm2 script to automatically adjust font size and window dimensions when entering/exiting fullscreen
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| """ | |
| iTerm2 Fullscreen Font Size Automation | |
| Automatically sets font size to 18pt when entering fullscreen and 12pt when | |
| exiting fullscreen. Resets window to 80x25 when exiting fullscreen. | |
| Setup: | |
| 1. Enable Python API in iTerm2: | |
| Preferences > General > Magic > Enable Python API | |
| 2. Install Python Runtime (if not already installed): | |
| Scripts > Manage > Install Python Runtime | |
| 3. Create the AutoLaunch folder (if it doesn't exist): | |
| mkdir -p ~/Library/Application\ Support/iTerm2/Scripts/AutoLaunch | |
| 4. Copy this script to the AutoLaunch folder: | |
| cp fullscreen_font_size.py ~/Library/Application\ Support/iTerm2/Scripts/AutoLaunch/ | |
| 5. Restart iTerm2 or run the script manually: | |
| Scripts > AutoLaunch > fullscreen_font_size | |
| Verification: | |
| - Check script is running: Scripts > Manage > Console | |
| - Press Cmd+Enter to toggle fullscreen and verify font size changes | |
| - Works independently for multiple windows | |
| Configuration: | |
| Adjust the constants below to customize font sizes and window dimensions. | |
| """ | |
| import asyncio | |
| import iterm2 | |
| import re | |
| FULLSCREEN_FONT_SIZE = 18 | |
| WINDOWED_FONT_SIZE = 12 | |
| WINDOWED_COLUMNS = 80 | |
| WINDOWED_ROWS = 25 | |
| FONT_REGEX = re.compile(r'^(.*) (\d+)(.*)$') | |
| # Track which windows are currently in fullscreen | |
| fullscreen_windows: dict[str, bool] = {} | |
| def set_font_size(font_string: str, new_size: int) -> str: | |
| """Replace the font size in an iTerm2 font string.""" | |
| match = FONT_REGEX.match(font_string) | |
| if match: | |
| return f"{match.group(1)} {new_size}{match.group(3)}" | |
| return font_string | |
| async def is_fullscreen(window: iterm2.Window) -> bool: | |
| """Check if window is in fullscreen mode.""" | |
| style = await window.async_get_variable("style") | |
| return style in ("native full screen", "non-native full screen") | |
| async def set_window_font_size(window: iterm2.Window, size: int): | |
| """Set font size for all sessions in a window.""" | |
| for tab in window.tabs: | |
| for session in tab.sessions: | |
| profile = await session.async_get_profile() | |
| current_font = profile.normal_font | |
| new_font = set_font_size(current_font, size) | |
| await profile.async_set_normal_font(new_font) | |
| async def set_window_grid_size(window: iterm2.Window, columns: int, rows: int): | |
| """Set window size to specified columns and rows.""" | |
| for tab in window.tabs: | |
| for session in tab.sessions: | |
| await session.async_set_grid_size(iterm2.Size(columns, rows)) | |
| async def check_window_fullscreen(window: iterm2.Window): | |
| """Check and update fullscreen state for a window.""" | |
| window_id = window.window_id | |
| currently_fullscreen = await is_fullscreen(window) | |
| was_fullscreen = fullscreen_windows.get(window_id, False) | |
| if currently_fullscreen and not was_fullscreen: | |
| await set_window_font_size(window, FULLSCREEN_FONT_SIZE) | |
| fullscreen_windows[window_id] = True | |
| elif not currently_fullscreen and was_fullscreen: | |
| await set_window_font_size(window, WINDOWED_FONT_SIZE) | |
| await set_window_grid_size(window, WINDOWED_COLUMNS, WINDOWED_ROWS) | |
| fullscreen_windows[window_id] = False | |
| async def monitor_window(connection: iterm2.Connection, window: iterm2.Window): | |
| """Monitor a single window for style changes.""" | |
| window_id = window.window_id | |
| # Initialize state | |
| fullscreen_windows[window_id] = await is_fullscreen(window) | |
| try: | |
| async with iterm2.VariableMonitor( | |
| connection, | |
| iterm2.VariableScopes.WINDOW, | |
| "style", | |
| window_id | |
| ) as monitor: | |
| while True: | |
| await monitor.async_get() | |
| app = await iterm2.async_get_app(connection) | |
| window = app.get_window_by_id(window_id) | |
| if window is None: | |
| break | |
| await check_window_fullscreen(window) | |
| except asyncio.CancelledError: | |
| pass | |
| finally: | |
| fullscreen_windows.pop(window_id, None) | |
| async def main(connection: iterm2.Connection): | |
| app = await iterm2.async_get_app(connection) | |
| # Track monitor tasks for each window | |
| monitor_tasks: dict[str, asyncio.Task] = {} | |
| def start_monitoring_window(window: iterm2.Window): | |
| """Start monitoring a window if not already monitoring.""" | |
| window_id = window.window_id | |
| if window_id not in monitor_tasks: | |
| task = asyncio.create_task(monitor_window(connection, window)) | |
| monitor_tasks[window_id] = task | |
| # Start monitoring existing windows | |
| for window in app.windows: | |
| start_monitoring_window(window) | |
| # Monitor for new windows | |
| async with iterm2.FocusMonitor(connection) as monitor: | |
| while True: | |
| update = await monitor.async_get_next_update() | |
| # Check for new windows when focus changes | |
| app = await iterm2.async_get_app(connection) | |
| current_window_ids = {w.window_id for w in app.windows} | |
| # Start monitoring any new windows | |
| for window in app.windows: | |
| start_monitoring_window(window) | |
| # Clean up tasks for closed windows | |
| closed_windows = set(monitor_tasks.keys()) - current_window_ids | |
| for window_id in closed_windows: | |
| task = monitor_tasks.pop(window_id, None) | |
| if task: | |
| task.cancel() | |
| iterm2.run_forever(main) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment