From 9b7792be9a14b2fbaab0648762c7b395a3bc35c5 Mon Sep 17 00:00:00 2001
From: Sundance <ahmetrustuygt@gmail.com>
Date: Mon, 31 Mar 2025 19:12:49 +0000
Subject: [PATCH] scripts/debug: Add debugging helper tool.

---
 README.md                             |  40 +++++++
 makefile                              |  16 ++-
 setup.py                              |   3 +
 zulipterminal/scripts/debug_helper.py | 164 ++++++++++++++++++++++++++
 4 files changed, 222 insertions(+), 1 deletion(-)
 create mode 100644 zulipterminal/scripts/debug_helper.py

diff --git a/README.md b/README.md
index c0395a2e05..d5a5deac25 100644
--- a/README.md
+++ b/README.md
@@ -799,6 +799,46 @@ $ telnet 127.0.0.1 6899
 in another terminal, where `127.0.0.1` is the IP address and `6899` is port you
 find in `./debug.log`.
 
+#### Remote debugging example
+
+Here's a complete example of how to debug a specific issue:
+
+1. Let's say you suspect an issue when sending messages. Find the function in the codebase that handles this (e.g., in `zulipterminal/ui/ui.py`).
+
+2. Add the debugger statement just before the suspicious code:
+   ```python
+   def send_message(self):
+       from pudb.remote import set_trace
+       set_trace()  # This will pause execution here
+       # Rest of the function...
+   ```
+
+3. Run Zulip Terminal with debug mode enabled:
+   ```bash
+   zulip-term -d
+   ```
+
+4. When you trigger the send_message function, check debug.log for telnet connection details:
+   ```bash
+   tail -f debug.log
+   ```
+
+5. Connect with telnet and you'll get an interactive debugger to step through the code.
+
+#### Profiling for performance issues
+
+If you're experiencing performance problems, you can run Zulip Terminal with profiling enabled:
+
+```bash
+zulip-term --profile
+```
+
+This will create a profile output file which you can analyze using:
+
+```bash
+snakeviz zulip-terminal.prof
+```
+
 #### There's no effect in Zulip Terminal after making local changes!
 
 This likely means that you have installed both normal and development versions
diff --git a/makefile b/makefile
index 13119cbe59..5759ebb918 100644
--- a/makefile
+++ b/makefile
@@ -1,4 +1,4 @@
-.PHONY: install-devel check lint test check-clean-tree fix force-fix venv
+.PHONY: install-devel check lint test check-clean-tree fix force-fix venv debug debug-profile debug-clean
 
 # NOTE: ZT_VENV and BASEPYTHON are advanced undocumented features
 # Customize your venv name by running make as "ZT_VENV=my_venv_name make <command>"
@@ -24,6 +24,20 @@ lint: venv
 test: venv
 	@pytest
 
+### DEBUG TARGETS ###
+
+debug: venv
+	@echo "=== Running with debug enabled ==="
+	$(PYTHON) -m zulipterminal.cli.run -d
+
+debug-profile: venv
+	@echo "=== Running with profiling enabled ==="
+	$(PYTHON) -m zulipterminal.cli.run --profile
+
+debug-clean:
+	@echo "=== Cleaning debug files ==="
+	rm -f debug.log zulip-terminal.prof zulip-terminal-tracebacks.log
+
 ### FIX FILES ###
 
 check-clean-tree:
diff --git a/setup.py b/setup.py
index 168f33dd33..85701dfa50 100644
--- a/setup.py
+++ b/setup.py
@@ -54,6 +54,7 @@ def long_description():
 helper_deps = [
     "pudb==2022.1.1",
     "snakeviz>=2.1.1",
+    "requests>=2.25.0",  # Added for debug_helper.py
 ]
 
 setup(
@@ -93,6 +94,8 @@ def long_description():
         "console_scripts": [
             "zulip-term = zulipterminal.cli.run:main",
             "zulip-term-check-symbols = zulipterminal.scripts.render_symbols:main",
+            # Added debug helper with proper path
+            "zulip-term-debug = zulipterminal.scripts.debug_helper:main",
         ],
     },
     extras_require={
diff --git a/zulipterminal/scripts/debug_helper.py b/zulipterminal/scripts/debug_helper.py
new file mode 100644
index 0000000000..73ddd007a2
--- /dev/null
+++ b/zulipterminal/scripts/debug_helper.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python3
+"""
+Helper script for debugging Zulip Terminal.
+
+This script provides utilities for common debugging tasks:
+1. Analyzing debug logs
+2. Testing connectivity to Zulip server
+3. Checking terminal capabilities
+"""
+
+import argparse
+import json
+import logging
+import os
+import re
+import subprocess
+from typing import Optional
+
+
+# Configure logging
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+
+def analyze_debug_log(log_file: str = "debug.log") -> None:
+    """
+    Analyze a debug log file for common issues.
+    """
+    if not os.path.exists(log_file):
+        logger.error("Log file '%s' not found", log_file)
+        return
+
+    logger.info("Analyzing %s...", log_file)
+    with open(log_file, "r") as f:
+        content = f.read()
+
+    # Look for error patterns
+    error_patterns = [r"ERROR", r"Exception", r"Traceback", r"Failed to"]
+
+    errors_found = False
+    for pattern in error_patterns:
+        matches = re.finditer(pattern, content, re.IGNORECASE)
+        for match in matches:
+            line_start = content.rfind("\n", 0, match.start()) + 1
+            line_end = content.find("\n", match.end())
+            if line_end == -1:
+                line_end = len(content)
+
+            line = content[line_start:line_end].strip()
+            logger.warning("Potential issue found: %s", line)
+            errors_found = True
+
+    if not errors_found:
+        logger.info("No obvious errors found in the log file.")
+
+
+def test_connectivity(server_url: Optional[str] = None) -> None:
+    """
+    Test connectivity to a Zulip server.
+    """
+    if not server_url:
+        # Try to get server URL from zuliprc
+        zuliprc_path = os.path.expanduser("~/.zuliprc")
+        if os.path.exists(zuliprc_path):
+            with open(zuliprc_path, "r") as f:
+                for line in f:
+                    if line.startswith("site="):
+                        server_url = line.split("=")[1].strip()
+                        break
+
+    if not server_url:
+        logger.error("No server URL provided and couldn't find one in ~/.zuliprc")
+        return
+
+    logger.info("Testing connectivity to %s...", server_url)
+    try:
+        import requests
+
+        response = requests.get(f"{server_url}/api/v1/server_settings")
+        if response.status_code == 200:
+            logger.info("Successfully connected to %s", server_url)
+            try:
+                settings = response.json()
+                logger.info(
+                    "Server version: %s", settings.get("zulip_version", "unknown")
+                )
+            except json.JSONDecodeError:
+                logger.error("Received response, but couldn't parse as JSON")
+        else:
+            logger.error("Failed to connect: HTTP status %s", response.status_code)
+    except Exception as e:
+        logger.error("Connection error: %s", e)
+
+
+def check_terminal_capabilities() -> None:
+    """
+    Check for terminal capabilities that might affect Zulip Terminal.
+    """
+    logger.info("Checking terminal capabilities...")
+
+    # Check for color support
+    colors = os.environ.get("TERM", "unknown")
+    logger.info("TERM environment: %s", colors)
+
+    if "COLORTERM" in os.environ:
+        logger.info("COLORTERM: %s", os.environ["COLORTERM"])
+
+    # Check for Unicode support
+    logger.info("Testing Unicode rendering capabilities:")
+    test_chars = [
+        ("Basic symbols", "▶ ◀ ✓ ✗"),
+        ("Emoji (simple)", "😀 🙂 👍"),
+        ("Box drawing", "│ ┌ ┐ └ ┘ ├ ┤ ┬ ┴ ┼"),
+        ("Math symbols", "∞ ∑ √ ∫ π"),
+    ]
+
+    for name, chars in test_chars:
+        logger.info("  %s: %s", name, chars)
+
+
+def main() -> None:
+    """
+    Main entry point for the debugging helper.
+    """
+    parser = argparse.ArgumentParser(description="Zulip Terminal Debugging Helper")
+    subparsers = parser.add_subparsers(dest="command", help="Command to run")
+
+    # Log analyzer
+    log_parser = subparsers.add_parser("log", help="Analyze debug logs")
+    log_parser.add_argument("--file", default="debug.log", help="Log file to analyze")
+
+    # Connectivity test
+    conn_parser = subparsers.add_parser("connect", help="Test connectivity")
+    conn_parser.add_argument(
+        "--server", help="Server URL (e.g., https://chat.zulip.org)"
+    )
+
+    # Terminal test
+    subparsers.add_parser("terminal", help="Check terminal capabilities")
+
+    # Run zulip-term with debug
+    run_parser = subparsers.add_parser("run", help="Run zulip-term with debugging")
+    run_parser.add_argument("--profile", action="store_true", help="Enable profiling")
+
+    args = parser.parse_args()
+
+    if args.command == "log":
+        analyze_debug_log(args.file)
+    elif args.command == "connect":
+        test_connectivity(args.server)
+    elif args.command == "terminal":
+        check_terminal_capabilities()
+    elif args.command == "run":
+        cmd = ["zulip-term", "-d"]
+        if args.profile:
+            cmd.append("--profile")
+        logger.info("Running: %s", " ".join(cmd))
+        subprocess.run(cmd, check=False)
+    else:
+        parser.print_help()
+
+
+if __name__ == "__main__":
+    main()