Skip to content

Commit

Permalink
Cursorless tutorial
Browse files Browse the repository at this point in the history
  • Loading branch information
pokey committed Jul 13, 2024
1 parent b9590b4 commit 57ed77b
Show file tree
Hide file tree
Showing 74 changed files with 3,016 additions and 12 deletions.
22 changes: 22 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
},
"group": "build"
},
{
"label": "Build tutorial webview",
"type": "npm",
"script": "build:dev",
"path": "packages/cursorless-vscode-tutorial-webview",
"presentation": {
"reveal": "silent"
},
"group": "build"
},
{
"label": "Build test harness",
"type": "npm",
Expand All @@ -57,6 +67,7 @@
"type": "npm",
"script": "populate-dist",
"path": "packages/cursorless-vscode",
"dependsOn": ["Build tutorial webview"],
"presentation": {
"reveal": "silent"
},
Expand Down Expand Up @@ -103,6 +114,17 @@
"dependsOn": ["Watch esbuild", "Watch typescript"],
"group": "build"
},
{
"label": "watch tutorial",
"type": "npm",
"script": "watch:tailwind",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"path": "packages/cursorless-vscode-tutorial-webview",
"group": "build"
},
{
"type": "npm",
"script": "watch:esbuild",
Expand Down
1 change: 1 addition & 0 deletions cursorless-talon/src/cheatsheet/cheat_sheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,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
68 changes: 67 additions & 1 deletion cursorless-talon/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,13 @@
"Application supporting cursorless commands",
)

global_ctx = Context()

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


@mod.action_class
class Actions:
Expand All @@ -16,8 +23,67 @@ 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"""
...

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", "unit-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
)


@global_ctx.action_class("user")
class GlobalActions:
def private_cursorless_notify_docs_opened():
# Do nothing if we're not in a Cursorless context
pass


@cursorless_ctx.action_class("user")
class CursorlessActions:
def private_cursorless_notify_docs_opened():
actions.user.private_cursorless_run_rpc_command_no_wait("cursorless.docsOpened")
11 changes: 11 additions & 0 deletions cursorless-talon/src/cursorless.talon
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,14 @@ 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: user.private_cursorless_tutorial_list()
tutorial <user.private_cursorless_number_small>:
user.private_cursorless_tutorial_start_by_number(private_cursorless_number_small)
30 changes: 30 additions & 0 deletions data/fixtures/recorded/tutorial/unit-1-basics/changeSit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
languageId: plaintext
command:
version: 7
spokenForm: change sit
action:
name: clearAndSetSelection
target:
type: primitive
mark: {type: decoratedSymbol, symbolColor: default, character: i}
usePrePhraseSnapshot: true
initialState:
documentContents: |
Welcome Cursorless!
Notice the hats above each word in this sentence.
selections:
- anchor: {line: 2, character: 15}
active: {line: 2, character: 15}
marks:
default.i:
start: {line: 2, character: 32}
end: {line: 2, character: 34}
finalState:
documentContents: |
Welcome Cursorless!
Notice the hats above each word this sentence.
selections:
- anchor: {line: 2, character: 32}
active: {line: 2, character: 32}
39 changes: 39 additions & 0 deletions data/fixtures/recorded/tutorial/unit-1-basics/chuckLineOdd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
languageId: plaintext
command:
version: 7
spokenForm: chuck line odd
action:
name: remove
target:
type: primitive
mark: {type: decoratedSymbol, symbolColor: default, character: o}
modifiers:
- type: containingScope
scopeType: {type: line}
usePrePhraseSnapshot: true
initialState:
documentContents: |-
Welcome Cursorless!
Notice the hats above each word in this sentence.
Now, see the sidebar.
selections:
- anchor: {line: 2, character: 0}
active: {line: 2, character: 6}
- anchor: {line: 2, character: 35}
active: {line: 2, character: 39}
marks:
default.o:
start: {line: 4, character: 0}
end: {line: 4, character: 3}
finalState:
documentContents: |
Welcome Cursorless!
Notice the hats above each word in this sentence.
selections:
- anchor: {line: 2, character: 0}
active: {line: 2, character: 6}
- anchor: {line: 2, character: 35}
active: {line: 2, character: 39}
38 changes: 38 additions & 0 deletions data/fixtures/recorded/tutorial/unit-1-basics/chuckTrap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
languageId: plaintext
command:
version: 7
spokenForm: chuck trap
action:
name: remove
target:
type: primitive
mark: {type: decoratedSymbol, symbolColor: default, character: t}
usePrePhraseSnapshot: true
initialState:
documentContents: |-
Welcome to Cursorless!
Notice the hats above each word in this sentence.
Now, see the sidebar.
selections:
- anchor: {line: 2, character: 0}
active: {line: 2, character: 6}
- anchor: {line: 2, character: 35}
active: {line: 2, character: 39}
marks:
default.t:
start: {line: 0, character: 8}
end: {line: 0, character: 10}
finalState:
documentContents: |-
Welcome Cursorless!
Notice the hats above each word in this sentence.
Now, see the sidebar.
selections:
- anchor: {line: 2, character: 0}
active: {line: 2, character: 6}
- anchor: {line: 2, character: 35}
active: {line: 2, character: 39}
30 changes: 30 additions & 0 deletions data/fixtures/recorded/tutorial/unit-1-basics/postAir.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
languageId: plaintext
command:
version: 7
spokenForm: post air
action:
name: setSelectionAfter
target:
type: primitive
mark: {type: decoratedSymbol, symbolColor: default, character: a}
usePrePhraseSnapshot: true
initialState:
documentContents: |
Welcome Cursorless!
Notice the hats above each word in this sentence.
selections:
- anchor: {line: 0, character: 8}
active: {line: 0, character: 8}
marks:
default.a:
start: {line: 2, character: 11}
end: {line: 2, character: 15}
finalState:
documentContents: |
Welcome Cursorless!
Notice the hats above each word in this sentence.
selections:
- anchor: {line: 2, character: 15}
active: {line: 2, character: 15}
30 changes: 30 additions & 0 deletions data/fixtures/recorded/tutorial/unit-1-basics/preUrge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
languageId: plaintext
command:
version: 7
spokenForm: pre urge
action:
name: setSelectionBefore
target:
type: primitive
mark: {type: decoratedSymbol, symbolColor: default, character: u}
usePrePhraseSnapshot: true
initialState:
documentContents: |
Welcome Cursorless!
Notice the hats above each word in this sentence.
selections:
- anchor: {line: 2, character: 0}
active: {line: 2, character: 49}
marks:
default.u:
start: {line: 0, character: 8}
end: {line: 0, character: 18}
finalState:
documentContents: |
Welcome Cursorless!
Notice the hats above each word in this sentence.
selections:
- anchor: {line: 0, character: 8}
active: {line: 0, character: 8}
17 changes: 17 additions & 0 deletions data/fixtures/recorded/tutorial/unit-1-basics/script.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"title": "Introduction",
"version": 0,
"steps": [
"Say {step:takeCap.yml}",
"Well done! 🙌 You just used the code word for 'c', {grapheme:c}, to refer to the word with a gray hat over the 'c'.\nWhen a hat is not gray, we say its color: say {step:takeBlueSun.yml}",
"Selecting a single token is great, but oftentimes we need something bigger.\nSay {step:takeHarpPastDrum.yml} to select a range.",
"Despite its name, one of the most powerful aspects of cursorless is the ability to use more than one cursor.\nLet's try that: {step:takeNearAndSun.yml}",
"But let's show that cursorless can live up to its name: we can say {step:chuckTrap.yml} to delete a word without ever moving our cursor.",
"Tokens are great, but they're just one way to think of a document.\nLet's try working with lines: {step:chuckLineOdd.yml}",
"We can also use {scopeType:line} to refer to the line containing our cursor: {step:takeLine.yml}",
"You now know how to select and delete; let's give you a couple more actions to play with: say {action:pre} to place the cursor before a target, as in {step:preUrge.yml}",
"Say {action:post} to place the cursor after a target: {step:postAir.yml}",
"Say {action:change} to delete a word and move your cursor to where it used to be: {step:changeSit.yml}",
"And that wraps up unit 1 of the cursorless tutorial! Next time, we'll write some code 🙌.\nFeel free to keep playing with this document, then say {special:next} to continue."
]
}
34 changes: 34 additions & 0 deletions data/fixtures/recorded/tutorial/unit-1-basics/takeBlueSun.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
languageId: plaintext
command:
version: 7
spokenForm: take blue sun
action:
name: setSelection
target:
type: primitive
mark: {type: decoratedSymbol, symbolColor: blue, character: s}
usePrePhraseSnapshot: true
initialState:
documentContents: |-
Welcome to Cursorless!
Notice the hats above each word in this sentence.
Now, see the sidebar.
selections:
- anchor: {line: 2, character: 22}
active: {line: 2, character: 26}
marks:
blue.s:
start: {line: 4, character: 5}
end: {line: 4, character: 8}
finalState:
documentContents: |-
Welcome to Cursorless!
Notice the hats above each word in this sentence.
Now, see the sidebar.
selections:
- anchor: {line: 4, character: 5}
active: {line: 4, character: 8}
Loading

0 comments on commit 57ed77b

Please sign in to comment.