bpo-5680: IDLE: Customize running a module (GH-13763)

The initialize options are 1) add command line options, which are appended to sys.argv as if passed on a real command line, and 2) skip the shell restart. The customization dialog is accessed by a new entry on the Run menu.
diff --git a/Lib/idlelib/query.py b/Lib/idlelib/query.py
index f0b7255..9b3bb1d 100644
--- a/Lib/idlelib/query.py
+++ b/Lib/idlelib/query.py
@@ -21,10 +21,11 @@
 
 import importlib
 import os
+import shlex
 from sys import executable, platform  # Platform is set for one test.
 
-from tkinter import Toplevel, StringVar, W, E, S
-from tkinter.ttk import Frame, Button, Entry, Label
+from tkinter import Toplevel, StringVar, BooleanVar, W, E, S
+from tkinter.ttk import Frame, Button, Entry, Label, Checkbutton
 from tkinter import filedialog
 from tkinter.font import Font
 
@@ -83,7 +84,7 @@
             self.deiconify()  # Unhide now that geometry set.
             self.wait_window()
 
-    def create_widgets(self):  # Call from override, if any.
+    def create_widgets(self, ok_text='OK'):  # Call from override, if any.
         # Bind to self widgets needed for entry_ok or unittest.
         self.frame = frame = Frame(self, padding=10)
         frame.grid(column=0, row=0, sticky='news')
@@ -99,7 +100,7 @@
         self.entry_error = Label(frame, text=' ', foreground='red',
                                  font=self.error_font)
         self.button_ok = Button(
-                frame, text='OK', default='active', command=self.ok)
+                frame, text=ok_text, default='active', command=self.ok)
         self.button_cancel = Button(
                 frame, text='Cancel', command=self.cancel)
 
@@ -302,10 +303,56 @@
         path = self.path_ok()
         return None if name is None or path is None else (name, path)
 
+class CustomRun(Query):
+    """Get settings for custom run of module.
+
+    1. Command line arguments to extend sys.argv.
+    2. Whether to restart Shell or not.
+    """
+    # Used in runscript.run_custom_event
+
+    def __init__(self, parent, title, *, cli_args='',
+                 _htest=False, _utest=False):
+        # TODO Use cli_args to pre-populate entry.
+        message = 'Command Line Arguments for sys.argv:'
+        super().__init__(
+                parent, title, message, text0=cli_args,
+                _htest=_htest, _utest=_utest)
+
+    def create_widgets(self):
+        super().create_widgets(ok_text='Run')
+        frame = self.frame
+        self.restartvar = BooleanVar(self, value=True)
+        restart = Checkbutton(frame, variable=self.restartvar, onvalue=True,
+                              offvalue=False, text='Restart shell')
+        self.args_error = Label(frame, text=' ', foreground='red',
+                                font=self.error_font)
+
+        restart.grid(column=0, row=4, columnspan=3, padx=5, sticky='w')
+        self.args_error.grid(column=0, row=12, columnspan=3, padx=5,
+                             sticky='we')
+
+    def cli_args_ok(self):
+        "Validity check and parsing for command line arguments."
+        cli_string = self.entry.get().strip()
+        try:
+            cli_args = shlex.split(cli_string, posix=True)
+        except ValueError as err:
+            self.showerror(str(err))
+            return None
+        return cli_args
+
+    def entry_ok(self):
+        "Return apparently valid (cli_args, restart) or None"
+        self.entry_error['text'] = ''
+        cli_args = self.cli_args_ok()
+        restart = self.restartvar.get()
+        return None if cli_args is None else (cli_args, restart)
+
 
 if __name__ == '__main__':
     from unittest import main
     main('idlelib.idle_test.test_query', verbosity=2, exit=False)
 
     from idlelib.idle_test.htest import run
-    run(Query, HelpSource)
+    run(Query, HelpSource, CustomRun)