2023-02-20

Talon Voice And Cursorless Usage Notes

Purpose And Scope

This post is intended to be a reference for myself and others I am trying to help get the most value out of Talon Voice (with community config) and Cursorless. I will try to cover things that other places do not mention or emphasize.

For instance, my experience is that the semiofficial community documentation does not properly emphasize that adding stuff to additional_words.csv and words_to_replace.csv in the "settings" folder is extremely useful and one of the first customizations you should do.  There are nice commands like "customize additional words" and "customize words to replace" to launch a text editor on those files (currently does not work on Windows 11).  It is also my experience that they do not even mention that you should change the gitignore file to source control all of the settings/*.csv files except for system_paths.csv.  I wish I had known these things earlier, so I'm mentioning here to help others and also to record them for myself.

This post is intended for people who are computer savvy and I will probably not go into depth about git stuff unless it is specifically requested.

Talon Draft Editor

If you get comfortable with Cursorless in vscode, then the draft editor is really nice for dictating and editing stuff.  

  • to start: "draft this/all/line"
  • do your drafting
  • to end: "draft submit/discard"
  • You can do "draft submit" multiple times for the most recent draft.
     

To Flesh Out

To Flesh Out, Talon Voice

I have a talon config GitHub private repo that is forked from talonhub/community and I pull from talonhub/community regularly; the private repo is so I don't have to separate or be afraid about exposing sensitive data.  As much as possible, I tried to put my changes in a personal folder (zz_jme) just under the root folder.  That minimizes merge conflicts.

https://github.com/pokey/upgrade-knausj is a tool to make it easier and safer to pull and merge your personal talonhub/community fork from the official talonhub/community repo.  For instance, it does the merge outside of your talon user folder so that merge conflicts don't break your talon config while you are trying to fix those merge conflicts.

I added every CSV file except for system_paths into source control.  words_to_replace.csv and additional_words.csv are super duper useful for dealing with work and other technical stuff; these are files that you want to start messing with immediately.  There are also commands to help add entries to these files.  Some thoughts on words_to_replace.csv and additional_words.csv:

  • Stuff in additional_words.csv will be top priority in recognition.  This can be great, but also you might not like it heavily preferring the added words over similar words that you say.
  • Stuff in additional_words.csv considered a single word even it is multiple words.  An entry of "some new word, stuff to become new word" will let you do command "word stuff to become new word" to type "some new word".
  • words_to_replace.csv is the best for when you say some common word and talon hears it as a weird word.  Like an entry "say, se" because I never use "se".  Also entries like "intake event, and take event" for phrases.  Unfortunately you have to add plurals and conjugations yourself.

You can terminate say/formatter commands without pausing by using the word "over".  "say let over, space, camel variable name over, space, say more words" types "let variableName more words".  The commas are just to show when commands end.

You can cancel a command if you end your utterance (before timeout expires) with "cancel cancel".

There are some good commands for talon itself.

  • "talon open log" to open a terminal that shows the bottom of talon log.  I often do the command after starting talon and keep it open indefinitely.
  • "talon test <possible commands>" shows in the log what the possible commands would trigger with file names and line numbers. 
  • "talon test last" and "talon test numb <number_small>" are good for understanding what happened with a previous command.
  • "talon home" to open the talon folder, where you are probably interested in the "user" subfolder where your config goes.
  • "help scope" to toggle a pop-up that tells you about the current modes, tags, and app/window info.
  • "talon open rebel", which opens the Talon REPL.  It's like an interactive session of being in one of the talon python files. (related wiki section)
    • You can do various `actions.user.SomeAction(PossibleArgs)` calls and it will execute them.
    • `sim("some spoken words for one or more command")` will interpret the arg like spoken words and tell you which rules (and their corresponding files) would trigger; it won't execute the commands
    • `mimic("one or more commands")` will execute the input as if you spoke it
    • `events.tail()` will show you a lot more logging of what is going on in talon.
    • `actions.speech.replay("path/to/flac/or/wav/file")` to provide an audio file as an input to the speech recognition engine


I have gated my work-specific stuff with "hostname: SomeHostname" context header.

https://tararoys.github.io/Getting-Started-With-Dictation-Mode.html 

Understanding Talon Functionality Itself (Not knausj/talonhub-community)

To get intellisense to work in vscode for Talon Voice, install the Andreas Talon vscode extension. You can also do actions.list("edit") or actions.list("clip") in the Talon REPL to see every method under edit or clip.

Update: try the https://marketplace.visualstudio.com/items?itemName=AndreasArvidsson.andreas-talon https://marketplace.visualstudio.com/items?itemName=AndreasArvidsson.andreas-talon

vscode Notes

Search

Once you do a search ("hunt all" command), you probably want to visit some of the search results.  F4 is a pretty good way to go to the next search result.

 

talon-gaze-ocr

talon-gaze-ocr is really nice.  Just git clone into your talon user folder, and it works.  It is very nice for clicking buttons/links/whatever that have text.  It is also nice for moving your cursor or selecting things for editing text.

Here are what seem to be the most useful commands.  "Teleport" means move the mouse cursor to where you are looking.

  • eye hover: teleport
  • eye [double/right/middle/shift/alt/control] touch/click: teleport, then do that type of click
  • eye scroll up/down/left/right [half]: teleport and mouse wheel scroll
  • [shift/alt/control] click <words_on_screen>: teleport and click at those words
  • go before/after <words_on_screen>: teleport and click before/after those words
    • go before/after <words_on_screen> say <words_to_insert>: also insert text
  • replace [???] seen <words_on_screen> with <words_to_insert>: replace existing text with new text
  • select <words>: select those words
  • ocr show [text/boxes]: show recognized text (default) or boxes around your gaze.

The "eye" commands that include a teleport need an eye tracker.  The "<words_on_screen>" commands work better with an eye tracker because your gaze is used to disambiguate words.


rango

Just say the letters of the hints to click.  "blank <hint>" for new focused tab.  "stash <hint>" for new background tab.  "pre/post <hint>" to go to the beginning or end of a text field.

Lots of nice tab commands, like "tab back", "tab clone" and "tab split".

There are "hints on/off [{user.rango_hints_toggle_levels}]" commands.  The levels are ["everywhere", "global", "tab", "host", "page", "now"].

 "toggle show" to show what the current hint toggle levels are.

 

Miscellaneous

The Voice Book audio tracks: https://www.chicagoreviewpress.com/the-voice-book-pages-630.php

To Flesh Out, Cursorless Stuff

I'm writing some "getting comfortable with Cursorless" doc at guide-intermediate.md which highlights the most useful actions and modifiers, explains some core concepts, and gives lots of common operation examples.

Cursorless Examples

Some examples are at https://github.com/Will-Sommers/cursorless-katas and my guide-intermediate.md, but some examples only live here.

  • core changers
    • bring T [to/before/after T2]; replace selection/T2 with T
    • move T1 [to/before/after T2]
    • change T; delete T and set cursor to T
    • chuck T; delete T
  • selection manipulation
    • take T; set selection
    • give T; deselect (I basically never use this; when I started, it looked important, but I was wrong)
  • line-related commands
    • drop/float T; insert line before or after
    • puff [T]; insert empty lines around
    • drink/pour [T]; edit new line before/after
  • paste to/before/after T
  • carve/copy [T]; cut/copy
  • pre/post T; set selection before/after
  • IDE commands
    • quick fix [T]
    • reference [T]
    • type def [T]
    • scout [all] [T]

"pre this" or "post this" to deselect.

 

“bring row 21 after line” to copy line 21 to line below cursor.

 

"chuck 3 lines row 21" to delete 3 line starting at line 21; "chuck 3 lines" to chuck 3 lines starting at current line.

 

"move tail MARK before its line" to do something like this (the # is the target)...
someCode(); # some comment
to...
# some comment
someCode();

 

 to join two lines together...

  • "move down one [to this]" if your cursor is at the end of the top line
  • "move down one to end of line" if your cursor is somewhere in the top line
  • "move row X+1 to end of row X" if you are not on top line
  • none of the above insert a space between the joined lines; to also get a separating space, do "post row X, space, move down one"
  • alternatively and awesomely, add "join, editor.action.joinLines" to your talon/user/cursorless-settings/experimental/actions_custom.csv file and you can say "join air" to do a join with the air-containing-line as the top line.  Also "join block" or "join air past bat".

 

“change second word air” to change the second word of the air token

“bring second word air to third word bat” to replace the third word of the bat token with the second word of the air token

If you have "setBlahBlahBlah" and you want to change the token after the word "set", then you can say...

  • “change tail token second word MARK”
  • “change second past last word MARK”
    • if you say “change second word past last word MARK”, then you'll affect something other than the token at mark if your cursor is elsewhere.  Not sure exactly what is going on.

"chuck second token" will delete the second token of the current line.  You can also do "chuck second token row seven" to choose the line.

"chuck until next token" is a good way to delete spaces from cursor to the next token.

"chuck arg <target>" to do all the nice formatting and comma stuff of deleting an arg, like "func(x, y, z)" to "func(x, z)".

"bring <target1> after arg <target2>" will nicely add a copy of target1 as an arg.  Like changing "func(xray)" to "func(xray, yankee)" would probably use "bring yank after arg plex".

"paste before <target>" to paste before something, but it will add a space before the target (I think if the target is not a line/block/whatever).  "paste before line" and "paste after row 7" are very useful.

"paste before just <target>" or "paste to start of <target>" to paste before something without an added space

"chuck trailing that" will delete the added space from a paste; the "that" refers to the thing that was pasted

"chuck tail inside" will delete from cursor until the first-hit ending curly/square/paren.  It is an okay way to delete a tail of a function


Deleting tokens using slices:

If you have...

a b c
d e f
g h i

and you want to delete {a b d e g h}, then do "pre air slice gust, chuck two tokens" (pre command, then chuck command). Once issue 1279 gets resolved, you can do "chuck two tokens air slice gust".

If there are empty lines, you have to do "take air slice gust, give empty, chuck two tokens".



Imagine I want cursors at the non-whitespace beginning of each line in a contiguous group of lines (ex: lines 5-8).  Here are some ways:

  • "pre row 5 and row 6 and row 7 and row 8" works but is verbose
  • "pre row 5 slice row 8" is the slice way.  Slice is meant for selections across lines, so the command is terse.  If your cursor is at the starting line, you can say "line" instead of "row 5".
  • "pre every line [row 5] past row 8" works and is wordier.  The "row 5" is optional if your cursor is at the starting line.
  • "pre every line 4 lines [row 5]" works and lets you provide how many lines rather that an end.  The "row 5" is optional if your cursor is at the starting line.
  • You don't have to do everything row based.  You could use "pre every line air past bat" or "pre every line 4 lines air" because the "every line" will transform the targets into lines. Likewise with "pre line air slice bat".
 Keep your mind open to alternate ways of thinking about it. Maybe "pre every line block [target]" would work if the contiguous lines are a full block.  Also, if your cursor is already at the beginning of the first desired line, then the following work: "pre slice row 8", "pre slice down 3".

These do not work:

  • "pre 3 lines row 5" just puts cursor it beginning of row 5 because the target is a single target.
  • "pre row 5 past row 7" has the same problem for the same reason.


"bring this to after token row forty one" will bring the selection to the end of row 41 and insert a separating space as well (because we treated row 41 as a token and thus used a token delimiter).


"take head inside air" is a way to operate on the span within a pair up to the mark.


"chuck leading block [SomeMark]" will delete the empty lines before the targeted block.  You can also do "chuck trailing block [SomeMark]" to delete empty lines after the targeted block.

Imagine you want to go from "(a[i] === true || b[j] === false)" to "(b[j] === false)"; then "chuck 4 short paints air" will do it.  "paint" expands a target left and right until it hits whitespace.  "short paint" expands a target until it hits white space or a surrounding pair character.  Let's walk through doing "short paint air" and how it goes from "a" to "a[i]".  Starting with "a" and expanding leftward, we hit "(" which is part of a pair that surrounds where we started, so we do not expand leftward at all.  Expanding rightward, we add "[i]" and stop at a space.  The square brackets do not surround the original target, so short paint can expand over them.

Cursorless treats kebab-case stuff (ex: `aaa-bbb-ccc`) as separate tokens, but you can still do "take N identifier <mark>" and it will flow over the dashes.  Like "take two identifiers bat" would select `bbb-ccc` from `aaa-bbb-ccc`); that is a bit easier than "take three tokens bat" where you have to count the dashes.  You can also add a `stick,\w[\w-]+` entry to your `cursorless-settings\experimental\regex_scope_types.csv` file (uses javascript regex).

Sometimes you have some lines selected, and when you cut/move the multi-line selection, an extra blank line is left behind.   Command "move line this to <target>" helps to not leave behind an extra blank line.

 

"take first token until <hat>" won't work because of inference.  Do "take first token until token <hat>".

 

In some C++ text, "func(/*comment*/a);", the command "take arg air" will just select the "a", but "take item air" will select the comment as well.

No comments:

Post a Comment