Fix space characters when using platformio build rules (#808, #809)

Instead of going through protoc, let nanopb_generator.py handle it.
Instead of constructing a string, create a list of arguments to avoid need for escaping.
diff --git a/.github/workflows/platformio_tests.yml b/.github/workflows/platformio_tests.yml
index 6c52ccd..4eb891a 100644
--- a/.github/workflows/platformio_tests.yml
+++ b/.github/workflows/platformio_tests.yml
@@ -3,6 +3,12 @@
 on:
   workflow_dispatch:
   workflow_call:
+  push:
+    paths:
+      - '*platformio*'
+  pull_request:
+    paths:
+      - '*platformio*'
 
 jobs:
   platformio:
@@ -50,6 +56,14 @@
       - name: Example - Run test with options
         run: example/.pio/build/pio_with_options/program
 
+      - name: Build in subdirectory with space characters
+        run: |
+          cp -R nanopb/examples/platformio "example with spaces"
+          mkdir -p "example with spaces/lib/nanopb"
+          tar -xzf nanopb/Nanopb-*.tar.gz -C "example with spaces/lib/nanopb"
+          cd "example with spaces"
+          pio run -e pio_with_options # ESP32 platform doesn't support spaces currently
+
       - name: Build with default platformio.ini
         run: |
           mkdir -p test_default_pio_conf
diff --git a/generator/platformio_generator.py b/generator/platformio_generator.py
index 53e7c64..8b677c9 100644
--- a/generator/platformio_generator.py
+++ b/generator/platformio_generator.py
@@ -1,6 +1,8 @@
 import os
 import hashlib
 import pathlib
+import shlex
+import SCons.Action
 from platformio import fs
 
 Import("env")
@@ -45,7 +47,7 @@
     if isinstance(nanopb_plugin_options, (list, tuple)):
         nanopb_plugin_options = " ".join(nanopb_plugin_options)
 
-    nanopb_plugin_options = nanopb_plugin_options.split()
+    nanopb_plugin_options = shlex.split(nanopb_plugin_options)
 
     protos_files = fs.match_src_files(project_dir, nanopb_protos)
     if not len(protos_files):
@@ -53,12 +55,12 @@
         print(f"custom_nanopb_protos: {nanopb_protos}")
         exit(1)
 
-    protoc_generator = os.path.join(nanopb_root, 'generator', 'protoc')
+    nanopb_generator = os.path.join(nanopb_root, 'generator', 'nanopb_generator.py')
 
-    nanopb_options = ""
-    nanopb_options += f" --nanopb_out={generated_src_dir}"
+    nanopb_options = []
+    nanopb_options.append(f"--output-dir={generated_src_dir}")
     for opt in nanopb_plugin_options:
-        nanopb_options += (" --nanopb_opt=" + opt)
+        nanopb_options.append(opt)
 
     try:
         os.makedirs(generated_src_dir)
@@ -78,8 +80,7 @@
         proto_include_dirs.add(proto_dir)
 
     for proto_include_dir in proto_include_dirs:
-        nanopb_options += (" --proto_path=" + proto_include_dir)
-        nanopb_options += (" --nanopb_opt=-I" + proto_include_dir)
+        nanopb_options.append("--proto-path=" + proto_include_dir)
 
     for proto_file in protos_files:
         proto_file_abs = os.path.join(project_dir, proto_file)
@@ -132,8 +133,9 @@
             print(f"[nanopb] Skipping '{proto_file}' ({options_info})")
         else:
             print(f"[nanopb] Processing '{proto_file}' ({options_info})")
-            cmd = protoc_generator + " " + nanopb_options + " " + proto_file_basename
-            result = env.Execute(cmd)
+            cmd = ["$PYTHONEXE", nanopb_generator] + nanopb_options + [proto_file_basename]
+            action = SCons.Action.CommandAction(cmd)
+            result = env.Execute(action)
             if result != 0:
                 print(f"[nanopb] ERROR: ({result}) processing cmd: '{cmd}'")
                 exit(1)