Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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 ))

(in-package :lem-tutor)

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: functional_style_rule

Contract: contract

AI check failed: "functional_style_rule"

Reason:
A dynamic variable is introduced and then used by helper functions instead of passing the source directory explicitly as an argument.


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

(defun tutorial-text ()
(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))))
Comment thread
Catsquotl marked this conversation as resolved.
(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