internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: talonhub/community

Issue:
Number small can go larger than 100
If you say "ten five" number small will be 105.
Number small can go larger than 100
If you say "ten five" number small will be 105.


Discussion:

Resolving patch:
diff --git a/code/numbers.py b/code/numbers.py
--- a/code/numbers.py
+++ b/code/numbers.py
@@ -5,14 +5,14 @@
 ctx = Context()
 
 digits = "zero one two three four five six seven eight nine".split()
-teens = "eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen".split()
-tens = "ten twenty thirty forty fifty sixty seventy eighty ninety".split()
+teens = "ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen".split()
+tens = "twenty thirty forty fifty sixty seventy eighty ninety".split()
 scales = "hundred thousand million billion trillion quadrillion quintillion sextillion septillion octillion nonillion decillion".split()
 
 digits_map = {n: i for i, n in enumerate(digits)}
 digits_map["oh"] = 0
-teens_map = {n: i + 11 for i, n in enumerate(teens)}
-tens_map = {n: 10 * (i + 1) for i, n in enumerate(tens)}
+teens_map = {n: i + 10 for i, n in enumerate(teens)}
+tens_map = {n: 10 * (i + 2) for i, n in enumerate(tens)}
 scales_map = {n: 10 ** (3 * (i+1)) for i, n in enumerate(scales[1:])}
 scales_map["hundred"] = 100
 
@@ -44,7 +44,7 @@ def scan_small_numbers(l: List[str]) -> Iterator[Union[str,int]]:
     while l:
         n = l.pop()
         # fuse tens onto digits, eg. "twenty", "one" -> 21
-        if n in tens_map and n != "ten" and l and digits_map.get(l[-1], 0) != 0:
+        if n in tens_map and l and digits_map.get(l[-1], 0) != 0:
             d = l.pop()
             yield numbers_map[n] + numbers_map[d]
         # turn small number terms into corresponding numbers


Test patch:
Repository: talonhub/community

Issue:
Tab last/next in Mac terminals should switch tabs
`tab next` and `tab last` don't do anything in the Mac terminal.

For a quick look at the code, it looks like the tag is implemented, so I suspect it just needs some custom keybindings.
https://github.com/knausj85/knausj_talon/blob/master/apps/platforms/mac/terminal/terminal.talon#L8


Latest knausj master, August 2nd 2021
Talon 0.2.0-8
Terminal version 2.10 (433)


Discussion:

Resolving patch:
diff --git a/apps/platforms/mac/terminal/terminal.py b/apps/platforms/mac/terminal/apple_terminal.py
similarity index 65%
rename from apps/platforms/mac/terminal/terminal.py
rename to apps/platforms/mac/terminal/apple_terminal.py
--- a/apps/platforms/mac/terminal/terminal.py
+++ b/apps/platforms/mac/terminal/apple_terminal.py
@@ -1,4 +1,4 @@
-from talon import Context, Module, actions, imgui, settings, ui
+from talon import Context, actions, ui
 import os
 
 # TODO: fit this to generic_terminal
@@ -14,12 +14,15 @@
 class EditActions:
     def delete_line(): actions.key('ctrl-u')
 
-
 @ctx.action_class('user')
 class UserActions:
     def file_manager_current_path():
         title = ui.active_window().title
 
+        #take the first split for the zsh-based terminal
+        if " — " in title:
+            title = title.split(" — ")[0]
+
         if "~" in title:
             title = os.path.expanduser(title)
 
@@ -40,7 +43,9 @@ def file_manager_open_directory(path: str):
         path = '"{}"'.format(path)
         actions.insert(path)
         actions.key("enter")
-        actions.user.file_manager_refresh_title()
+
+        #jtk - refresh title isn't necessary since the apple terminal does it for us
+        #actions.user.file_manager_refresh_title()
         
     def file_manager_open_parent():
         actions.insert('cd ..')
@@ -65,33 +70,20 @@ def file_manager_select_file(path: str):
         """selects the file"""
         actions.insert(path)
 
-    def terminal_list_directories():
-        actions.insert("ls")
-        actions.key("enter")
+    def file_manager_refresh_title():
+        return
 
-    def terminal_list_all_directories():
-        actions.insert("ls -a")
-        actions.key("enter")
+@ctx.action_class("app")
+class app_actions:
+    # other tab functions should already be implemented in 
+    # code/platforms/mac/app.py
 
-    def terminal_change_directory(path: str):
-        actions.insert("cd {}".format(path))
-        if path:
-            actions.key("enter")
+    def tab_previous():
+        actions.key("ctrl-shift-tab")
 
-    def terminal_change_directory_root():
-        """Root of current drive"""
-        actions.insert("cd /")
-        actions.key("enter")
-
-    def terminal_clear_screen():
-        """Clear screen"""
-        actions.key("ctrl-l")
+    def tab_next():
+        actions.key("ctrl-tab")
+        
 
-    def terminal_run_last():
-        actions.key("up enter")
 
-    def terminal_kill_all():
-        actions.key("ctrl-c")
-        actions.insert("y")
-        actions.key("enter")
 


Test patch:
Repository: talonhub/community

Issue:
"million", "billion", "thousand" etc should not be valid numbers
They should require a prefix such as "one", eg "one million"


Discussion:
This is difficult to do in general without abandoning or at least modifying the bag-of-words approach to the number capture, which aegis suggested to improve dfa & parsing performance.

Would it satisfy you to only prohibit numbers from *starting* with the words "million", "billion", "thousand", etc? That would be easier and probably not significantly worse from a perf POV.
Here are some options. Below`scale_word` means hundred, thousand, million, billion, etc; `value_word` means any other numeric word (zero, one, ..., nineteen, twenty, thirty, ..., ninety); and `number_word` means both combined.

1. `{value_word} ({number_word} | and)*`. Simplest but allows numbers to end with "and".
2. `{value_word} {number_word}* (and {number_word}+)*`. Smallest change to what we have now.
3. `({value_word} [{scale_word}+ [and {value_word}]])+`. This rules out "million" without a prefix (& so on) in any position. Complex, would want @lunixbochs approval and some testing to make sure it doesn't cause dfa compile issues or parser issues for long numbers.

Yeah def worth understanding impact on DFA if we move away from bag of words.  @lunixbochs was this the kind of grammar what you had in mind?
Reminder to myself: try each option and see what effect it has on both dfa compile times and parse times.

Resolving patch:
diff --git a/code/numbers.py b/code/numbers.py
--- a/code/numbers.py
+++ b/code/numbers.py
@@ -155,6 +155,10 @@ def split_list(value, l: list) -> Iterator:
 alt_tens = "(" + ("|".join(tens_map.keys())) + ")"
 alt_scales = "(" + ("|".join(scales_map.keys())) + ")"
 number_word = "(" + "|".join(numbers_map.keys()) + ")"
+# don't allow numbers to start with scale words like "hundred", "thousand", etc
+leading_words = numbers_map.keys() - scales_map.keys()
+leading_words -= {'oh', 'o'} # comment out to enable bare/initial "oh"
+number_word_leading = f"({'|'.join(leading_words)})"
 
 # TODO: allow things like "double eight" for 88
 @ctx.capture("digit_string", rule=f"({alt_digits} | {alt_teens} | {alt_tens})+")
@@ -165,7 +169,7 @@ def digits(m) -> int:
     """Parses a phrase representing a digit sequence, returning it as an integer."""
     return int(m.digit_string)
 
-@mod.capture(rule=f"{number_word}+ (and {number_word}+)*")
+@mod.capture(rule=f"{number_word_leading} ([and] {number_word})*")
 def number_string(m) -> str:
     """Parses a number phrase, returning that number as a string."""
     return parse_number(list(m))


Test patch:
Repository: talonhub/community

Issue:
Shouldn't call methods directly on an @action_class
You shouldn't call methods directly on an @action_class, for example:

https://github.com/knausj85/knausj_talon/blob/65ccd94b8fe97056a34b858b2f1f261cc5269c3f/mouse_grid/mouse_grid.py#L282

This will continue to work, but generate a warning in the next beta.

You should probably use `actions.self.grid_narrow(...)` instead.


Discussion:
Looks like that is the only instance of this practise in the repo:

```python
import sys

# Usage find . -name "*.py" | python finder.py | less

for file_ in sys.stdin:
    file = file_.strip()

    with open(file) as fh:
        lines = fh.readlines()

    action_classes = []
    for line1, line2 in zip(lines, lines[1:]):
        if "action_class" in line1.strip() and line1.startswith("@"):
            assert line2.startswith("class ")
            action_classes.append(line2[6:line2.find(":")])

    first = True
    for line in lines:
        for action_class in action_classes:
            if f"{action_class}." in line:
                if first:
                    print(f"\n{file}:")
                    first = False
                print(line.strip())
```

Resolving patch:
diff --git a/mouse_grid/mouse_grid.py b/mouse_grid/mouse_grid.py
--- a/mouse_grid/mouse_grid.py
+++ b/mouse_grid/mouse_grid.py
@@ -1,6 +1,6 @@
 # courtesy of https://github.com/timo/
 # see https://github.com/timo/talon_scripts
-from talon import Module, Context, app, canvas, screen, settings, ui, ctrl, cron
+from talon import Module, Context, actions, app, canvas, screen, settings, ui, ctrl, cron
 from talon.skia import Shader, Color, Paint, Rect
 from talon.types.point import Point2d
 from talon_plugins import eye_mouse, eye_zoom_mouse
@@ -279,7 +279,7 @@ def grid_select_screen(screen: int):
     def grid_narrow_list(digit_list: typing.List[str]):
         """Choose fields multiple times in a row"""
         for d in digit_list:
-            GridActions.grid_narrow(int(d))
+            actions.self.grid_narrow(int(d))
 
     def grid_narrow(digit: Union[int, str]):
         """Choose a field of the grid and narrow the selection down"""


Test patch:
Repository: talonhub/community

Issue:
auto_insert is documented to call auto_format
I understand if you want to override `auto_insert` too because you're adjusting the cursor position afterwards, but the general intention is for `auto_format` to do text formatting

I think the dictation `auto_insert()` implementation should potentially first `text = auto_format(text)` (which is the identity function by default) as per the docstring:
```
auto_insert(text: str)
  Insert text at the current cursor position, automatically formatting it using actions.auto_format(text)
```

https://github.com/knausj85/knausj_talon/blob/master/code/dictation.py#L401


Discussion:
This apparently dates back to context sensitive dictation, which moves the cursor around and selects text to figure out the surrounding context. Even without this, dictation context is stateful, and prior to context sensitive dictation, so was user.auto_format. Hence, to achieve this we would need to separate the contextual formatting from auto_format and possibly even the stateful formatting if we want auto_format to be stateless. The latter would be particularly difficult considering how the DictationFormat object uses state extensively. Considering all that, do you think this would be a change for the better or would you suggest another approach? We could also simply re-implement auto_format to use a fresh DictationFormat object, which would provide approximately the same behavior, but would not exactly match the auto_insert docs.

@rntz (added support for context sensitive dictation)
I think what aegis was suggesting was not that we try to move all of our dictation formatting into auto_format, which would be difficult for the reasons you give, but rather that the first thing we should do in auto_insert should be to call auto_format, so that if the user overrides it their auto formatting will get applied. This should be a simple fix.

Resolving patch:
diff --git a/code/dictation.py b/code/dictation.py
--- a/code/dictation.py
+++ b/code/dictation.py
@@ -398,4 +398,5 @@ def dictation_peek_right() -> Optional[str]:
 
 @dictation_ctx.action_class("main")
 class main_action:
-    def auto_insert(text): actions.user.dictation_insert(text)
+    def auto_insert(text):
+        actions.user.dictation_insert(actions.auto_format(text))


Test patch:
Repository: talonhub/community

Issue:
'go <arrow keys>' conflicts with generic_editor 'go left/right/up/down'
This is really only a problem if the edit actions are overridden, but one might want to do so for `vim`...


Discussion:
What behavior do you think you would like? I see three options:

1. Remove the generic_editor `go left/right/up/down` commands and only have `go <arrow keys>`. If you want custom commands for the edit actions, you can add them yourself.

2. Have `go <arrow keys>` use `edit.left()`/`edit.right()` etc instead of pressing the corresponding keys. Since the default implementations of these are to press the arrow keys, this should be *mostly* ok? However, it means there's no command to just press those arrow keys if `edit.left()` etc are overridden. Hm.

3. Have separate commands for pressing the arrow keys and issuing the edit actions. I'm not sure what these would be called, though.
> Have separate commands for pressing the arrow keys and issuing the edit actions. I'm not sure what these would be called, though.

I've seen people (myself included) use the cardinal directions. Not sure if they should belong in knausj_talon, but something to consider.

In that scenario I think it would make sense to keep `go <arrow keys>` sending the raw keys, to keep things simple.
Yeah, I'm inclined to leave `go <arrow keys>` as is and remove or comment out the go left/right/up/down commands in generic_editor.
I would definitely keep `go <arrow keys>`as-is

Could always use a synonym like walk/march/trek if there's value in keeping the generic_editor commands, but I'd be tempted to make that application-specific. 
The approach we landed on during the grooming session today was to 

- have `go <user.arrow_keys>` map to `edit.direction` in generic editor (pressing the arrow keys as many times as was chained), 
- but then have a separate command `press <user.unmodified_key>` which can be used to directly press the specific key such as up or down 

wdyt @rntz ?
That seems ok, although it means `press` has three quite different meanings:

1. `press <user.keys>` to press a sequence of keys in *dictation* mode.
2. `press <user.modifiers>` to press a modifier key in command mode, eg. `press super`.
3. `press <user.unmodified_key>` to press an unmodified key in command mode, eg `press left`.

We already had (1) & (2), so this issue already existed, this just makes it more obvious. Maybe this merits a separate issue.

Anyway, if there are folks who want this, and knausj has signed off, I have no objection.

Resolving patch:
diff --git a/code/keys.py b/code/keys.py
--- a/code/keys.py
+++ b/code/keys.py
@@ -249,3 +249,12 @@ def letters(m) -> str:
 }
 
 
+@mod.action_class
+class Actions:
+    def move_cursor(s: str):
+        """Given a sequence of directions, eg. 'left left up', moves the cursor accordingly using edit.{left,right,up,down}."""
+        for d in s.split():
+            if d in ('left','right','up','down'):
+                getattr(actions.edit, d)()
+            else:
+                raise RuntimeError(f'invalid arrow key: {d}')


Test patch:
Repository: talonhub/community

Issue:
Improve phrase history mechanism
instead of this:

https://github.com/knausj85/knausj_talon/blob/3e57e0165257cf07b0e21880d44a91e79cb3ef16/code/history.py#L19-L29

consider something like this:

```py
def on_phrase(j):
    global history
    words = j.get('text')
    if words:
        text = ' '.join(words)
        history.append(text)
        history = history[-setting_command_history_size.get() :]
```


Discussion:

Resolving patch:
diff --git a/code/history.py b/code/history.py
--- a/code/history.py
+++ b/code/history.py
@@ -1,3 +1,4 @@
+from typing import Optional
 from talon import imgui, Module, speech_system, actions, app
 
 # We keep command_history_size lines of history, but by default display only
@@ -12,20 +13,15 @@
 history = []
 
 
-def parse_phrase(word_list):
-    return " ".join(word.split("\\")[0] for word in word_list)
-
-
 def on_phrase(j):
     global history
 
-    try:
-        val = parse_phrase(getattr(j["parsed"], "_unmapped", j["phrase"]))
-    except:
-        val = parse_phrase(j["phrase"])
+    words = j.get('text')
+
+    text = actions.user.history_transform_phrase_text(words)
 
-    if val != "":
-        history.append(val)
+    if text is not None:
+        history.append(text)
         history = history[-setting_command_history_size.get() :]
 
 
@@ -85,3 +81,11 @@ def history_get(number: int):
         """returns the history entry at the specified index"""
         num = (0 - number) - 1
         return history[num]
+
+    def history_transform_phrase_text(words: list[str]) -> Optional[str]:
+        """Transforms phrase text for presentation in history. Return `None` to omit from history"""
+
+        if not actions.speech.enabled():
+            return None
+
+        return ' '.join(words) if words else None
\ No newline at end of file


Test patch:
Repository: talonhub/community

Issue:
Do we need _capitalize_defaults now that Talon lexicon includes capitalization?



Discussion:
Did some testing, it looks like the the only things we still need are the month names, because apart from January and February the lexicon doesn't capitalize any of the others. March and may I understand, since they're common english words (we don't capitalize them by default either). August is technically an adjective but the month is much more common. The others seem like oversights.

Resolving patch:
diff --git a/code/vocabulary.py b/code/vocabulary.py
--- a/code/vocabulary.py
+++ b/code/vocabulary.py
@@ -10,31 +10,15 @@
 mod.list("vocabulary", desc="additional vocabulary words")
 
 
-# Default words that will need to be capitalized (particularly under w2l).
-# NB. These defaults and those later in this file are ONLY used when
+# Default words that will need to be capitalized.
+# DON'T EDIT THIS. Edit settings/words_to_replace.csv instead.
+# These defaults and those later in this file are ONLY used when
 # auto-creating the corresponding settings/*.csv files. Those csv files
 # determine the contents of user.vocabulary and dictate.word_map. Once they
 # exist, the contents of the lists/dictionaries below are irrelevant.
 _capitalize_defaults = [
-    "I",
-    "I'm",
-    "I've",
-    "I'll",
-    "I'd",
-    "Monday",
-    "Mondays",
-    "Tuesday",
-    "Tuesdays",
-    "Wednesday",
-    "Wednesdays",
-    "Thursday",
-    "Thursdays",
-    "Friday",
-    "Fridays",
-    "Saturday",
-    "Saturdays",
-    "Sunday",
-    "Sundays",
+    # NB. the lexicon now capitalizes January/February by default, but not the
+    # others below. Not sure why.
     "January",
     "February",
     # March omitted because it's a regular word too
@@ -42,7 +26,7 @@
     # May omitted because it's a regular word too
     "June",
     "July",
-    "August",
+    "August", # technically also an adjective but the month is far more common
     "September",
     "October",
     "November",


Test patch:
Repository: talonhub/community

Issue:
redundant empty list initialization
Shouldn't be a need to do this empty list initialization anymore, it was fixed a while back in public:
https://github.com/knausj85/knausj_talon/blob/97bf66e/code/switcher.py#L358-L362


Discussion:

Resolving patch:
diff --git a/code/switcher.py b/code/switcher.py
--- a/code/switcher.py
+++ b/code/switcher.py
@@ -354,13 +354,6 @@ def ui_event(event, arg):
     if event in ("app_launch", "app_close"):
         update_running_list()
 
-
-# Currently update_launch_list only does anything on mac, so we should make sure
-# to initialize user launch to avoid getting "List not found: user.launch"
-# errors on other platforms.
-ctx.lists["user.launch"] = {}
-ctx.lists["user.running"] = {}
-
 # Talon starts faster if you don't use the `talon.ui` module during launch
 
 


Test patch:
Repository: talonhub/community

Issue:
formatter accuracy
This has come up a couple of times. I suspect you'll improve formatter accuracy if you make these changes:

"allcaps" -> "all cap"
"alldown" -> "all down"

The reason for this is e.g. "alldown" is not an english word, D sounds like T, so "alld" sounds like alt, and you get "alt down".
Same for allcaps. Allc sounds a bit like alt, and you get "alt cap".

allcaps has a second problem. If you say "allcaps something", the S S (cap(s s)omething) chain will blend together in your speech and you'll get something that might sound more like "alt cap something". Hence removing the S.


Discussion:
I would be tempted to leave this one where @rntz left it, with "all caps", because I'd worry "all cap" would lead to some accuracy issues wrt "alt cap".  Shall we close this one out?
It's the other way around! Binding it as `all caps` can cause misrecognitions as `alt cap` when you say a word starting with an s. It's human nature to collapse a double-s - e.g. listen to yourself saying "all caps something" out loud quickly (and IMO the engine isn't even wrong, after listening to user recordings, the problem is with the command words as defined)

I mentioned this case in the original comment. I actually did test several variants of this and you should not close the issue without fixing the double-S case. In my testing, `all cap` performed better than `all caps`.
ahh ok yeah. For some reason it made more sense the second time you said it 🤷‍♂️😄

do we want to keep "all caps" as a synonym?  @lunixbochs in your testing did you try saying "all caps" when the term was mapped as "all cap", or just tried "all cap"?
I did test saying "all caps" when it was bound as "all cap" and it worked, still better than when only "allcaps" was bound.

A possible issue with binding both, is now you may have a problem of homophones that only differ by whether the word starts with an `s`.

I would suggest just binding "all cap" and re-evaluate if new complaints surface. We're still likely going to be much better off than the old "allcaps" command.

Resolving patch:
diff --git a/code/formatters.py b/code/formatters.py
--- a/code/formatters.py
+++ b/code/formatters.py
@@ -124,7 +124,7 @@ def every_word(word_func):
 
 # This is the mapping from spoken phrases to formatters
 formatters_words = {
-    "all caps": formatters_dict["ALL_CAPS"],
+    "all cap": formatters_dict["ALL_CAPS"],
     "all down": formatters_dict["ALL_LOWERCASE"],
     "camel": formatters_dict["PRIVATE_CAMEL_CASE"],
     "dotted": formatters_dict["DOT_SEPARATED"],


Test patch: