Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions extensions/lem-tutor/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.fasl
*.fas
*.lib
*.o
lem-tutor-saves/
3 changes: 3 additions & 0 deletions extensions/lem-tutor/lem-tutor.asd
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(defsystem "lem-tutor"
:depends-on ("lem/core")
:components ((:file "lem-tutor")))
75 changes: 75 additions & 0 deletions extensions/lem-tutor/lem-tutor.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
(defpackage :lem-tutor
(:use :cl :lem)
(:export #:tutorial :tutorial-rescan))

(in-package :lem-tutor)

(defun tutorial-text ()
"Set correct paths to core and save files"
(merge-pathnames "tutorial-basics.txt" (asdf:system-source-directory :lem-tutor)))

(defun tutorial-save-file ()
(merge-pathnames "lem-tutor-saves/lem-tutor-save.txt" (lem-home)))

(defun tutorial-progress ()
(merge-pathnames "lem-tutor-saves/lem-tutor-progress.lisp" (lem-home)))

(define-command tutorial () ()
"Learn Lem interactively with guided exercises and progress tracking."
(tutorial-mode t))

(defun tutorial-save-progress (buffer)
"Create or update a save file with the cursor position, for easy continuation of the tutorial"
(let* ((point (buffer-point buffer))
(line (line-number-at-point point))
(column (point-column point)))
(with-open-file (stream (tutorial-progress)
:direction :output
:if-exists :supersede
:if-does-not-exist :create)
(format stream "(:line ~D :column ~D)" line column))))

(defun tutorial-load-progress ()
"Load cursor position from progress file and restore cursor position."
(handler-case
(when (probe-file (tutorial-progress))
(with-open-file (stream (tutorial-progress)
:direction :input)
(let* ((plist (read stream))
(line (getf plist :line))
(column (getf plist :column))
(point (buffer-point (find-file-buffer (tutorial-save-file)))))
(move-to-line point line)
(move-to-column point column))))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Contractor: error_handling_rule

Contract: contract

AI check failed: "error_handling_rule"

Reason:
User-facing failure handling reports a message directly instead of using editor-error as required for messages shown to users.


💬 Reply /dismiss <reason> to dismiss this violation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll see to those soon.

(error (e)
(declare (ignore e))
(editor-error "Could not restore latest savepoint. Starting at the top, previously made edits are preserved"))))

(defun tutorial-enable ()
"Enable tutorial mode: ensure save directory exists, initialize working copy if needed,
open the save file, store the buffer and hook into after-save for progress tracking."
(ensure-directories-exist (tutorial-save-file))
(unless (probe-file (tutorial-save-file))
(uiop:copy-file (tutorial-text) (tutorial-save-file)))
(let ((buffer (find-file-buffer (tutorial-save-file))))
(switch-to-buffer buffer)
(tutorial-load-progress)
(add-hook (variable-value 'after-save-hook :buffer buffer)
#'tutorial-save-progress)))

(defun tutorial-disable ()
"Save progress when tutorial mode is disabled."
(tutorial-save-progress (find-file-buffer (tutorial-save-file))))

(define-command tutorial-rescan () ()
"Force a syntax rescan of the tutorial buffer"
(let ((buffer (find-file-buffer (tutorial-save-file))))
(lem-tutor/syntax-parser:scan-region
(buffer-start-point buffer)
(buffer-end-point buffer))))

(define-minor-mode tutorial-mode
(:name "Lem-tutor"
:description "A tutorial for the lem editor."
:enable-hook #'tutorial-enable
:disable-hook #'tutorial-disable))
Loading
Loading