fastled 1.4.33__tar.gz → 1.4.35__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. {fastled-1.4.33 → fastled-1.4.35}/PKG-INFO +1 -1
  2. fastled-1.4.35/requirements.docker.txt +1 -0
  3. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/__init__.py +2 -1
  4. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/__version__.py +1 -1
  5. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/app.py +2 -1
  6. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/client_server.py +11 -6
  7. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/compile_server_impl.py +2 -1
  8. fastled-1.4.35/src/fastled/emoji_util.py +27 -0
  9. fastled-1.4.35/src/fastled/install/vscode_config.py +344 -0
  10. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/test/examples.py +7 -5
  11. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/web_compile.py +13 -3
  12. {fastled-1.4.33 → fastled-1.4.35}/src/fastled.egg-info/PKG-INFO +1 -1
  13. {fastled-1.4.33 → fastled-1.4.35}/src/fastled.egg-info/SOURCES.txt +1 -0
  14. {fastled-1.4.33 → fastled-1.4.35}/tests/integration/test_libcompile.py +43 -34
  15. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_bad_ino.py +8 -7
  16. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_debug_fetch_source_files.py +3 -1
  17. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_webcompile.py +3 -2
  18. fastled-1.4.33/requirements.docker.txt +0 -1
  19. fastled-1.4.33/src/fastled/install/vscode_config.py +0 -167
  20. {fastled-1.4.33 → fastled-1.4.35}/.aiderignore +0 -0
  21. {fastled-1.4.33 → fastled-1.4.35}/.cursorrules +0 -0
  22. {fastled-1.4.33 → fastled-1.4.35}/.dockerignore +0 -0
  23. {fastled-1.4.33 → fastled-1.4.35}/.github/workflows/build_multi_docker_image.yml +0 -0
  24. {fastled-1.4.33 → fastled-1.4.35}/.github/workflows/build_webpage.yml +0 -0
  25. {fastled-1.4.33 → fastled-1.4.35}/.github/workflows/lint.yml +0 -0
  26. {fastled-1.4.33 → fastled-1.4.35}/.github/workflows/publish_release.yml +0 -0
  27. {fastled-1.4.33 → fastled-1.4.35}/.github/workflows/template_build_docker_image.yml +0 -0
  28. {fastled-1.4.33 → fastled-1.4.35}/.github/workflows/test_build_exe.yml +0 -0
  29. {fastled-1.4.33 → fastled-1.4.35}/.github/workflows/test_macos.yml +0 -0
  30. {fastled-1.4.33 → fastled-1.4.35}/.github/workflows/test_ubuntu.yml +0 -0
  31. {fastled-1.4.33 → fastled-1.4.35}/.github/workflows/test_win.yml +0 -0
  32. {fastled-1.4.33 → fastled-1.4.35}/.gitignore +0 -0
  33. {fastled-1.4.33 → fastled-1.4.35}/.pylintrc +0 -0
  34. {fastled-1.4.33 → fastled-1.4.35}/.vscode/launch.json +0 -0
  35. {fastled-1.4.33 → fastled-1.4.35}/.vscode/settings.json +0 -0
  36. {fastled-1.4.33 → fastled-1.4.35}/.vscode/tasks.json +0 -0
  37. {fastled-1.4.33 → fastled-1.4.35}/DEBUGGER.md +0 -0
  38. {fastled-1.4.33 → fastled-1.4.35}/Dockerfile +0 -0
  39. {fastled-1.4.33 → fastled-1.4.35}/FAQ.md +0 -0
  40. {fastled-1.4.33 → fastled-1.4.35}/LICENSE +0 -0
  41. {fastled-1.4.33 → fastled-1.4.35}/MANIFEST.in +0 -0
  42. {fastled-1.4.33 → fastled-1.4.35}/README.md +0 -0
  43. {fastled-1.4.33 → fastled-1.4.35}/RELEASE.md +0 -0
  44. {fastled-1.4.33 → fastled-1.4.35}/TODO.md +0 -0
  45. {fastled-1.4.33 → fastled-1.4.35}/build_exe.py +0 -0
  46. {fastled-1.4.33 → fastled-1.4.35}/build_local_docker.py +0 -0
  47. {fastled-1.4.33 → fastled-1.4.35}/build_site.py +0 -0
  48. {fastled-1.4.33 → fastled-1.4.35}/chrome_vscode_bridge_design_task.md +0 -0
  49. {fastled-1.4.33 → fastled-1.4.35}/clean +0 -0
  50. {fastled-1.4.33 → fastled-1.4.35}/compiler/debug.sh +0 -0
  51. {fastled-1.4.33 → fastled-1.4.35}/compiler/run.py +0 -0
  52. {fastled-1.4.33 → fastled-1.4.35}/demo/100dots.html +0 -0
  53. {fastled-1.4.33 → fastled-1.4.35}/demo/demo_threejs.html +0 -0
  54. {fastled-1.4.33 → fastled-1.4.35}/demo/micdemo.html +0 -0
  55. {fastled-1.4.33 → fastled-1.4.35}/demo/mp3upload.html +0 -0
  56. {fastled-1.4.33 → fastled-1.4.35}/demo/webgl_postprocessing_unreal_bloom.html +0 -0
  57. {fastled-1.4.33 → fastled-1.4.35}/docker-compose.yml +0 -0
  58. {fastled-1.4.33 → fastled-1.4.35}/entrypoint.sh +0 -0
  59. {fastled-1.4.33 → fastled-1.4.35}/install +0 -0
  60. {fastled-1.4.33 → fastled-1.4.35}/install_linux.sh +0 -0
  61. {fastled-1.4.33 → fastled-1.4.35}/lint +0 -0
  62. {fastled-1.4.33 → fastled-1.4.35}/pyproject.toml +0 -0
  63. {fastled-1.4.33 → fastled-1.4.35}/requirements.testing.txt +0 -0
  64. {fastled-1.4.33 → fastled-1.4.35}/setup.cfg +0 -0
  65. {fastled-1.4.33 → fastled-1.4.35}/setup.py +0 -0
  66. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/__main__.py +0 -0
  67. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/args.py +0 -0
  68. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/assets/example.txt +0 -0
  69. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/assets/localhost-key.pem +0 -0
  70. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/assets/localhost.pem +0 -0
  71. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/cli.py +0 -0
  72. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/cli_test.py +0 -0
  73. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/cli_test_interactive.py +0 -0
  74. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/compile_server.py +0 -0
  75. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/docker_manager.py +0 -0
  76. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/filewatcher.py +0 -0
  77. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/find_good_connection.py +0 -0
  78. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/install/__init__.py +0 -0
  79. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/install/examples_manager.py +0 -0
  80. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/install/extension_manager.py +0 -0
  81. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/install/main.py +0 -0
  82. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/install/project_detection.py +0 -0
  83. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/install/test_install.py +0 -0
  84. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/interruptible_http.py +0 -0
  85. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/keyboard.py +0 -0
  86. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/keyz.py +0 -0
  87. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/live_client.py +0 -0
  88. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/open_browser.py +0 -0
  89. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/parse_args.py +0 -0
  90. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/paths.py +0 -0
  91. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/playwright/chrome_extension_downloader.py +0 -0
  92. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/playwright/playwright_browser.py +0 -0
  93. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/playwright/resize_tracking.py +0 -0
  94. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/print_filter.py +0 -0
  95. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/project_init.py +0 -0
  96. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/select_sketch_directory.py +0 -0
  97. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/server_flask.py +0 -0
  98. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/server_start.py +0 -0
  99. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/settings.py +0 -0
  100. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/site/build.py +0 -0
  101. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/site/examples.py +0 -0
  102. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/sketch.py +0 -0
  103. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/spinner.py +0 -0
  104. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/string_diff.py +0 -0
  105. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/test/can_run_local_docker_tests.py +0 -0
  106. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/types.py +0 -0
  107. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/util.py +0 -0
  108. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/version.py +0 -0
  109. {fastled-1.4.33 → fastled-1.4.35}/src/fastled/zip_files.py +0 -0
  110. {fastled-1.4.33 → fastled-1.4.35}/src/fastled.egg-info/dependency_links.txt +0 -0
  111. {fastled-1.4.33 → fastled-1.4.35}/src/fastled.egg-info/entry_points.txt +0 -0
  112. {fastled-1.4.33 → fastled-1.4.35}/src/fastled.egg-info/requires.txt +0 -0
  113. {fastled-1.4.33 → fastled-1.4.35}/src/fastled.egg-info/top_level.txt +0 -0
  114. {fastled-1.4.33 → fastled-1.4.35}/task.md +0 -0
  115. {fastled-1.4.33 → fastled-1.4.35}/task2.md +0 -0
  116. {fastled-1.4.33 → fastled-1.4.35}/test +0 -0
  117. {fastled-1.4.33 → fastled-1.4.35}/tests/integration/test_build_examples.py +0 -0
  118. {fastled-1.4.33 → fastled-1.4.35}/tests/integration/test_examples.py +0 -0
  119. {fastled-1.4.33 → fastled-1.4.35}/tests/integration/test_playwright_integration.py +0 -0
  120. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/html/index.html +0 -0
  121. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_api.py +0 -0
  122. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_banner_string.py +0 -0
  123. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_cli.py +0 -0
  124. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_cli_no_platformio.py +0 -0
  125. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_compile_server.py +0 -0
  126. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_docker_linux_on_windows.py +0 -0
  127. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_embedded_data.py +0 -0
  128. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_filechanger.py +0 -0
  129. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_flask_headers.py +0 -0
  130. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_http_server.py +0 -0
  131. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_ino/bad/bad.ino +0 -0
  132. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_ino/bad_platformio/bad_platformio.ino +0 -0
  133. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_ino/bad_platformio/platformio.ini +0 -0
  134. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_ino/embedded/data/bigdata.dat +0 -0
  135. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_ino/embedded/wasm.ino +0 -0
  136. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_ino/wasm/wasm.ino +0 -0
  137. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_manual_api_invocation.py +0 -0
  138. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_no_platformio_compile.py +0 -0
  139. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_project_init.py +0 -0
  140. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_server_and_client_seperatly.py +0 -0
  141. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_session_compile.py +0 -0
  142. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_string_diff.py +0 -0
  143. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_string_diff_comprehensive.py +0 -0
  144. {fastled-1.4.33 → fastled-1.4.35}/tests/unit/test_version.py +0 -0
  145. {fastled-1.4.33 → fastled-1.4.35}/upload_package.sh +0 -0
  146. {fastled-1.4.33 → fastled-1.4.35}/vscode-plugin/readme +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastled
3
- Version: 1.4.33
3
+ Version: 1.4.35
4
4
  Summary: FastLED Wasm Compiler
5
5
  Home-page: https://github.com/zackees/fastled-wasm
6
6
  Maintainer: Zachary Vorhies
@@ -0,0 +1 @@
1
+ fastled-wasm-server>=1.1.39
@@ -7,6 +7,7 @@ from typing import Generator
7
7
 
8
8
  from .__version__ import __version__
9
9
  from .compile_server import CompileServer
10
+ from .emoji_util import EMO
10
11
  from .live_client import LiveClient
11
12
  from .settings import DOCKER_FILE, IMAGE_NAME
12
13
  from .site.build import build
@@ -54,7 +55,7 @@ class Api:
54
55
  allow_libcompile = looks_like_fastled_repo(Path(".").resolve())
55
56
  if not allow_libcompile:
56
57
  print(
57
- "⚠️ libfastled compilation disabled: not running in FastLED repository"
58
+ f"{EMO('⚠️', 'WARNING:')} libfastled compilation disabled: not running in FastLED repository"
58
59
  )
59
60
 
60
61
  out: CompileResult = web_compile(
@@ -1,6 +1,6 @@
1
1
  # IMPORTANT! There's a bug in github which will REJECT any version update
2
2
  # that has any other change in the repo. Please bump the version as the
3
3
  # ONLY change in a commit, or else the pypi update and the release will fail.
4
- __version__ = "1.4.33"
4
+ __version__ = "1.4.35"
5
5
 
6
6
  __version_url_latest__ = "https://raw.githubusercontent.com/zackees/fastled-wasm/refs/heads/main/src/fastled/__version__.py"
@@ -9,6 +9,7 @@ from pathlib import Path
9
9
 
10
10
  from fastled.client_server import run_client_server
11
11
  from fastled.compile_server import CompileServer
12
+ from fastled.emoji_util import EMO
12
13
  from fastled.filewatcher import file_watcher_set
13
14
  from fastled.parse_args import Args, parse_args
14
15
  from fastled.sketch import find_sketch_directories, looks_like_fastled_repo
@@ -79,7 +80,7 @@ def main() -> int:
79
80
  # Check if Playwright browsers are installed
80
81
  playwright_dir = Path.home() / ".fastled" / "playwright"
81
82
  if playwright_dir.exists() and any(playwright_dir.iterdir()):
82
- print(f"🎭 Playwright browsers available at: {playwright_dir}")
83
+ print(f"{EMO('🎭', '*')} Playwright browsers available at: {playwright_dir}")
83
84
 
84
85
  # Resolve some of the last interactive arguments
85
86
  # 1. If interactive is set and the sketch directory is not given,
@@ -10,6 +10,7 @@ from pathlib import Path
10
10
 
11
11
  from fastled.compile_server import CompileServer
12
12
  from fastled.docker_manager import DockerManager
13
+ from fastled.emoji_util import EMO
13
14
  from fastled.filewatcher import DebouncedFileWatcherProcess, FileWatcherProcess
14
15
  from fastled.find_good_connection import ConnectionResult
15
16
  from fastled.keyboard import SpaceBarWatcher
@@ -100,7 +101,7 @@ def _run_web_compiler(
100
101
 
101
102
  # Guard: libfastled compilation requires volume source mapping
102
103
  if not allow_libcompile:
103
- print("⚠️ libfastled compilation disabled.")
104
+ print(f"{EMO('⚠️', 'WARNING:')} libfastled compilation disabled.")
104
105
 
105
106
  start = time.time()
106
107
  web_result = web_compile(
@@ -283,16 +284,20 @@ def _background_update_docker_image() -> None:
283
284
  image_name=IMAGE_NAME, tag="latest", upgrade=True
284
285
  )
285
286
  if updated:
286
- print("✅ Background docker image update completed successfully.")
287
+ print(
288
+ f"{EMO('✅', 'SUCCESS:')} Background docker image update completed successfully."
289
+ )
287
290
  else:
288
- print("ℹ️ Docker image was already up to date.")
291
+ print(f"{EMO('ℹ️', 'INFO:')} Docker image was already up to date.")
289
292
  except KeyboardInterrupt:
290
- print("⚠️ Background docker image update interrupted by user.")
293
+ print(
294
+ f"{EMO('⚠️', 'WARNING:')} Background docker image update interrupted by user."
295
+ )
291
296
  import _thread
292
297
 
293
298
  _thread.interrupt_main()
294
299
  except Exception as e:
295
- print(f"⚠️ Background docker image update failed: {e}")
300
+ print(f"{EMO('⚠️', 'WARNING:')} Background docker image update failed: {e}")
296
301
 
297
302
 
298
303
  def _is_local_host(url: str) -> bool:
@@ -365,7 +370,7 @@ def run_client(
365
370
  # Auto-detect libcompile capability on first call
366
371
  from fastled.sketch import looks_like_fastled_repo
367
372
 
368
- allow_libcompile = looks_like_fastled_repo(Path(".").resolve())
373
+ allow_libcompile = is_local_host and looks_like_fastled_repo(Path(".").resolve())
369
374
 
370
375
  try:
371
376
 
@@ -15,6 +15,7 @@ from fastled.docker_manager import (
15
15
  RunningContainer,
16
16
  Volume,
17
17
  )
18
+ from fastled.emoji_util import EMO
18
19
  from fastled.settings import DEFAULT_CONTAINER_NAME, IMAGE_NAME, SERVER_PORT
19
20
  from fastled.sketch import looks_like_fastled_repo
20
21
  from fastled.types import BuildMode, CompileResult, CompileServerError
@@ -76,7 +77,7 @@ class CompileServerImpl:
76
77
  # If we don't have fastled_src_dir (not in FastLED repo), disable libcompile
77
78
  if allow_libcompile and self.fastled_src_dir is None:
78
79
  print(
79
- "⚠️ libfastled compilation disabled: volume source mapping not available"
80
+ f"{EMO('⚠️', 'WARNING:')} libfastled compilation disabled: volume source mapping not available"
80
81
  )
81
82
  print(" (not running in FastLED repository)")
82
83
  allow_libcompile = False
@@ -0,0 +1,27 @@
1
+ """
2
+ Emoji utility functions for handling Unicode display issues on Windows cmd.exe
3
+ """
4
+
5
+ import sys
6
+
7
+
8
+ def EMO(emoji: str, fallback: str) -> str:
9
+ """Get emoji with fallback for systems that don't support Unicode properly"""
10
+ try:
11
+ # Test if we can encode the emoji properly
12
+ emoji.encode(sys.stdout.encoding or "utf-8")
13
+ return emoji
14
+ except (UnicodeEncodeError, AttributeError):
15
+ return fallback
16
+
17
+
18
+ def safe_print(text: str) -> None:
19
+ """Print text safely, handling Unicode/emoji encoding issues on Windows cmd.exe"""
20
+ try:
21
+ print(text)
22
+ except UnicodeEncodeError:
23
+ # Replace problematic characters with safe alternatives
24
+ safe_text = text.encode(
25
+ sys.stdout.encoding or "utf-8", errors="replace"
26
+ ).decode(sys.stdout.encoding or "utf-8")
27
+ print(safe_text)
@@ -0,0 +1,344 @@
1
+ """VSCode configuration generation for FastLED projects."""
2
+
3
+ import json
4
+ from pathlib import Path
5
+
6
+
7
+ def update_launch_json_for_arduino() -> None:
8
+ """Update launch.json with Arduino debugging configuration."""
9
+ launch_json_path = Path.cwd() / ".vscode" / "launch.json"
10
+
11
+ # Default launch configuration
12
+ arduino_config = {
13
+ "name": "🎯 Auto Debug (Smart File Detection)",
14
+ "type": "auto-debug",
15
+ "request": "launch",
16
+ "map": {
17
+ "*.ino": "Arduino: Run .ino with FastLED",
18
+ "*.py": "Python: Current File (UV)",
19
+ },
20
+ }
21
+
22
+ if launch_json_path.exists():
23
+ # Merge with existing
24
+ try:
25
+ with open(launch_json_path, "r") as f:
26
+ data = json.load(f)
27
+ except json.JSONDecodeError:
28
+ data = {"version": "0.2.0", "configurations": []}
29
+ else:
30
+ data = {"version": "0.2.0", "configurations": []}
31
+
32
+ # Check if configuration already exists
33
+ configs = data.get("configurations", [])
34
+ exists = any(cfg.get("name") == arduino_config["name"] for cfg in configs)
35
+
36
+ if not exists:
37
+ configs.insert(0, arduino_config) # Add at the beginning
38
+ data["configurations"] = configs
39
+
40
+ # Write back
41
+ launch_json_path.parent.mkdir(exist_ok=True)
42
+ with open(launch_json_path, "w") as f:
43
+ json.dump(data, f, indent=4)
44
+
45
+ print(f"✅ Updated {launch_json_path}")
46
+
47
+
48
+ def generate_fastled_tasks() -> None:
49
+ """Generate/update tasks.json with FastLED build tasks."""
50
+ tasks_json_path = Path.cwd() / ".vscode" / "tasks.json"
51
+
52
+ # FastLED tasks
53
+ fastled_tasks = [
54
+ {
55
+ "type": "shell",
56
+ "label": "Run FastLED (Debug)",
57
+ "command": "fastled",
58
+ "args": ["${file}", "--debug", "--app"],
59
+ "options": {"cwd": "${workspaceFolder}"},
60
+ "group": {"kind": "build", "isDefault": True},
61
+ "presentation": {
62
+ "echo": True,
63
+ "reveal": "always",
64
+ "focus": True,
65
+ "panel": "new",
66
+ "showReuseMessage": False,
67
+ "clear": True,
68
+ },
69
+ "detail": "Run FastLED with debug mode and app visualization",
70
+ "problemMatcher": [],
71
+ },
72
+ {
73
+ "type": "shell",
74
+ "label": "Run FastLED (Quick)",
75
+ "command": "fastled",
76
+ "args": ["${file}", "--background-update"],
77
+ "options": {"cwd": "${workspaceFolder}"},
78
+ "group": "build",
79
+ "presentation": {
80
+ "echo": True,
81
+ "reveal": "always",
82
+ "focus": True,
83
+ "panel": "new",
84
+ "showReuseMessage": False,
85
+ "clear": True,
86
+ },
87
+ "detail": "Run FastLED with quick background update mode",
88
+ "problemMatcher": [],
89
+ },
90
+ ]
91
+
92
+ if tasks_json_path.exists():
93
+ # Merge with existing
94
+ try:
95
+ with open(tasks_json_path, "r") as f:
96
+ data = json.load(f)
97
+ except json.JSONDecodeError:
98
+ data = {"version": "2.0.0", "tasks": []}
99
+ else:
100
+ data = {"version": "2.0.0", "tasks": []}
101
+
102
+ # Get existing tasks
103
+ existing_tasks = data.get("tasks", [])
104
+ existing_labels = {task.get("label") for task in existing_tasks}
105
+
106
+ # Add new tasks if they don't exist
107
+ for task in fastled_tasks:
108
+ if task["label"] not in existing_labels:
109
+ existing_tasks.append(task)
110
+
111
+ data["tasks"] = existing_tasks
112
+
113
+ # Write back
114
+ tasks_json_path.parent.mkdir(exist_ok=True)
115
+ with open(tasks_json_path, "w") as f:
116
+ json.dump(data, f, indent=4)
117
+
118
+ print(f"✅ Updated {tasks_json_path}")
119
+
120
+
121
+ def update_vscode_settings_for_fastled() -> None:
122
+ """
123
+ 🚨 Repository-only: Apply clangd settings and IntelliSense overrides.
124
+ This should ONLY be called for the actual FastLED repository.
125
+ """
126
+ from .project_detection import is_fastled_repository
127
+
128
+ # Safety check - only apply in actual repository
129
+ if not is_fastled_repository():
130
+ return
131
+ settings_json_path = Path.cwd() / ".vscode" / "settings.json"
132
+
133
+ # FastLED repository-specific settings - updated to match the official FastLED repo
134
+ fastled_settings = {
135
+ # Terminal configuration
136
+ "terminal.integrated.defaultProfile.windows": "Git Bash",
137
+ "terminal.integrated.shellIntegration.enabled": False,
138
+ "terminal.integrated.profiles.windows": {
139
+ "Command Prompt": {"path": "C:\\Windows\\System32\\cmd.exe"},
140
+ "Git Bash": {
141
+ "path": "C:\\Program Files\\Git\\bin\\bash.exe",
142
+ "args": ["--cd=."],
143
+ },
144
+ },
145
+ # File settings
146
+ "files.eol": "\n", # Unix line endings
147
+ "files.autoDetectEol": False, # Prevent VS Code from auto-detecting and changing EOL
148
+ "files.insertFinalNewline": True, # Ensure files end with a newline
149
+ "files.trimFinalNewlines": True, # Remove extra newlines at the end
150
+ "editor.tabSize": 4,
151
+ "editor.insertSpaces": True,
152
+ "editor.detectIndentation": True,
153
+ "editor.formatOnSave": False, # Disabled to prevent conflicts
154
+ # Debugger defaults - ensure C++ debugger is used for C++ files
155
+ "debug.defaultDebuggerType": "cppdbg",
156
+ "debug.toolBarLocation": "docked",
157
+ "debug.console.fontSize": 14,
158
+ "debug.console.lineHeight": 19,
159
+ # Python configuration (using uv as per project rules)
160
+ "python.defaultInterpreterPath": "uv",
161
+ "python.debugger": "debugpy",
162
+ # File associations for debugger
163
+ "[cpp]": {
164
+ "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd",
165
+ "debug.defaultDebuggerType": "cppdbg",
166
+ },
167
+ "[c]": {
168
+ "editor.defaultFormatter": "ms-vscode.cpptools",
169
+ "debug.defaultDebuggerType": "cppdbg",
170
+ },
171
+ "[ino]": {
172
+ "editor.defaultFormatter": "ms-vscode.cpptools",
173
+ "debug.defaultDebuggerType": "cppdbg",
174
+ },
175
+ # clangd configuration - enhanced
176
+ "clangd.arguments": [
177
+ "--compile-commands-dir=${workspaceFolder}",
178
+ "--clang-tidy",
179
+ "--header-insertion=never",
180
+ "--completion-style=detailed",
181
+ "--function-arg-placeholders=false",
182
+ "--background-index",
183
+ "--pch-storage=memory",
184
+ ],
185
+ "clangd.fallbackFlags": [
186
+ "-std=c++17",
187
+ "-I${workspaceFolder}/src",
188
+ "-I${workspaceFolder}/tests",
189
+ "-Wno-global-constructors",
190
+ ],
191
+ # Disable conflicting IntelliSense to let clangd handle C++ analysis
192
+ "C_Cpp.intelliSenseEngine": "disabled",
193
+ "C_Cpp.autocomplete": "disabled",
194
+ "C_Cpp.errorSquiggles": "disabled",
195
+ "C_Cpp.suggestSnippets": False,
196
+ "C_Cpp.intelliSenseEngineFallback": "disabled",
197
+ "C_Cpp.autocompleteAddParentheses": False,
198
+ "C_Cpp.formatting": "disabled",
199
+ "C_Cpp.vcpkg.enabled": False,
200
+ "C_Cpp.configurationWarnings": "disabled",
201
+ "C_Cpp.intelliSenseCachePath": "",
202
+ "C_Cpp.intelliSenseCacheSize": 0,
203
+ "C_Cpp.intelliSenseUpdateDelay": 0,
204
+ "C_Cpp.workspaceParsingPriority": "lowest",
205
+ "C_Cpp.disabled": True,
206
+ # File associations - comprehensive
207
+ "files.associations": {
208
+ "*.ino": "cpp",
209
+ "*.h": "cpp",
210
+ "*.hpp": "cpp",
211
+ "*.cpp": "cpp",
212
+ "*.c": "c",
213
+ "*.inc": "cpp",
214
+ "*.tcc": "cpp",
215
+ "*.embeddedhtml": "html",
216
+ # Core C++ standard library files
217
+ "compare": "cpp",
218
+ "type_traits": "cpp",
219
+ "cmath": "cpp",
220
+ "limits": "cpp",
221
+ "iostream": "cpp",
222
+ "random": "cpp",
223
+ "functional": "cpp",
224
+ "bit": "cpp",
225
+ "vector": "cpp",
226
+ "array": "cpp",
227
+ "string": "cpp",
228
+ "memory": "cpp",
229
+ "algorithm": "cpp",
230
+ "iterator": "cpp",
231
+ "utility": "cpp",
232
+ "optional": "cpp",
233
+ "variant": "cpp",
234
+ "numeric": "cpp",
235
+ "chrono": "cpp",
236
+ "thread": "cpp",
237
+ "mutex": "cpp",
238
+ "atomic": "cpp",
239
+ "future": "cpp",
240
+ "condition_variable": "cpp",
241
+ },
242
+ # Disable Java language support and popups
243
+ "java.enabled": False,
244
+ "java.jdt.ls.enabled": False,
245
+ "java.compile.nullAnalysis.mode": "disabled",
246
+ "java.configuration.checkProjectSettingsExclusions": False,
247
+ "java.import.gradle.enabled": False,
248
+ "java.import.maven.enabled": False,
249
+ "java.autobuild.enabled": False,
250
+ "java.maxConcurrentBuilds": 0,
251
+ "java.recommendations.enabled": False,
252
+ "java.help.showReleaseNotes": False,
253
+ "redhat.telemetry.enabled": False,
254
+ # Java exclusions
255
+ "java.project.sourcePaths": [],
256
+ "java.project.referencedLibraries": [],
257
+ "files.exclude": {
258
+ "**/.classpath": True,
259
+ "**/.project": True,
260
+ "**/.factorypath": True,
261
+ },
262
+ # Disable PlatformIO auto-detection for .ino files in FastLED project
263
+ "platformio.disableToolchainAutoInstaller": True,
264
+ "platformio-ide.autoRebuildAutocompleteIndex": False,
265
+ "platformio-ide.activateProjectOnTextEditorChange": False,
266
+ "platformio-ide.autoOpenPlatformIOIniFile": False,
267
+ "platformio-ide.autoPreloadEnvTasks": False,
268
+ "platformio-ide.autoCloseSerialMonitor": False,
269
+ "platformio-ide.disablePIOHomeStartup": True,
270
+ # Disable conflicting extensions
271
+ "extensions.ignoreRecommendations": True,
272
+ # Semantic token color customizations for better C++ development
273
+ "editor.semanticTokenColorCustomizations": {
274
+ "rules": {
275
+ # Types (classes, structs, enums) - Teal/Cyan
276
+ "class": "#4EC9B0",
277
+ "struct": "#4EC9B0",
278
+ "type": "#4EC9B0",
279
+ "enum": "#4EC9B0",
280
+ "enumMember": "#B5CEA8",
281
+ "typedef": "#4EC9B0",
282
+ # Variables - Almost pure white for maximum readability
283
+ "variable": "#FAFAFA",
284
+ "variable.local": "#FAFAFA",
285
+ # Parameters - Orange for clear distinction
286
+ "parameter": "#FF8C42",
287
+ "variable.parameter": "#FF8C42",
288
+ # Properties - Light purple/pink
289
+ "property": "#D197D9",
290
+ # Functions and methods - Yellow
291
+ "function": "#DCDCAA",
292
+ "method": "#DCDCAA",
293
+ "function.declaration": "#DCDCAA",
294
+ "method.declaration": "#DCDCAA",
295
+ # Namespaces - Soft blue
296
+ "namespace": "#86C5F7",
297
+ # Constants and readonly - Light green with italic
298
+ "variable.readonly": {"foreground": "#B5CEA8", "fontStyle": "italic"},
299
+ "variable.defaultLibrary": "#B5CEA8",
300
+ # Macros and defines - Muted red/salmon
301
+ "macro": "#E06C75",
302
+ # String literals - Peach/salmon
303
+ "string": "#CE9178",
304
+ # Numbers - Light green
305
+ "number": "#B5CEA8",
306
+ # Keywords - Pink/magenta
307
+ "keyword": "#C586C0",
308
+ # Storage specifiers - Bright magenta/pink
309
+ "keyword.storage": "#FF79C6",
310
+ "storageClass": "#FF79C6",
311
+ # Built-in types - Different from user-defined types
312
+ "type.builtin": "#569CD6",
313
+ "keyword.type": "#569CD6",
314
+ # Comments - Green
315
+ "comment": "#6A9955",
316
+ "comment.documentation": "#6A9955",
317
+ }
318
+ },
319
+ # Inlay hints - Brighter gray for better visibility
320
+ "editor.inlayHints.fontColor": "#808080",
321
+ "editor.inlayHints.background": "#3C3C3C20",
322
+ }
323
+
324
+ if settings_json_path.exists():
325
+ # Merge with existing
326
+ try:
327
+ with open(settings_json_path, "r") as f:
328
+ data = json.load(f)
329
+ except json.JSONDecodeError:
330
+ data = {}
331
+ else:
332
+ data = {}
333
+
334
+ # Update settings
335
+ data.update(fastled_settings)
336
+
337
+ # Write back
338
+ settings_json_path.parent.mkdir(exist_ok=True)
339
+ with open(settings_json_path, "w") as f:
340
+ json.dump(data, f, indent=4)
341
+
342
+ print(
343
+ f"✅ Updated {settings_json_path} with comprehensive FastLED development settings"
344
+ )
@@ -2,6 +2,8 @@ from tempfile import TemporaryDirectory
2
2
  from time import time
3
3
  from warnings import warn
4
4
 
5
+ from fastled.emoji_util import safe_print
6
+
5
7
  _FILTER = True
6
8
 
7
9
 
@@ -18,21 +20,21 @@ def test_examples(
18
20
  examples.remove("LuminescentGrand")
19
21
  with TemporaryDirectory() as tmpdir:
20
22
  for example in examples:
21
- print(f"Initializing example: {example}")
23
+ safe_print(f"Initializing example: {example}")
22
24
  try:
23
25
  sketch_dir = Api.project_init(example, outputdir=tmpdir, host=host)
24
26
  except Exception as e:
25
27
  warn(f"Failed to initialize example: {example}, error: {e}")
26
28
  out[example] = e
27
29
  continue
28
- print(f"Project initialized at: {sketch_dir}")
30
+ safe_print(f"Project initialized at: {sketch_dir}")
29
31
  start = time()
30
- print(f"Compiling example: {example}")
32
+ safe_print(f"Compiling example: {example}")
31
33
  diff = time() - start
32
- print(f"Compilation took: {diff:.2f} seconds")
34
+ safe_print(f"Compilation took: {diff:.2f} seconds")
33
35
  result = Api.web_compile(sketch_dir, host=host)
34
36
  if not result.success:
35
- print(f"Compilation failed for {example}: {result.stdout}")
37
+ safe_print(f"Compilation failed for {example}: {result.stdout}")
36
38
  out[example] = Exception(result.stdout)
37
39
  return out
38
40
 
@@ -8,6 +8,7 @@ from pathlib import Path
8
8
 
9
9
  import httpx
10
10
 
11
+ from fastled.emoji_util import EMO, safe_print
11
12
  from fastled.find_good_connection import find_good_connection
12
13
  from fastled.interruptible_http import make_interruptible_post_request
13
14
  from fastled.settings import AUTH_TOKEN, SERVER_PORT
@@ -89,7 +90,7 @@ def _banner(msg: str) -> str:
89
90
 
90
91
 
91
92
  def _print_banner(msg: str) -> None:
92
- print(_banner(msg))
93
+ safe_print(_banner(msg))
93
94
 
94
95
 
95
96
  def _compile_libfastled(
@@ -144,7 +145,6 @@ def _send_compile_request(
144
145
  build_mode: BuildMode,
145
146
  profile: bool,
146
147
  no_platformio: bool,
147
- allow_libcompile: bool,
148
148
  ) -> httpx.Response:
149
149
  """Send the compile request to the server and return the response."""
150
150
  host = _sanitize_host(host)
@@ -293,6 +293,11 @@ def _process_compile_response(
293
293
  )
294
294
 
295
295
 
296
+ def _libcompiled_is_allowed(host: str) -> bool:
297
+ """Check if libcompiled is allowed for the given host."""
298
+ return "localhost" in host or "127.0.0.1" in host or "0.0.0.0" in host
299
+
300
+
296
301
  def web_compile(
297
302
  directory: Path | str,
298
303
  host: str | None = None,
@@ -312,6 +317,12 @@ def web_compile(
312
317
  if not directory.exists():
313
318
  raise FileNotFoundError(f"Directory not found: {directory}")
314
319
 
320
+ if allow_libcompile and not _libcompiled_is_allowed(host):
321
+ print(
322
+ f"{EMO('🚫', '[ERROR]')} libcompile is not allowed for host {host}, disabling."
323
+ )
324
+ allow_libcompile = False
325
+
315
326
  # Time the zip creation
316
327
  zip_start_time = time.time()
317
328
  zip_result: ZipResult | Exception = zip_files(directory, build_mode=build_mode)
@@ -419,7 +430,6 @@ def web_compile(
419
430
  build_mode,
420
431
  profile,
421
432
  no_platformio,
422
- False, # allow_libcompile is always False since we handle it manually
423
433
  )
424
434
  sketch_time = time.time() - sketch_start_time
425
435
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastled
3
- Version: 1.4.33
3
+ Version: 1.4.35
4
4
  Summary: FastLED Wasm Compiler
5
5
  Home-page: https://github.com/zackees/fastled-wasm
6
6
  Maintainer: Zachary Vorhies
@@ -60,6 +60,7 @@ src/fastled/client_server.py
60
60
  src/fastled/compile_server.py
61
61
  src/fastled/compile_server_impl.py
62
62
  src/fastled/docker_manager.py
63
+ src/fastled/emoji_util.py
63
64
  src/fastled/filewatcher.py
64
65
  src/fastled/find_good_connection.py
65
66
  src/fastled/interruptible_http.py