Skip to content

Commit

Permalink
Cursorless tutorial units 1 & 2 (#360)
Browse files Browse the repository at this point in the history
<img width="773" alt="image"
src="https://github.com/user-attachments/assets/ae0d024b-a810-4eab-add5-732f1171d9ef">



## Todo

- [x] Install locally and try everything out
- [x] Try "cursorless docs" both inside and outside of VSCode
- [x] I have not broken the cheatsheet
- [x] Make it more obvious that the tutorial list is a list of all
tutorials
- [x] Change what we show when tutorial prereqs no longer met, eg
"prereqs not met, feel free to keep playing, and say resume to resume"
- [x] Add note at end of unit 1 suggesting they continue to play with
the document
- [x] Tune tutorial content. Move / add docs tip to end of first
tutorial. More stuff maybe better for follow-up PR
- [x] Point out that we're using highlights for marks in first tutorial
step
- [x] Have "tutorial exit" command and corresponding button
- [x] Add paragraph break between sentences in step
- [x] Workshop the actual text in the editor itself so that it indicates
they should look at the side bar
- [x] Make color of commands stand out more
- [x] Properly support custom actions and other necessary custom spoken
forms
- [x] Store current progress in local storage (and sync it)
- [x] Properly support custom symbol spoken forms (eg alphabet)
- [x] Add "tutorial restart"
- [x] I have added
[tests](https://www.cursorless.org/docs/contributing/test-case-recorder/)
- [x] Fix scope tree view
- [x] How to handle disabled hat color?
- [x] Figure out unicode for emoji
- [x] Figure out what "cursorless tutorial" should actually do.
Currently starts second tutorial, which is obv not what we want
- [x] Figure out how to advance from last step of initial tutorial, as
it has no action to perform
- [x] Add "tutorial next" / "tutorial previous" commands
- [x] Add tutorial step saying to use "cursorless help" cheatsheat
- [x] Fix broken references to css eg reset
- [x] Invalidate state if custom spoken forms change
- [x] Change view when we detect that prereqs are no longer met (eg
cursor in wrong place, etc). Indicate they should say "tutorial
continue" / "tutorial restore" / "cursorless tutorial" to reset the
prereqs
- [x] Merge HUD changes
- [x] Figure out how to properly detect VSCode focused
- [x] Highlight marks that need to be targeted, so user doesn't have to
search for them
- [x] Remove print statements and commented out code from `tutorial.py`
- [x] Figure out how to only run step preparation when you have the
right window focused. Some of the time @pokey gets error message after
"cursorles help" step
<img width="385" alt="image"
src="https://github.com/cursorless-dev/cursorless/assets/755842/fc9bbcbd-111c-48e0-80b5-beeed8dafaea">
- [x] Open new window on start?
- [x] Ensure you're in the right window / editor before restoring state,
so we don't accidentally clobber something
- [x] Get it to work with mainline Talon HUD
- [x] Finish constructing spoken forms from commands
- [x] Use [app
name](https://github.com/pokey/cursorless-vscode/blob/a81dd0ce5f6359482fe9afc55a47ceb142cac17d/cursorless-talon/src/tutorial.py#L17)
for VSCode that works cross-platform
- [x] Figure out what todo with the fact that the cheatsheet clobbers
the entire screen and you can't even see the close button (#619)

See also cursorless-dev/cursorless-talon#143

### Unit 2

- Python
- Have an action class?

To cover:

- [x] New scope types
- [x] New actions, including
  - [x] single argument "bring"
  - [x] multiple argument "bring"
  - [x] "move"
  - [x] "swap"
- [x] Simple inference in the context of multiple target actions such as
swap or bring

### Extra unit

- [x] Probably want to move this into a new pull request
- [x] Create a json script for it
- [x] Don't forget to add the intermediate steps where it was not a
cursorless command and so isn't recorded

## Links

### Helpful places in our code base

-
https://github.com/cursorless-dev/cursorless/blob/main/packages/cursorless-vscode-e2e/src/suite/recorded.vscode.test.ts
sets up file to initial state of tutorial step
- to generate a spoken form from the command payload in the yaml:
https://github.com/cursorless-dev/cursorless/blob/a9cc79f287a0278faf1198f9775cef6932630800/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts#L95
- this is where you'll send a command to cursorless requesting it to set
up initial tutorial step state and have it return generated spoken form:
https://github.com/cursorless-dev/cursorless/pull/360/files#diff-5c1cd9d422f7c8df0325fd0958446c90873fb338c462287ef5f57606a363658bR35-R37
- registering a new command extension-side
https://github.com/cursorless-dev/cursorless/blob/a9cc79f287a0278faf1198f9775cef6932630800/packages/cursorless-vscode/src/extension.ts#L125

### In case we decided to look into VSCode walkthroughs rather than
Talon hud

-
https://code.visualstudio.com/api/references/contribution-points#contributes.walkthroughs

---------

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
  • Loading branch information
pokey and pre-commit-ci-lite[bot] authored Jul 19, 2024
1 parent 2c322ab commit d7fe84b
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 1 deletion.
7 changes: 7 additions & 0 deletions src/cheatsheet/cheat_sheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from .sections.modifiers import get_modifiers
from .sections.scopes import get_scopes
from .sections.special_marks import get_special_marks
from .sections.tutorial import get_tutorial_entries

mod = Module()
ctx = Context()
Expand All @@ -37,6 +38,7 @@ def private_cursorless_cheat_sheet_update_json():

def private_cursorless_open_instructions():
"""Open web page with cursorless instructions"""
actions.user.private_cursorless_notify_docs_opened()
webbrowser.open(instructions_url)


Expand Down Expand Up @@ -150,5 +152,10 @@ def cursorless_cheat_sheet_get_json():
"id": "shapes",
"items": get_list("hat_shape", "hatShape"),
},
{
"name": "Tutorial",
"id": "tutorial",
"items": get_tutorial_entries(),
},
]
}
83 changes: 83 additions & 0 deletions src/cheatsheet/sections/tutorial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
def get_tutorial_entries():
return [
{
"id": "start_tutorial",
"type": "command",
"variations": [
{
"spokenForm": "cursorless tutorial",
"description": "Start the introductory Cursorless tutorial",
},
],
},
{
"id": "tutorial_next",
"type": "command",
"variations": [
{
"spokenForm": "tutorial next",
"description": "Advance to next step in tutorial",
},
],
},
{
"id": "tutorial_previous",
"type": "command",
"variations": [
{
"spokenForm": "tutorial previous",
"description": "Go back to previous step in tutorial",
},
],
},
{
"id": "tutorial_restart",
"type": "command",
"variations": [
{
"spokenForm": "tutorial restart",
"description": "Restart the tutorial",
},
],
},
{
"id": "tutorial_resume",
"type": "command",
"variations": [
{
"spokenForm": "tutorial resume",
"description": "Resume the tutorial",
},
],
},
{
"id": "tutorial_list",
"type": "command",
"variations": [
{
"spokenForm": "tutorial list",
"description": "List all available tutorials",
},
],
},
{
"id": "tutorial_close",
"type": "command",
"variations": [
{
"spokenForm": "tutorial close",
"description": "Close the tutorial",
},
],
},
{
"id": "tutorial_start_by_number",
"type": "command",
"variations": [
{
"spokenForm": "tutorial <number>",
"description": "Start a specific tutorial by number",
},
],
},
]
61 changes: 60 additions & 1 deletion src/cursorless.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from talon import Module, actions
from talon import Context, Module, actions

mod = Module()

Expand All @@ -7,6 +7,11 @@
"Application supporting cursorless commands",
)

ctx = Context()
ctx.matches = r"""
tag: user.cursorless
"""


@mod.action_class
class Actions:
Expand All @@ -16,8 +21,62 @@ def private_cursorless_show_settings_in_ide():
def private_cursorless_show_sidebar():
"""Show Cursorless-specific settings in ide"""

def private_cursorless_notify_docs_opened():
"""Notify the ide that the docs were opened in case the tutorial is waiting for that event"""
actions.skip()

def private_cursorless_show_command_statistics():
"""Show Cursorless command statistics"""
actions.user.private_cursorless_run_rpc_command_no_wait(
"cursorless.analyzeCommandHistory"
)

def private_cursorless_start_tutorial():
"""Start the introductory Cursorless tutorial"""
actions.user.private_cursorless_run_rpc_command_no_wait(
"cursorless.tutorial.start", "tutorial-1-basics"
)

def private_cursorless_tutorial_next():
"""Cursorless tutorial: next"""
actions.user.private_cursorless_run_rpc_command_no_wait(
"cursorless.tutorial.next"
)

def private_cursorless_tutorial_previous():
"""Cursorless tutorial: previous"""
actions.user.private_cursorless_run_rpc_command_no_wait(
"cursorless.tutorial.previous"
)

def private_cursorless_tutorial_restart():
"""Cursorless tutorial: restart"""
actions.user.private_cursorless_run_rpc_command_no_wait(
"cursorless.tutorial.restart"
)

def private_cursorless_tutorial_resume():
"""Cursorless tutorial: resume"""
actions.user.private_cursorless_run_rpc_command_no_wait(
"cursorless.tutorial.resume"
)

def private_cursorless_tutorial_list():
"""Cursorless tutorial: list all available tutorials"""
actions.user.private_cursorless_run_rpc_command_no_wait(
"cursorless.tutorial.list"
)

def private_cursorless_tutorial_start_by_number(number: int): # pyright: ignore [reportGeneralTypeIssues]
"""Start Cursorless tutorial by number"""
actions.user.private_cursorless_run_rpc_command_no_wait(
"cursorless.tutorial.start", number - 1
)


@ctx.action_class("user")
class CursorlessActions:
def private_cursorless_notify_docs_opened():
actions.user.private_cursorless_run_rpc_command_no_wait(
"cursorless.documentationOpened"
)
10 changes: 10 additions & 0 deletions src/cursorless.talon
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,13 @@ bar {user.cursorless_homophone}:

{user.cursorless_homophone} stats:
user.private_cursorless_show_command_statistics()

{user.cursorless_homophone} tutorial:
user.private_cursorless_start_tutorial()
tutorial next: user.private_cursorless_tutorial_next()
tutorial (previous | last): user.private_cursorless_tutorial_previous()
tutorial restart: user.private_cursorless_tutorial_restart()
tutorial resume: user.private_cursorless_tutorial_resume()
tutorial (list | close): user.private_cursorless_tutorial_list()
tutorial <user.private_cursorless_number_small>:
user.private_cursorless_tutorial_start_by_number(private_cursorless_number_small)

0 comments on commit d7fe84b

Please sign in to comment.