We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Windows switching could use fuzzier matching
Right now when you want to switch window focus you have to say a word the matches a generated list of running applications, and this list has an override that lets you more easily say the names of complex application names, for instance `term` is `iTerm2` or whatever.

I propose we change the way the list works so that actually we just use `focus <user.text>` for the command, and then `switcher_focus()` does the lookup for whatever text it gets inside the running application list. Doing it this way allows us to leverage any additional vocabulary that's been added to `vocabulary.py` without necessarily having to hardcode it again inside of `switcher.py`. 

in addition I propose that we introduce slightly fuzzer matching. IFor example, my `vocabulary.py` as a rule for "key pass" which becomes "keepass", and this is helpful when I am just talking to other people in chat or whatever. But the actual name of the running process is `KeePassXC`. I don't necessarily want to always be typing that exact word into chat with other people when I say `key pass` though. I suspect this type of thing will be increasingly common the more people are using it with different applications 

As it stands if I wanted to match the app with current switcher I'd have to put "key pass":"KeePassXC" override in `switcher.py`, instead of just matching the result I already have in `vocabulary.py`. 

In addition to using `vocabulary.py`, I propose we check for a partial match using `startswith()`, so then I would be able to say something like "focus key pass" and it would actually come through as `focus keepass`, which would in turn match against `keepassxc`. 

We can of course keep the overrides for certain things that are a bit harder to say in `switcher.py`, for instance I think people aren't going to have `term` becoming `iTerm2` in `vocabulary.py`.

This can mostly all be done with a simple `switcher_focus()` change like:

```
        running = ctx.lists["self.running"]
        wanted_app = None
        for running_name in running.keys():
            if running_name == name or running_name.lower().startswith(name):
                wanted_app = running[running_name]
                break
        if wanted_app is None:
            return

        for app in ui.apps():
            if app.name == wanted_app and not app.background:
                #os.system("i3-msg '[class=\"(?)%s\"] focus'" % app.name)
                app.focus()
                break
```

Not sending a PR for now as I figured I'd run it past others first.

One possible change could be that it does two passes, the first pass matches on explicit name matches so you don't accidentally match against something that has a more explicit match, and then if there are no explicit matches, it tries a second pass with fuzzy matching.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `code/switcher.py`
Content:
```
1 from talon import app, Module, Context, actions, ui, imgui
2 from talon.voice import Capture
3 import re
4 import time
5 import os
6 
7 # Construct at startup a list of overides for application names (similar to how homophone list is managed)
8 # ie for a given talon recognition word set  `one note`, recognized this in these switcher functions as `ONENOTE`
9 # the list is a comma seperated `<Recognized Words>, <Overide>`
10 # TODO: Consider put list csv's (homophones.csv, app_name_overrides.csv) files together in a seperate directory,`knausj_talon/lists`
11 cwd = os.path.dirname(os.path.realpath(__file__))
12 overrides_file = os.path.join(
13     cwd, "app_names", f"app_name_overrides.{app.platform}.csv"
14 )
15 overrides = {}
16 with open(overrides_file, "r") as f:
17     for line in f:
18         line = line.rstrip()
19         line = line.split(",")
20         overrides[line[0].lower()] = line[1].strip()
21 
22 print(f"knausj_talon.switcher------------ app name overrides:{overrides}")
23 
24 app_cache = {}
25 
26 
27 mod = Module()
28 mod.list("running", desc="all running applications")
29 mod.list("launch", desc="all launchable applications")
30 
31 
32 @mod.capture
33 def running_applications(m) -> str:
34     "Returns a single application name"
35 
36 
37 @mod.capture
38 def launch_applications(m) -> Capture:
39     "Returns a single application name"
40 
41 
42 ctx = Context()
43 
44 
45 @ctx.capture(rule="{self.running}")
46 def running_applications(m):
47     return m.running
48 
49 
50 @ctx.capture(rule="{self.launch}")
51 def launch_applications(m):
52     return m.launch
53 
54 
55 def split_camel(word):
56     return re.findall(r"[0-9A-Z]*[a-z]+(?=[A-Z]|$)", word)
57 
58 
59 def get_words(name):
60     words = re.findall(r"[0-9A-Za-z]+", name)
61     out = []
62     for word in words:
63         out += split_camel(word)
64     return out
65 
66 
67 @mod.action_class
68 class Actions:
69     def switcher_focus(name: str):
70         """Focus a new application by  name"""
71         for app in ui.apps():
72             # print(f"--------- app.name:{app.name}  app.bundler:{app.bundle}")
73             if name in app.name and not app.background:
74                 app.focus()
75                 break
76 
77     def switcher_launch(path: str):
78         """Launch a new application by path"""
79         ui.launch(path=path)
80 
81     def switcher_list_running():
82         """Lists all running applications"""
83         gui.show()
84 
85     def switcher_hide_running():
86         """Hides list of running applications"""
87         gui.hide()
88 
89 
90 @imgui.open(software=False)
91 def gui(gui: imgui.GUI):
92     gui.text("Names of running applications")
93     gui.line()
94     for line in ctx.lists["self.running"]:
95         gui.text(line)
96 
97 
98 def update_lists():
99     running = {}
100     launch = {}
101 
102     for cur_app in ui.apps(background=False):
103         name = cur_app.name
104         if name.endswith(".exe"):
105             name = name.rsplit(".", 1)[0]
106         words = get_words(name)
107         for word in words:
108             if word and not word in running:
109                 running[word.lower()] = cur_app.name
110         running[name.lower()] = cur_app.name
111     for override in overrides:
112         running[override] = overrides[override]
113 
114     if app.platform == "mac":
115         for base in "/Applications", "/Applications/Utilities":
116             for name in os.listdir(base):
117                 path = os.path.join(base, name)
118                 name = name.rsplit(".", 1)[0].lower()
119                 launch[name] = path
120                 words = name.split(" ")
121                 for word in words:
122                     if word and word not in launch:
123                         if len(name) > 6 and len(word) < 3:
124                             continue
125                         launch[word] = path
126 
127     lists = {
128         "self.running": running,
129         "self.launch": launch,
130     }
131 
132     # batch update lists
133     ctx.lists.update(lists)
134 
135 
136 def ui_event(event, arg):
137     if event in ("app_activate", "app_launch", "app_close", "win_open", "win_close"):
138         # print(f'------------------ event:{event}  arg:{arg}')
139         update_lists()
140 
141 
142 ui.register("", ui_event)
143 update_lists()
144
```
--- 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()

```

diff --git a/code/switcher.py b/code/switcher.py
--- a/code/switcher.py
+++ b/code/switcher.py
@@ -1,8 +1,9 @@
-from talon import app, Module, Context, actions, ui, imgui
-from talon.voice import Capture
+import os
 import re
 import time
-import os
+
+from talon import Context, Module, app, imgui, ui
+from talon.voice import Capture
 
 # Construct at startup a list of overides for application names (similar to how homophone list is managed)
 # ie for a given talon recognition word set  `one note`, recognized this in these switcher functions as `ONENOTE`
@@ -68,10 +69,18 @@
 class Actions:
     def switcher_focus(name: str):
         """Focus a new application by  name"""
-        for app in ui.apps():
-            # print(f"--------- app.name:{app.name}  app.bundler:{app.bundle}")
-            if name in app.name and not app.background:
-                app.focus()
+        running = ctx.lists["self.running"]
+        wanted_app = None
+        for running_name in running.keys():
+            if running_name == name or running_name.lower().startswith(name):
+                wanted_app = running[running_name]
+                break
+        if wanted_app is None:
+            return
+
+        for cur_app in ui.apps():
+            if cur_app.name == wanted_app and not cur_app.background:
+                cur_app.focus()
                 break
 
     def switcher_launch(path: str):
@@ -105,7 +114,7 @@
             name = name.rsplit(".", 1)[0]
         words = get_words(name)
         for word in words:
-            if word and not word in running:
+            if word and word not in running:
                 running[word.lower()] = cur_app.name
         running[name.lower()] = cur_app.name
     for override in overrides:

{"golden_diff": "diff --git a/code/switcher.py b/code/switcher.py\n--- a/code/switcher.py\n+++ b/code/switcher.py\n@@ -1,8 +1,9 @@\n-from talon import app, Module, Context, actions, ui, imgui\n-from talon.voice import Capture\n+import os\n import re\n import time\n-import os\n+\n+from talon import Context, Module, app, imgui, ui\n+from talon.voice import Capture\n \n # Construct at startup a list of overides for application names (similar to how homophone list is managed)\n # ie for a given talon recognition word set  `one note`, recognized this in these switcher functions as `ONENOTE`\n@@ -68,10 +69,18 @@\n class Actions:\n     def switcher_focus(name: str):\n         \"\"\"Focus a new application by  name\"\"\"\n-        for app in ui.apps():\n-            # print(f\"--------- app.name:{app.name}  app.bundler:{app.bundle}\")\n-            if name in app.name and not app.background:\n-                app.focus()\n+        running = ctx.lists[\"self.running\"]\n+        wanted_app = None\n+        for running_name in running.keys():\n+            if running_name == name or running_name.lower().startswith(name):\n+                wanted_app = running[running_name]\n+                break\n+        if wanted_app is None:\n+            return\n+\n+        for cur_app in ui.apps():\n+            if cur_app.name == wanted_app and not cur_app.background:\n+                cur_app.focus()\n                 break\n \n     def switcher_launch(path: str):\n@@ -105,7 +114,7 @@\n             name = name.rsplit(\".\", 1)[0]\n         words = get_words(name)\n         for word in words:\n-            if word and not word in running:\n+            if word and word not in running:\n                 running[word.lower()] = cur_app.name\n         running[name.lower()] = cur_app.name\n     for override in overrides:\n", "issue": "Windows switching could use fuzzier matching\nRight now when you want to switch window focus you have to say a word the matches a generated list of running applications, and this list has an override that lets you more easily say the names of complex application names, for instance `term` is `iTerm2` or whatever.\r\n\r\nI propose we change the way the list works so that actually we just use `focus <user.text>` for the command, and then `switcher_focus()` does the lookup for whatever text it gets inside the running application list. Doing it this way allows us to leverage any additional vocabulary that's been added to `vocabulary.py` without necessarily having to hardcode it again inside of `switcher.py`. \r\n\r\nin addition I propose that we introduce slightly fuzzer matching. IFor example, my `vocabulary.py` as a rule for \"key pass\" which becomes \"keepass\", and this is helpful when I am just talking to other people in chat or whatever. But the actual name of the running process is `KeePassXC`. I don't necessarily want to always be typing that exact word into chat with other people when I say `key pass` though. I suspect this type of thing will be increasingly common the more people are using it with different applications \r\n\r\nAs it stands if I wanted to match the app with current switcher I'd have to put \"key pass\":\"KeePassXC\" override in `switcher.py`, instead of just matching the result I already have in `vocabulary.py`. \r\n\r\nIn addition to using `vocabulary.py`, I propose we check for a partial match using `startswith()`, so then I would be able to say something like \"focus key pass\" and it would actually come through as `focus keepass`, which would in turn match against `keepassxc`. \r\n\r\nWe can of course keep the overrides for certain things that are a bit harder to say in `switcher.py`, for instance I think people aren't going to have `term` becoming `iTerm2` in `vocabulary.py`.\r\n\r\nThis can mostly all be done with a simple `switcher_focus()` change like:\r\n\r\n```\r\n        running = ctx.lists[\"self.running\"]\r\n        wanted_app = None\r\n        for running_name in running.keys():\r\n            if running_name == name or running_name.lower().startswith(name):\r\n                wanted_app = running[running_name]\r\n                break\r\n        if wanted_app is None:\r\n            return\r\n\r\n        for app in ui.apps():\r\n            if app.name == wanted_app and not app.background:\r\n                #os.system(\"i3-msg '[class=\\\"(?)%s\\\"] focus'\" % app.name)\r\n                app.focus()\r\n                break\r\n```\r\n\r\nNot sending a PR for now as I figured I'd run it past others first.\r\n\r\nOne possible change could be that it does two passes, the first pass matches on explicit name matches so you don't accidentally match against something that has a more explicit match, and then if there are no explicit matches, it tries a second pass with fuzzy matching.\n", "before_files": [{"content": "from talon import app, Module, Context, actions, ui, imgui\nfrom talon.voice import Capture\nimport re\nimport time\nimport os\n\n# Construct at startup a list of overides for application names (similar to how homophone list is managed)\n# ie for a given talon recognition word set  `one note`, recognized this in these switcher functions as `ONENOTE`\n# the list is a comma seperated `<Recognized Words>, <Overide>`\n# TODO: Consider put list csv's (homophones.csv, app_name_overrides.csv) files together in a seperate directory,`knausj_talon/lists`\ncwd = os.path.dirname(os.path.realpath(__file__))\noverrides_file = os.path.join(\n    cwd, \"app_names\", f\"app_name_overrides.{app.platform}.csv\"\n)\noverrides = {}\nwith open(overrides_file, \"r\") as f:\n    for line in f:\n        line = line.rstrip()\n        line = line.split(\",\")\n        overrides[line[0].lower()] = line[1].strip()\n\nprint(f\"knausj_talon.switcher------------ app name overrides:{overrides}\")\n\napp_cache = {}\n\n\nmod = Module()\nmod.list(\"running\", desc=\"all running applications\")\nmod.list(\"launch\", desc=\"all launchable applications\")\n\n\n@mod.capture\ndef running_applications(m) -> str:\n    \"Returns a single application name\"\n\n\n@mod.capture\ndef launch_applications(m) -> Capture:\n    \"Returns a single application name\"\n\n\nctx = Context()\n\n\n@ctx.capture(rule=\"{self.running}\")\ndef running_applications(m):\n    return m.running\n\n\n@ctx.capture(rule=\"{self.launch}\")\ndef launch_applications(m):\n    return m.launch\n\n\ndef split_camel(word):\n    return re.findall(r\"[0-9A-Z]*[a-z]+(?=[A-Z]|$)\", word)\n\n\ndef get_words(name):\n    words = re.findall(r\"[0-9A-Za-z]+\", name)\n    out = []\n    for word in words:\n        out += split_camel(word)\n    return out\n\n\n@mod.action_class\nclass Actions:\n    def switcher_focus(name: str):\n        \"\"\"Focus a new application by  name\"\"\"\n        for app in ui.apps():\n            # print(f\"--------- app.name:{app.name}  app.bundler:{app.bundle}\")\n            if name in app.name and not app.background:\n                app.focus()\n                break\n\n    def switcher_launch(path: str):\n        \"\"\"Launch a new application by path\"\"\"\n        ui.launch(path=path)\n\n    def switcher_list_running():\n        \"\"\"Lists all running applications\"\"\"\n        gui.show()\n\n    def switcher_hide_running():\n        \"\"\"Hides list of running applications\"\"\"\n        gui.hide()\n\n\n@imgui.open(software=False)\ndef gui(gui: imgui.GUI):\n    gui.text(\"Names of running applications\")\n    gui.line()\n    for line in ctx.lists[\"self.running\"]:\n        gui.text(line)\n\n\ndef update_lists():\n    running = {}\n    launch = {}\n\n    for cur_app in ui.apps(background=False):\n        name = cur_app.name\n        if name.endswith(\".exe\"):\n            name = name.rsplit(\".\", 1)[0]\n        words = get_words(name)\n        for word in words:\n            if word and not word in running:\n                running[word.lower()] = cur_app.name\n        running[name.lower()] = cur_app.name\n    for override in overrides:\n        running[override] = overrides[override]\n\n    if app.platform == \"mac\":\n        for base in \"/Applications\", \"/Applications/Utilities\":\n            for name in os.listdir(base):\n                path = os.path.join(base, name)\n                name = name.rsplit(\".\", 1)[0].lower()\n                launch[name] = path\n                words = name.split(\" \")\n                for word in words:\n                    if word and word not in launch:\n                        if len(name) > 6 and len(word) < 3:\n                            continue\n                        launch[word] = path\n\n    lists = {\n        \"self.running\": running,\n        \"self.launch\": launch,\n    }\n\n    # batch update lists\n    ctx.lists.update(lists)\n\n\ndef ui_event(event, arg):\n    if event in (\"app_activate\", \"app_launch\", \"app_close\", \"win_open\", \"win_close\"):\n        # print(f'------------------ event:{event}  arg:{arg}')\n        update_lists()\n\n\nui.register(\"\", ui_event)\nupdate_lists()\n", "path": "code/switcher.py"}], "after_files": [{"content": "import os\nimport re\nimport time\n\nfrom talon import Context, Module, app, imgui, ui\nfrom talon.voice import Capture\n\n# Construct at startup a list of overides for application names (similar to how homophone list is managed)\n# ie for a given talon recognition word set  `one note`, recognized this in these switcher functions as `ONENOTE`\n# the list is a comma seperated `<Recognized Words>, <Overide>`\n# TODO: Consider put list csv's (homophones.csv, app_name_overrides.csv) files together in a seperate directory,`knausj_talon/lists`\ncwd = os.path.dirname(os.path.realpath(__file__))\noverrides_file = os.path.join(\n    cwd, \"app_names\", f\"app_name_overrides.{app.platform}.csv\"\n)\noverrides = {}\nwith open(overrides_file, \"r\") as f:\n    for line in f:\n        line = line.rstrip()\n        line = line.split(\",\")\n        overrides[line[0].lower()] = line[1].strip()\n\nprint(f\"knausj_talon.switcher------------ app name overrides:{overrides}\")\n\napp_cache = {}\n\n\nmod = Module()\nmod.list(\"running\", desc=\"all running applications\")\nmod.list(\"launch\", desc=\"all launchable applications\")\n\n\n@mod.capture\ndef running_applications(m) -> str:\n    \"Returns a single application name\"\n\n\n@mod.capture\ndef launch_applications(m) -> Capture:\n    \"Returns a single application name\"\n\n\nctx = Context()\n\n\n@ctx.capture(rule=\"{self.running}\")\ndef running_applications(m):\n    return m.running\n\n\n@ctx.capture(rule=\"{self.launch}\")\ndef launch_applications(m):\n    return m.launch\n\n\ndef split_camel(word):\n    return re.findall(r\"[0-9A-Z]*[a-z]+(?=[A-Z]|$)\", word)\n\n\ndef get_words(name):\n    words = re.findall(r\"[0-9A-Za-z]+\", name)\n    out = []\n    for word in words:\n        out += split_camel(word)\n    return out\n\n\n@mod.action_class\nclass Actions:\n    def switcher_focus(name: str):\n        \"\"\"Focus a new application by  name\"\"\"\n        running = ctx.lists[\"self.running\"]\n        wanted_app = None\n        for running_name in running.keys():\n            if running_name == name or running_name.lower().startswith(name):\n                wanted_app = running[running_name]\n                break\n        if wanted_app is None:\n            return\n\n        for cur_app in ui.apps():\n            if cur_app.name == wanted_app and not cur_app.background:\n                cur_app.focus()\n                break\n\n    def switcher_launch(path: str):\n        \"\"\"Launch a new application by path\"\"\"\n        ui.launch(path=path)\n\n    def switcher_list_running():\n        \"\"\"Lists all running applications\"\"\"\n        gui.show()\n\n    def switcher_hide_running():\n        \"\"\"Hides list of running applications\"\"\"\n        gui.hide()\n\n\n@imgui.open(software=False)\ndef gui(gui: imgui.GUI):\n    gui.text(\"Names of running applications\")\n    gui.line()\n    for line in ctx.lists[\"self.running\"]:\n        gui.text(line)\n\n\ndef update_lists():\n    running = {}\n    launch = {}\n\n    for cur_app in ui.apps(background=False):\n        name = cur_app.name\n        if name.endswith(\".exe\"):\n            name = name.rsplit(\".\", 1)[0]\n        words = get_words(name)\n        for word in words:\n            if word and word not in running:\n                running[word.lower()] = cur_app.name\n        running[name.lower()] = cur_app.name\n    for override in overrides:\n        running[override] = overrides[override]\n\n    if app.platform == \"mac\":\n        for base in \"/Applications\", \"/Applications/Utilities\":\n            for name in os.listdir(base):\n                path = os.path.join(base, name)\n                name = name.rsplit(\".\", 1)[0].lower()\n                launch[name] = path\n                words = name.split(\" \")\n                for word in words:\n                    if word and word not in launch:\n                        if len(name) > 6 and len(word) < 3:\n                            continue\n                        launch[word] = path\n\n    lists = {\n        \"self.running\": running,\n        \"self.launch\": launch,\n    }\n\n    # batch update lists\n    ctx.lists.update(lists)\n\n\ndef ui_event(event, arg):\n    if event in (\"app_activate\", \"app_launch\", \"app_close\", \"win_open\", \"win_close\"):\n        # print(f'------------------ event:{event}  arg:{arg}')\n        update_lists()\n\n\nui.register(\"\", ui_event)\nupdate_lists()\n", "path": "code/switcher.py"}]}