github.com/xyproto/orbiton/v2@v2.65.12-0.20240516144430-e10a419274ec/tutorial.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/xyproto/vt100" 8 ) 9 10 // TutorialStep represents a step in the tutorial wizard 11 type TutorialStep struct { 12 title string 13 description string 14 expectKeys []string 15 } 16 17 // Tutorial is a collection of steps 18 type Tutorial []TutorialStep 19 20 var tutorialSteps = Tutorial{ 21 TutorialStep{ 22 title: "Start of text", 23 description: "Press ctrl-a to go to the start of the text on the current line.", 24 expectKeys: []string{"c:1"}, // ctrl-a 25 }, 26 TutorialStep{ 27 title: "Start of line", 28 description: "Press ctrl-a twice to go to the start of the line.", 29 expectKeys: []string{"c:1", "c:1"}, // ctrl-a 30 }, 31 TutorialStep{ 32 title: "End of the line above", 33 description: "Press ctrl-a three times to go to the end of the line above.", 34 expectKeys: []string{"c:1", "c:1", "c:1"}, // ctrl-a 35 }, 36 TutorialStep{ 37 title: "Create a bookmark", 38 description: "Press ctrl-b to bookmark the current line.", 39 expectKeys: []string{"c:2"}, // ctrl-b 40 }, 41 TutorialStep{ 42 title: "Jump to a bookmark", 43 description: "Press ctrl-b jump to the bookmark. It must be on a different line than the current line.", 44 expectKeys: []string{"c:2"}, // ctrl-b 45 }, 46 TutorialStep{ 47 title: "Remove a bookmark", 48 description: "Press ctrl-b to clear a bookmark. The bookmark must be set and the current line must be the bookmarked line.", 49 expectKeys: []string{"c:2"}, // ctrl-b 50 }, 51 TutorialStep{ 52 title: "Copy line", 53 description: "Press ctrl-c to copy the current line to the clipboard. If no clipboard is available, an internal buffer is used.", 54 expectKeys: []string{"c:3"}, // ctrl-c 55 }, 56 TutorialStep{ 57 title: "Copy block of text", 58 description: "Press ctrl-c twice to copy a block of text (until the next blank line) to the clipboard. If no clipboard is available, an internal buffer is used. For some terminal emulators, this must not be pressed too fast.", 59 expectKeys: []string{"c:3", "c:3"}, // ctrl-c 60 }, 61 TutorialStep{ 62 title: "Delete the current letter", 63 description: "Press ctrl-d to delete the current letter.", 64 expectKeys: []string{"c:8"}, // ctrl-d 65 }, 66 TutorialStep{ 67 title: "End of the line", 68 description: "Press ctrl-e to go to the end of the line.", 69 expectKeys: []string{"c:5"}, // ctrl-e 70 }, 71 TutorialStep{ 72 title: "Start of the next line", 73 description: "Press ctrl-e twice to go to the start of the next line.", 74 expectKeys: []string{"c:5"}, // ctrl-e 75 }, 76 TutorialStep{ 77 title: "Search", 78 description: "Press ctrl-f and type in the text to search for.", 79 expectKeys: []string{"c:6"}, // ctrl-f 80 }, 81 TutorialStep{ 82 title: "Search and replace", 83 description: "Press ctrl-f, type in text to search for, press Tab, type in text that all instances should be replaced with and then press return.", 84 expectKeys: []string{"c:6"}, // ctrl-f 85 }, 86 TutorialStep{ 87 title: "Go to definition", 88 description: "For some programming languages, ctrl-g can be pressed to jump to a definition, and ctrl-b can be used to jump back.", 89 expectKeys: []string{"c:7"}, // ctrl-g 90 }, 91 TutorialStep{ 92 title: "Toggle word count and cursor position status", 93 description: "ctrl-g will toggle a status bar at the bottom, containing the current line, total number of lines, the current rune, word count, file mode and either \"tabs\" or \"spaces\", unless the cursor is over a definition that can be jumped to.", 94 expectKeys: []string{"c:7"}, // ctrl-g 95 }, 96 TutorialStep{ 97 title: "Delete to letter to the left", 98 description: "Press ctrl-h or backspace to delete the letter to the left.", 99 expectKeys: []string{"c:8"}, // ctrl-h or backspace 100 }, 101 TutorialStep{ 102 title: "Indentation", 103 description: "Press ctrl-i or tab to indent a line.", 104 expectKeys: []string{"c:9"}, // ctrl-i or tab 105 }, 106 TutorialStep{ 107 title: "Join", 108 description: "Press ctrl-j to join this line with the next. The next line is placed after the current one.", 109 expectKeys: []string{"c:10"}, // ctrl-j 110 }, 111 TutorialStep{ 112 title: "Remove the rest of the line", 113 description: "Press ctrl-k to remove the rest of the current line.", 114 expectKeys: []string{"c:11"}, // ctrl-k 115 }, 116 TutorialStep{ 117 title: "Jump to a location", 118 description: "Press ctrl-l and then press one of the highlighted letters to jump there.", 119 expectKeys: []string{"c:12"}, // ctrl-l 120 }, 121 TutorialStep{ 122 title: "Jump to the top", 123 description: "Unless the cursor is already at the top, press ctrl-l and then return.", 124 expectKeys: []string{"c:12"}, // ctrl-l 125 }, 126 TutorialStep{ 127 title: "Jump to the top (method 2)", 128 description: "Press ctrl-l and then t to jump to the top of the file.", 129 expectKeys: []string{"c:12"}, // ctrl-l 130 }, 131 TutorialStep{ 132 title: "Jump to the top (method 3)", 133 description: "Press ctrl-l, type in 0 and press return.", 134 expectKeys: []string{"c:12"}, // ctrl-l 135 }, 136 TutorialStep{ 137 title: "Jump to the bottom", 138 description: "Press ctrl-l and then b to jump to the bottom of the file.", 139 expectKeys: []string{"c:12"}, // ctrl-l 140 }, 141 TutorialStep{ 142 title: "Jump to the bottom (method 2)", 143 description: "Press ctrl-l and return to jump to the top, then ctrl-l and return to jump to the bottom.", 144 expectKeys: []string{"c:12"}, // ctrl-l 145 }, 146 TutorialStep{ 147 title: "Jump to the bottom (method 3)", 148 description: "Press ctrl-l, type in 100% and press return.", 149 expectKeys: []string{"c:12"}, // ctrl-l 150 }, 151 TutorialStep{ 152 title: "Jump to the bottom (method 4)", 153 description: "Press ctrl-l, type in 1. and press return.", 154 expectKeys: []string{"c:12"}, // ctrl-l 155 }, 156 TutorialStep{ 157 title: "Jump to the center of the file", 158 description: "Press ctrl-l and then c to jump to the center of the file.", 159 expectKeys: []string{"c:12"}, // ctrl-l 160 }, 161 TutorialStep{ 162 title: "Jump to the center of the file (method 2)", 163 description: "Press ctrl-l, type in 50% and press return.", 164 expectKeys: []string{"c:12"}, // ctrl-l 165 }, 166 TutorialStep{ 167 title: "Jump to the center of the file (method 3)", 168 description: "Press ctrl-l, type in .5 and press return.", 169 expectKeys: []string{"c:12"}, // ctrl-l 170 }, 171 TutorialStep{ 172 title: "Move a line down or start a new line", 173 description: "Press ctrl-m or press return.", 174 expectKeys: []string{"c:13"}, // ctrl-m 175 }, 176 TutorialStep{ 177 title: "Move down 10 lines", 178 description: "Press ctrl-n to move and scroll down 10 lines.", 179 expectKeys: []string{"c:14"}, // ctrl-n 180 }, 181 TutorialStep{ 182 title: "Go to the next instance", 183 description: "When searching, press ctrl-n to go to the next instance.", 184 expectKeys: []string{"c:14"}, // ctrl-n 185 }, 186 TutorialStep{ 187 title: "Go to the next instruction", 188 description: "When debugging, press ctrl-n to go to the next instruction.", 189 expectKeys: []string{"c:14"}, // ctrl-n 190 }, 191 TutorialStep{ 192 title: "Main menu", 193 description: "Press ctrl-o to open the main menu.", 194 expectKeys: []string{"c:15"}, // ctrl-o 195 }, 196 TutorialStep{ 197 title: "Move up 10 lines", 198 description: "Press ctrl-p to move and scroll up 10 lines.", 199 expectKeys: []string{"c:16"}, // ctrl-p 200 }, 201 TutorialStep{ 202 title: "Go to the previous instance", 203 description: "When searching, press ctrl-p to go to the previous instance.", 204 expectKeys: []string{"c:16"}, // ctrl-p 205 }, 206 TutorialStep{ 207 title: "Cycle register pane layout", 208 description: "When debugging, press ctrl-p to cycle the size of the register pane from small, to large to hidden.", 209 expectKeys: []string{"c:16"}, // ctrl-p 210 }, 211 TutorialStep{ 212 title: "Quit", 213 description: "Press ctrl-q to quit, no questions asked.", 214 expectKeys: []string{"c:17"}, // ctrl-q 215 }, 216 TutorialStep{ 217 title: "Open a portal", 218 description: "Press ctrl-r to open a portal that can be used to paste lines into another file with ctrl-v.", 219 expectKeys: []string{"c:18"}, // ctrl-r 220 }, 221 TutorialStep{ 222 title: "Close a portal", 223 description: "If a portal is open, it will time out after 20 minutes, or it can be closed with ctrl-r.", 224 expectKeys: []string{"c:18"}, // ctrl-r 225 }, 226 TutorialStep{ 227 title: "Save", 228 description: "Press ctrl-s to save the current file.", 229 expectKeys: []string{"c:19"}, // ctrl-s 230 }, 231 TutorialStep{ 232 title: "Save without using the pinky finger", 233 description: "In rapid succession, press arrow right, arrow down and arrow left. When \"o:\" appears at the bottom, press arrow down to save.", 234 expectKeys: []string{}, // tbd 235 }, 236 TutorialStep{ 237 title: "Save and quit without using the pinky finger", 238 description: "In rapid succession, press arrow right, arrow down and arrow left. When \"o:\" appears at the bottom, press arrow up to save and quit.", 239 expectKeys: []string{}, // tbd 240 }, 241 TutorialStep{ 242 title: "Record macro", 243 description: "Press ctrl-t to record keypresses. Press ctrl-t again to stop recording.", 244 expectKeys: []string{"c:20"}, // ctrl-t 245 }, 246 TutorialStep{ 247 title: "Play back macro", 248 description: "Press ctrl-t to play back the current macro.", 249 expectKeys: []string{"c:20"}, // ctrl-t 250 }, 251 TutorialStep{ 252 title: "Clear macro", 253 description: "Press Esc to clear the current macro.", 254 expectKeys: []string{"c:27"}, // esc 255 }, 256 TutorialStep{ 257 title: "Toggle checkbox", 258 description: "When editing Markdown, move the cursor to a line with a checkbox (\"- [ ] TODO\") and press ctrl-t or ctrl-space to toggle it.", 259 expectKeys: []string{"c:20"}, // ctrl-t 260 }, 261 TutorialStep{ 262 title: "Edit table", 263 description: "When editing Markdown, move the cursor to a line with a table and press ctrl-t to enter the table editor. This feature currently only supports small tables.", 264 expectKeys: []string{"c:20"}, // ctrl-t 265 }, 266 TutorialStep{ 267 title: "Format table", 268 description: "When editing Markdown, move the cursor to a line with a table and press ctrl-w to format it.", 269 expectKeys: []string{"c:23"}, // ctrl-w 270 }, 271 TutorialStep{ 272 title: "Undo", 273 description: "Press ctrl-u to undo the last operation. There is no redo, yet.", 274 expectKeys: []string{"c:21"}, // ctrl-u 275 }, 276 TutorialStep{ 277 title: "Paste", 278 description: "Press ctrl-v to paste the first line from the clipboard. The string will be trimmed.", 279 expectKeys: []string{"c:22"}, // ctrl-v 280 }, 281 TutorialStep{ 282 title: "Paste", 283 description: "Press ctrl-v twice to paste the contents of the clipbard.", 284 expectKeys: []string{"c:22", "c:22"}, // ctrl-v 285 }, 286 TutorialStep{ 287 title: "Generate template", 288 description: "Open an empty source code file and press ctrl-w to generate a \"hello world\" program. This applies to several programming languages.", 289 expectKeys: []string{"c:23"}, // ctrl-w 290 }, 291 TutorialStep{ 292 title: "Format source code", 293 description: "Open a source code file and press ctrl-w to format it. This applies to several programming languages.", 294 expectKeys: []string{"c:23"}, // ctrl-w 295 }, 296 TutorialStep{ 297 title: "Cut", 298 description: "Press ctrl-x to cut the current line and place it in the clipboard.", 299 expectKeys: []string{"c:24"}, // ctrl-x 300 }, 301 TutorialStep{ 302 title: "Paste", 303 description: "Press ctrl-x twice to cut the current block of text (to a blank line) and place it in the clipboard.", 304 expectKeys: []string{"c:24", "c:24"}, // ctrl-x 305 }, 306 TutorialStep{ 307 title: "Go to start of line (method 2)", 308 description: "Press ctrl-y to go to the start of the text, then line, then the end of the line above. Same as ctrl-a.", 309 expectKeys: []string{"c:25"}, // ctrl-y 310 }, 311 TutorialStep{ 312 title: "Undo (method 2)", 313 description: "Press ctrl-z to undo the last operation. If ctrl-z backgrounds the application, run \"fg\" to bring it back.", 314 expectKeys: []string{"c:26"}, // ctrl-z 315 }, 316 TutorialStep{ 317 title: "Build source code", 318 description: "Open a source code file and press ctrl-space to build it. This works for some projects and programming languages.", 319 expectKeys: []string{"c:0"}, // ctrl-space 320 }, 321 TutorialStep{ 322 title: "Build and run", 323 description: "Open a source code file and press ctrl-space twice to build it, run it and also display stdout + stderr.", 324 expectKeys: []string{"c:0", "c:0"}, // ctrl-space 325 }, 326 TutorialStep{ 327 title: "Insert a file", 328 description: "Let the file be named include.txt, then select the 'Insert \"include.txt\" at the current line' option in the ctrl-o menu.", 329 expectKeys: []string{}, // tbd 330 }, 331 TutorialStep{ 332 title: "Insert a file (method 2)", 333 description: "In rapid succession, press arrow right, arrow down and arrow left. Then type \"insertfile somefile.txt\" to insert somefile.txt into the current file.", 334 expectKeys: []string{}, // tbd 335 }, 336 TutorialStep{ 337 title: "English spell check (experimental feature)", 338 description: "Press ctrl-f, type t and press return. Then press ctrl-n for next instance, ctrl-a to add the word temporarily or ctrl-i to ignore the word temporarily.", 339 expectKeys: []string{}, // tbd 340 }, 341 TutorialStep{ 342 title: "Jump to matching parenthesis", 343 description: "Be on a (, [, {, }, ] or ) character. Press ctrl-_ to jump to the matching one, for instance the next \")\" if the cursor is on \"(\".", 344 expectKeys: []string{"c:31"}, // ctrl-_ 345 }, 346 TutorialStep{ 347 title: "Insert digraph", 348 description: "Press ctrl-_ to insert a digraph. For instance \"ae\" to insert \"æ\". These are the same as for ViM or NeoViM. Do not be on a (, [, {, }, ] or ) character.", 349 expectKeys: []string{"c:31"}, // ctrl-_ 350 }, 351 TutorialStep{ 352 title: "Tutorial complete", 353 description: "Press q, esc or ctrl-q to end this tutorial.", 354 expectKeys: []string{"c:32"}, // space 355 }, 356 } 357 358 // LaunchTutorial launches a short and sweet tutorial that covers at least portals and cut/paste 359 func LaunchTutorial(tty *vt100.TTY, c *vt100.Canvas, e *Editor, status *StatusBar) { 360 const repositionCursorAfterDrawing = false 361 const marginX = 4 362 363 minWidth := 32 364 for _, step := range tutorialSteps { 365 for _, line := range strings.Split(step.description, "\n") { 366 if len(line) > minWidth { 367 minWidth = len(line) + marginX 368 } 369 } 370 } 371 372 displayedStatusOnce := false 373 374 i := 0 375 for { 376 if i == 0 && !displayedStatusOnce { 377 status.SetMessage("q to end") 378 status.Show(c, e) 379 displayedStatusOnce = true 380 } else { 381 status.Clear(c) 382 } 383 384 step := tutorialSteps[i] 385 progress := fmt.Sprintf("%d / %d", i+1, len(tutorialSteps)) 386 step.Draw(c, e, progress, minWidth, repositionCursorAfterDrawing) 387 388 // Wait for a keypress 389 key := tty.String() 390 switch key { 391 case " ", "c:13", "↓", "→", "j", "c:14", "n": // space, return, down, right, j, ctrl-n or n to go to the next step 392 if i < (len(tutorialSteps) - 1) { 393 i++ 394 } 395 continue 396 case "↑", "←", "k", "c:16", "p": // up, left, k, ctrl-p or p to go to the previous step 397 if i > 0 { 398 i-- 399 } 400 continue 401 case "c:17", "c:27", "q", "x": // ctrl-q, esc, q or x to exit 402 return 403 } 404 // Other keypress, do nothing 405 } 406 } 407 408 // Draw draws a step of the tutorial 409 func (step TutorialStep) Draw(c *vt100.Canvas, e *Editor, progress string, minWidth int, repositionCursorAfterDrawing bool) { 410 canvasBox := NewCanvasBox(c) 411 412 // Window is the background box that will be drawn in the upper right 413 centerBox := NewBox() 414 415 centerBox.EvenLowerRightPlacement(canvasBox, minWidth) 416 e.redraw = true 417 418 // Then create a list box 419 listBox := NewBox() 420 listBox.FillWithMargins(centerBox, 2, 2) 421 422 // Get the current theme for the register box 423 bt := e.NewBoxTheme() 424 bt.Foreground = &e.BoxTextColor 425 bt.Background = &e.DebugInstructionsBackground 426 427 // First figure out how many lines of text this will be after word wrap 428 const dryRun = true 429 addedLines := e.DrawText(bt, c, listBox, step.description, dryRun) 430 431 if addedLines > listBox.H { 432 // Then adjust the box height and text position (addedLines could very well be 0) 433 centerBox.Y -= addedLines 434 centerBox.H += addedLines 435 listBox.Y -= addedLines 436 } 437 438 // Then draw the box with the text 439 e.DrawBox(bt, c, centerBox) 440 e.DrawTitle(bt, c, centerBox, step.title, true) 441 e.DrawFooter(bt, c, centerBox, "("+progress+")") 442 e.DrawText(bt, c, listBox, step.description, false) 443 444 // Blit 445 c.Draw() 446 447 // Reposition the cursor, if needed 448 if repositionCursorAfterDrawing { 449 x := e.pos.ScreenX() 450 y := e.pos.ScreenY() 451 vt100.SetXY(uint(x), uint(y)) 452 } 453 }