prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Improve VSCode draft editor robustness
  Users can lose drafts if window switch is too slow.  To address this issue, we propose the following:
  
  - [x] Increase sleep timeout in https://github.com/knausj85/knausj_talon/blob/0d4ad8523b87c2fe10457b7fae7f2ba2f22ad735/draft_editor/draft_editor.py#L112
  - [x] Keep last draft in memory, and have "draft submit" when outside of VSCode just submit the most recent draft.  That way if initial draft submit doesn't work, user can just say "draft submit" again
  - [x] While we're here, add "draft top", which selects from cursor to start of document
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `draft_editor/draft_editor.py`
  Content:
  ```
  1 from talon import Context, Module, actions, ui
  2 
  3 mod = Module()
  4 mod.tag("draft_editor_active", "Indicates whether the draft editor has been activated")
  5 mod.tag(
  6     "draft_editor_app_focused",
  7     "Indicates that the draft editor app currently has focus",
  8 )
  9 
  10 ctx = Context()
  11 tags: set[str] = set()
  12 
  13 
  14 def add_tag(tag: str):
  15     tags.add(tag)
  16     ctx.tags = list(tags)
  17 
  18 
  19 def remove_tag(tag: str):
  20     tags.discard(tag)
  21     ctx.tags = list(tags)
  22 
  23 
  24 default_names = ["Visual Studio Code", "Code", "VSCodium", "Codium", "code-oss"]
  25 
  26 setting_editor_names = mod.setting(
  27     "draft_editor",
  28     type=str,
  29     default=None,
  30     desc="List of application names to use for draft editor",
  31 )
  32 
  33 
  34 def get_editor_names():
  35     names_csv = setting_editor_names.get()
  36     return names_csv.split(", ") if names_csv else default_names
  37 
  38 
  39 @mod.scope
  40 def scope():
  41     editor_names = get_editor_names()
  42 
  43     for app in ui.apps(background=False):
  44         if app.name in editor_names:
  45             return {"draft_editor_running": True}
  46 
  47     return {"draft_editor_running": False}
  48 
  49 
  50 def handle_app_activate(app):
  51     if app.name in get_editor_names():
  52         add_tag("user.draft_editor_app_focused")
  53     else:
  54         remove_tag("user.draft_editor_app_focused")
  55 
  56 
  57 ui.register("app_launch", scope.update)
  58 ui.register("app_close", scope.update)
  59 ui.register("app_activate", handle_app_activate)
  60 
  61 
  62 original_window = None
  63 
  64 
  65 @mod.action_class
  66 class Actions:
  67     def draft_editor_open():
  68         """Open draft editor"""
  69         global original_window
  70         original_window = ui.active_window()
  71         editor_app = get_editor_app()
  72         selected_text = actions.edit.selected_text()
  73         actions.user.switcher_focus_app(editor_app)
  74         # Wait additional time for talon context to update.
  75         actions.sleep("200ms")
  76         actions.app.tab_open()
  77         if selected_text != "":
  78             actions.user.paste(selected_text)
  79         add_tag("user.draft_editor_active")
  80 
  81     def draft_editor_submit():
  82         """Submit/save draft editor"""
  83         close_editor(submit_draft=True)
  84 
  85     def draft_editor_discard():
  86         """Discard draft editor"""
  87         close_editor(submit_draft=False)
  88 
  89 
  90 def get_editor_app() -> ui.App:
  91     editor_names = get_editor_names()
  92 
  93     for app in ui.apps(background=False):
  94         if app.name in editor_names:
  95             return app
  96 
  97     raise RuntimeError("Draft editor is not running")
  98 
  99 
  100 def close_editor(submit_draft: bool):
  101     remove_tag("user.draft_editor_active")
  102     actions.edit.select_all()
  103     selected_text = actions.edit.selected_text()
  104     actions.edit.delete()
  105     actions.app.tab_close()
  106     actions.user.switcher_focus_window(original_window)
  107     actions.sleep("200ms")
  108     if submit_draft:
  109         actions.user.paste(selected_text)
  110
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/draft_editor/draft_editor.py b/draft_editor/draft_editor.py
  --- a/draft_editor/draft_editor.py
  +++ b/draft_editor/draft_editor.py
  @@ -61,6 +61,8 @@
   
   original_window = None
   
  +last_draft = None
  +
   
   @mod.action_class
   class Actions:
  @@ -86,6 +88,11 @@
           """Discard draft editor"""
           close_editor(submit_draft=False)
   
  +    def draft_editor_paste_last():
  +        """Paste last submitted draft"""
  +        if last_draft:
  +            actions.user.paste(last_draft)
  +
   
   def get_editor_app() -> ui.App:
       editor_names = get_editor_names()
  @@ -98,12 +105,14 @@
   
   
   def close_editor(submit_draft: bool):
  +    global last_draft
       remove_tag("user.draft_editor_active")
       actions.edit.select_all()
       selected_text = actions.edit.selected_text()
       actions.edit.delete()
       actions.app.tab_close()
       actions.user.switcher_focus_window(original_window)
  -    actions.sleep("200ms")
  +    actions.sleep("300ms")
       if submit_draft:
  +        last_draft = selected_text
           actions.user.paste(selected_text)
  
verification_info: {"golden_diff": "diff --git a/draft_editor/draft_editor.py b/draft_editor/draft_editor.py\n--- a/draft_editor/draft_editor.py\n+++ b/draft_editor/draft_editor.py\n@@ -61,6 +61,8 @@\n \n original_window = None\n \n+last_draft = None\n+\n \n @mod.action_class\n class Actions:\n@@ -86,6 +88,11 @@\n         \"\"\"Discard draft editor\"\"\"\n         close_editor(submit_draft=False)\n \n+    def draft_editor_paste_last():\n+        \"\"\"Paste last submitted draft\"\"\"\n+        if last_draft:\n+            actions.user.paste(last_draft)\n+\n \n def get_editor_app() -> ui.App:\n     editor_names = get_editor_names()\n@@ -98,12 +105,14 @@\n \n \n def close_editor(submit_draft: bool):\n+    global last_draft\n     remove_tag(\"user.draft_editor_active\")\n     actions.edit.select_all()\n     selected_text = actions.edit.selected_text()\n     actions.edit.delete()\n     actions.app.tab_close()\n     actions.user.switcher_focus_window(original_window)\n-    actions.sleep(\"200ms\")\n+    actions.sleep(\"300ms\")\n     if submit_draft:\n+        last_draft = selected_text\n         actions.user.paste(selected_text)\n", "issue": "Improve VSCode draft editor robustness\nUsers can lose drafts if window switch is too slow.  To address this issue, we propose the following:\r\n\r\n- [x] Increase sleep timeout in https://github.com/knausj85/knausj_talon/blob/0d4ad8523b87c2fe10457b7fae7f2ba2f22ad735/draft_editor/draft_editor.py#L112\r\n- [x] Keep last draft in memory, and have \"draft submit\" when outside of VSCode just submit the most recent draft.  That way if initial draft submit doesn't work, user can just say \"draft submit\" again\r\n- [x] While we're here, add \"draft top\", which selects from cursor to start of document\n", "before_files": [{"content": "from talon import Context, Module, actions, ui\n\nmod = Module()\nmod.tag(\"draft_editor_active\", \"Indicates whether the draft editor has been activated\")\nmod.tag(\n    \"draft_editor_app_focused\",\n    \"Indicates that the draft editor app currently has focus\",\n)\n\nctx = Context()\ntags: set[str] = set()\n\n\ndef add_tag(tag: str):\n    tags.add(tag)\n    ctx.tags = list(tags)\n\n\ndef remove_tag(tag: str):\n    tags.discard(tag)\n    ctx.tags = list(tags)\n\n\ndefault_names = [\"Visual Studio Code\", \"Code\", \"VSCodium\", \"Codium\", \"code-oss\"]\n\nsetting_editor_names = mod.setting(\n    \"draft_editor\",\n    type=str,\n    default=None,\n    desc=\"List of application names to use for draft editor\",\n)\n\n\ndef get_editor_names():\n    names_csv = setting_editor_names.get()\n    return names_csv.split(\", \") if names_csv else default_names\n\n\n@mod.scope\ndef scope():\n    editor_names = get_editor_names()\n\n    for app in ui.apps(background=False):\n        if app.name in editor_names:\n            return {\"draft_editor_running\": True}\n\n    return {\"draft_editor_running\": False}\n\n\ndef handle_app_activate(app):\n    if app.name in get_editor_names():\n        add_tag(\"user.draft_editor_app_focused\")\n    else:\n        remove_tag(\"user.draft_editor_app_focused\")\n\n\nui.register(\"app_launch\", scope.update)\nui.register(\"app_close\", scope.update)\nui.register(\"app_activate\", handle_app_activate)\n\n\noriginal_window = None\n\n\n@mod.action_class\nclass Actions:\n    def draft_editor_open():\n        \"\"\"Open draft editor\"\"\"\n        global original_window\n        original_window = ui.active_window()\n        editor_app = get_editor_app()\n        selected_text = actions.edit.selected_text()\n        actions.user.switcher_focus_app(editor_app)\n        # Wait additional time for talon context to update.\n        actions.sleep(\"200ms\")\n        actions.app.tab_open()\n        if selected_text != \"\":\n            actions.user.paste(selected_text)\n        add_tag(\"user.draft_editor_active\")\n\n    def draft_editor_submit():\n        \"\"\"Submit/save draft editor\"\"\"\n        close_editor(submit_draft=True)\n\n    def draft_editor_discard():\n        \"\"\"Discard draft editor\"\"\"\n        close_editor(submit_draft=False)\n\n\ndef get_editor_app() -> ui.App:\n    editor_names = get_editor_names()\n\n    for app in ui.apps(background=False):\n        if app.name in editor_names:\n            return app\n\n    raise RuntimeError(\"Draft editor is not running\")\n\n\ndef close_editor(submit_draft: bool):\n    remove_tag(\"user.draft_editor_active\")\n    actions.edit.select_all()\n    selected_text = actions.edit.selected_text()\n    actions.edit.delete()\n    actions.app.tab_close()\n    actions.user.switcher_focus_window(original_window)\n    actions.sleep(\"200ms\")\n    if submit_draft:\n        actions.user.paste(selected_text)\n", "path": "draft_editor/draft_editor.py"}], "after_files": [{"content": "from talon import Context, Module, actions, ui\n\nmod = Module()\nmod.tag(\"draft_editor_active\", \"Indicates whether the draft editor has been activated\")\nmod.tag(\n    \"draft_editor_app_focused\",\n    \"Indicates that the draft editor app currently has focus\",\n)\n\nctx = Context()\ntags: set[str] = set()\n\n\ndef add_tag(tag: str):\n    tags.add(tag)\n    ctx.tags = list(tags)\n\n\ndef remove_tag(tag: str):\n    tags.discard(tag)\n    ctx.tags = list(tags)\n\n\ndefault_names = [\"Visual Studio Code\", \"Code\", \"VSCodium\", \"Codium\", \"code-oss\"]\n\nsetting_editor_names = mod.setting(\n    \"draft_editor\",\n    type=str,\n    default=None,\n    desc=\"List of application names to use for draft editor\",\n)\n\n\ndef get_editor_names():\n    names_csv = setting_editor_names.get()\n    return names_csv.split(\", \") if names_csv else default_names\n\n\n@mod.scope\ndef scope():\n    editor_names = get_editor_names()\n\n    for app in ui.apps(background=False):\n        if app.name in editor_names:\n            return {\"draft_editor_running\": True}\n\n    return {\"draft_editor_running\": False}\n\n\ndef handle_app_activate(app):\n    if app.name in get_editor_names():\n        add_tag(\"user.draft_editor_app_focused\")\n    else:\n        remove_tag(\"user.draft_editor_app_focused\")\n\n\nui.register(\"app_launch\", scope.update)\nui.register(\"app_close\", scope.update)\nui.register(\"app_activate\", handle_app_activate)\n\n\noriginal_window = None\n\nlast_draft = None\n\n\n@mod.action_class\nclass Actions:\n    def draft_editor_open():\n        \"\"\"Open draft editor\"\"\"\n        global original_window\n        original_window = ui.active_window()\n        editor_app = get_editor_app()\n        selected_text = actions.edit.selected_text()\n        actions.user.switcher_focus_app(editor_app)\n        # Wait additional time for talon context to update.\n        actions.sleep(\"200ms\")\n        actions.app.tab_open()\n        if selected_text != \"\":\n            actions.user.paste(selected_text)\n        add_tag(\"user.draft_editor_active\")\n\n    def draft_editor_submit():\n        \"\"\"Submit/save draft editor\"\"\"\n        close_editor(submit_draft=True)\n\n    def draft_editor_discard():\n        \"\"\"Discard draft editor\"\"\"\n        close_editor(submit_draft=False)\n\n    def draft_editor_paste_last():\n        \"\"\"Paste last submitted draft\"\"\"\n        if last_draft:\n            actions.user.paste(last_draft)\n\n\ndef get_editor_app() -> ui.App:\n    editor_names = get_editor_names()\n\n    for app in ui.apps(background=False):\n        if app.name in editor_names:\n            return app\n\n    raise RuntimeError(\"Draft editor is not running\")\n\n\ndef close_editor(submit_draft: bool):\n    global last_draft\n    remove_tag(\"user.draft_editor_active\")\n    actions.edit.select_all()\n    selected_text = actions.edit.selected_text()\n    actions.edit.delete()\n    actions.app.tab_close()\n    actions.user.switcher_focus_window(original_window)\n    actions.sleep(\"300ms\")\n    if submit_draft:\n        last_draft = selected_text\n        actions.user.paste(selected_text)\n", "path": "draft_editor/draft_editor.py"}]}