1 ;;; tutorial.el --- tutorial for Emacs
3 ;; Copyright (C) 2006 Free Software Foundation, Inc.
6 ;; Keywords: help, internal
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 ;; Boston, MA 02110-1301, USA.
27 ;; Code for running the Emacs tutorial.
31 ;; File was created 2006-09.
35 (require 'help-mode) ;; for function help-buffer
36 (eval-when-compile (require 'cl))
38 (defface tutorial-warning-face
39 '((((class color) (min-colors 88) (background light))
40 (:foreground "Red1" :weight bold))
41 (((class color) (min-colors 88) (background dark))
42 (:foreground "Pink" :weight bold))
43 (((class color) (min-colors 16) (background light))
44 (:foreground "Red1" :weight bold))
45 (((class color) (min-colors 16) (background dark))
46 (:foreground "Pink" :weight bold))
47 (((class color) (min-colors 8)) (:foreground "red"))
48 (t (:inverse-video t :weight bold)))
49 "Face used to highlight warnings in the tutorial."
50 :group 'font-lock-faces)
52 (defvar tutorial--point-before-chkeys 0
53 "Point before display of key changes.")
54 (make-variable-buffer-local 'tutorial--point-before-chkeys)
56 (defvar tutorial--point-after-chkeys 0
57 "Point after display of key changes.")
58 (make-variable-buffer-local 'tutorial--point-after-chkeys)
60 (defvar tutorial--lang nil
62 (make-variable-buffer-local 'tutorial--lang)
64 (defun tutorial--describe-nonstandard-key (value)
65 "Give more information about a changed key binding.
66 This is used in `help-with-tutorial'. The information includes
67 the key sequence that no longer has a default binding, the
68 default binding and the current binding. It also tells in what
69 keymap the new binding has been done and how to access the
70 function in the default binding from the keyboard.
72 For `cua-mode' key bindings that try to combine CUA key bindings
73 with default Emacs bindings information about this is shown.
75 VALUE should have either of these formats:
78 \(current-binding KEY-FUN DEF-FUN KEY WHERE)
81 KEY is a key sequence whose standard binding has been changed
82 KEY-FUN is the actual binding for KEY
83 DEF-FUN is the standard binding of KEY
84 WHERE is a text describing the key sequences to which DEF-FUN is
85 bound now (or, if it is remapped, a key sequence
86 for the function it is remapped to)"
87 (with-output-to-temp-buffer (help-buffer)
88 (help-setup-xref (list #'tutorial--describe-nonstandard-key value)
90 (with-current-buffer (help-buffer)
92 "Your Emacs customizations override the default binding for this key:"
94 (let ((inhibit-read-only t))
96 ((eq (car value) 'cua-mode)
100 When CUA mode is enabled, you can use C-z, C-x, C-c, and C-v to
101 undo, cut, copy, and paste in addition to the normal Emacs
102 bindings. The C-x and C-c keys only do cut and copy when the
103 region is active, so in most cases, they do not conflict with the
104 normal function of these prefix keys.
106 If you really need to perform a command which starts with one of
107 the prefix keys even when the region is active, you have three
109 - press the prefix key twice very quickly (within 0.2 seconds),
110 - press the prefix key and the following key within 0.2 seconds, or
111 - use the SHIFT key with the prefix key, i.e. C-S-x or C-S-c."))
112 ((eq (car value) 'current-binding)
113 (let ((cb (nth 1 value))
116 (where (nth 4 value))
118 (maps (current-active-maps))
120 ;; Look at the currently active keymaps and try to find
121 ;; first the keymap where the current binding occurs:
123 (let* ((m (car maps))
124 (mb (lookup-key m key t)))
125 (setq maps (cdr maps))
129 ;; Now, if a keymap was found we must found the symbol
130 ;; name for it to display to the user. This can not
131 ;; always be found since all keymaps does not have a
132 ;; symbol pointing to them, but here they should have
135 (mapatoms (lambda (s)
137 ;; If not already found
139 ;; and if s is a keymap
141 (keymapp (symbol-value s)))
142 ;; and not the local symbol map
144 ;; and the value of s is map
145 (eq map (symbol-value s))
146 ;; then save this value in mapsym
148 (insert "The default Emacs binding for the key "
149 (key-description key)
151 (insert (format "%s" db))
153 "However, your customizations have rebound it to the command `")
154 (insert (format "%s" cb))
157 (insert " (For the more advanced user:"
158 " This binding is in the keymap `"
161 (if (string= where "")
163 (insert "\n\nYou can use M-x "
166 (insert "\n\nWith you current key bindings"
167 " you can use the key "
169 " to get the function `"
173 (fill-region (point-min) (point)))))
174 (print-help-return-message))))
176 (defun tutorial--sort-keys (left right)
177 "Sort predicate for use with `tutorial--default-keys'.
178 This is a predicate function to `sort'.
180 The sorting is for presentation purpose only and is done on the
183 LEFT and RIGHT are the elements to compare."
184 (let ((x (append (cadr left) nil))
185 (y (append (cadr right) nil)))
186 ;; Skip the front part of the key sequences if they are equal:
189 (equal (car x) (car y)))
192 ;; Try to make a comparision that is useful for presentation (this
193 ;; could be made nicer perhaps):
196 ;;(message "x=%s, y=%s;;;; cx=%s, cy=%s" x y cx cy)
198 ;; Lists? Then call this again
202 (tutorial--sort-keys cx cy))
203 ;; Are both numbers? Then just compare them
207 ;; Is one of them a number? Let that be bigger then.
212 ;; Are both symbols? Compare the names then.
215 (string< (symbol-name cy)
219 (defconst tutorial--default-keys
221 ;; On window system suspend Emacs is replaced in the
222 ;; default keymap so honor this here.
223 (suspend-emacs (if window-system
224 'iconify-or-deiconify-frame
228 ;; These are not mentioned but are basic:
230 (Control-X-prefix [?\C-x])
231 (mode-specific-command-prefix [?\C-c])
233 (save-buffers-kill-emacs [?\C-x ?\C-c])
238 (scroll-down [?\M-v])
242 ;; * BASIC CURSOR CONTROL
243 (forward-char [?\C-f])
244 (backward-char [?\C-b])
246 (forward-word [?\M-f])
247 (backward-word [?\M-b])
250 (previous-line [?\C-p])
252 (move-beginning-of-line [?\C-a])
253 (move-end-of-line [?\C-e])
255 (backward-sentence [?\M-a])
256 (forward-sentence [?\M-e])
260 (beginning-of-buffer [?\M-<])
261 (end-of-buffer [?\M->])
263 (universal-argument [?\C-u])
266 ;; * WHEN EMACS IS HUNG
267 (keyboard-quit [?\C-g])
270 ;; * DISABLED COMMANDS
271 (downcase-region [?\C-x ?\C-l])
275 (delete-other-windows [?\C-x ?1])
277 ;; Type CONTROL-h k CONTROL-f.
280 ;; * INSERTING AND DELETING
281 ;; C-u 8 * to insert ********.
283 (delete-backward-char [backspace])
284 (delete-backward-char "\d")
285 (delete-char [?\C-d])
287 (backward-kill-word [(meta backspace)])
291 (kill-sentence [?\M-k])
293 (set-mark-command [?\C-@])
294 (set-mark-command [?\C- ])
295 (kill-region [?\C-w])
301 (advertised-undo [?\C-x ?u])
302 (advertised-undo [?\C-x ?u])
306 (find-file [?\C-x ?\C-f])
307 (save-buffer [?\C-x ?\C-s])
311 (list-buffers [?\C-x ?\C-b])
312 (switch-to-buffer [?\C-x ?b])
313 (save-some-buffers [?\C-x ?s])
316 ;; * EXTENDING THE COMMAND SET
317 ;; C-x Character eXtend. Followed by one character.
318 (execute-extended-command [?\M-x])
322 ;; C-x s Save some buffers
323 ;; C-x C-b List buffers
324 ;; C-x b Switch buffer
325 ;; C-x C-c Quit Emacs
326 ;; C-x 1 Delete all but one window
331 (describe-mode [?\C-h ?m])
333 (set-fill-column [?\C-x ?f])
334 (fill-paragraph [?\M-q])
338 (isearch-forward [?\C-s])
339 (isearch-backward [?\C-r])
342 ;; * MULTIPLE WINDOWS
343 (split-window-vertically [?\C-x ?2])
344 (scroll-other-window [?\C-\M-v])
345 (other-window [?\C-x ?o])
346 (find-file-other-window [?\C-x ?4 ?\C-f])
349 ;; * RECURSIVE EDITING LEVELS
350 (keyboard-escape-quit [27 27 27])
353 ;; * GETTING MORE HELP
354 ;; The most basic HELP feature is C-h c
355 (describe-key-briefly [?\C-h ?c])
356 (describe-key [?\C-h ?k])
364 ;;(iconify-or-deiconify-frame [?\C-z])
365 (,suspend-emacs [?\C-z])
367 (sort default-keys 'tutorial--sort-keys))
368 "Default Emacs key bindings that the tutorial depends on.")
370 (defun tutorial--detailed-help (button)
371 "Give detailed help about changed keys."
372 (with-output-to-temp-buffer (help-buffer)
373 (help-setup-xref (list #'tutorial--detailed-help button)
375 (with-current-buffer (help-buffer)
376 (let* ((tutorial-buffer (button-get button 'tutorial-buffer))
377 ;;(tutorial-arg (button-get button 'tutorial-arg))
378 (explain-key-desc (button-get button 'explain-key-desc))
379 (changed-keys (with-current-buffer tutorial-buffer
381 (goto-char (point-min))
382 (tutorial--find-changed-keys
383 tutorial--default-keys)))))
386 "The following key bindings used in the tutorial had been changed
387 from Emacs default in the " (buffer-name tutorial-buffer) " buffer:\n\n" )
388 (let ((frm " %-9s %-27s %-11s %s\n"))
389 (insert (format frm "Key" "Standard Binding" "Is Now On" "Remark")))
390 (dolist (tk changed-keys)
391 (let* ((def-fun (nth 1 tk))
393 (def-fun-txt (nth 2 tk))
396 (rem-fun (command-remapping def-fun))
397 (key-txt (key-description key))
398 (key-fun (with-current-buffer tutorial-buffer (key-binding key)))
400 (unless (eq def-fun key-fun)
401 ;; Insert key binding description:
402 (when (string= key-txt explain-key-desc)
403 (put-text-property 0 (length key-txt)
404 'face 'tutorial-warning-face key-txt))
405 (insert " " key-txt " ")
406 (setq tot-len (length key-txt))
408 (insert (make-string (- 9 tot-len) ? ))
410 ;; Insert a link describing the old binding:
411 (insert-button def-fun-txt
414 (lambda(button) (interactive)
416 (button-get button 'value)))
418 (setq tot-len (+ tot-len (length def-fun-txt)))
420 (insert (make-string (- 36 tot-len) ? )))
423 ;; Tell where the old binding is now:
424 (insert (format " %-11s "
425 (if (string= "" where)
426 (format "M-x %s" def-fun-txt)
428 ;; Insert a link with more information, for example
429 ;; current binding and keymap or information about
430 ;; cua-mode replacements:
431 (insert-button (car remark)
433 (lambda(b) (interactive)
434 (let ((value (button-get b 'value)))
435 (tutorial--describe-nonstandard-key value)))
441 It is legitimate to change key bindings, but changed bindings do not
442 correspond to what the tutorial says. (See also " )
443 (insert-button "Key Binding Conventions"
445 (lambda(button) (interactive)
447 "(elisp) Key Binding Conventions")
448 (message "Type C-x 0 to close the new window"))
451 (print-help-return-message)))))
453 (defun tutorial--find-changed-keys (default-keys)
454 "Find the key bindings that have changed.
455 Check if the default Emacs key bindings that the tutorial depends
456 on have been changed.
458 Return a list with the keys that have been changed. The element
459 of this list have the following format:
461 \(list KEY DEF-FUN DEF-FUN-TXT WHERE REMARK)
464 KEY is a key sequence whose standard binding has been changed
465 DEF-FUN is the standard binding of KEY
466 DEF-FUN-TXT is a short descriptive text for DEF-FUN
467 WHERE is a text describing the key sequences to which DEF-FUN is
468 bound now (or, if it is remapped, a key sequence
469 for the function it is remapped to)
470 REMARK is a list with info about rebinding. It has either of these
474 \(TEXT current-binding KEY-FUN DEF-FUN KEY WHERE)
476 Here TEXT is a link text to show to the user. The
477 rest of the list is used to show information when
478 the user clicks the link.
480 KEY-FUN is the actual binding for KEY."
481 (let (changed-keys remark)
482 ;; (default-keys tutorial--default-keys))
483 (dolist (kdf default-keys)
484 ;; The variables below corresponds to those with the same names
485 ;; described in the doc string.
486 (let* ((key (nth 1 kdf))
487 (def-fun (nth 0 kdf))
488 (def-fun-txt (format "%s" def-fun))
489 (rem-fun (command-remapping def-fun))
490 (key-fun (if (eq def-fun 'ESC-prefix)
491 (lookup-key global-map [27])
493 (where (where-is-internal (if rem-fun rem-fun def-fun))))
496 (setq where (key-description (car where)))
497 (when (and (< 10 (length where))
498 (string= (substring where 0 (length "<menu-bar>"))
500 (setq where "the menus")))
504 (cond ((eq key-fun def-fun)
505 ;; No rebinding, return t
507 ((eq key-fun (command-remapping def-fun))
508 ;; Just a remapping, return t
510 ;; cua-mode specials:
514 (eq key-fun 'cua-paste))
517 (eq key-fun 'undo))))
518 (setq remark (list "cua-mode, more info" 'cua-mode))
522 (and (eq def-fun 'ESC-prefix)
525 (118 . cua-repeat-replace-region))))
526 (and (eq def-fun 'mode-specific-command-prefix)
529 (timeout . copy-region-as-kill))))
530 (and (eq def-fun 'Control-X-prefix)
532 '(keymap (timeout . kill-region))))))
533 (setq remark (list "cua-mode replacement" 'cua-mode))
535 ((eq def-fun 'mode-specific-command-prefix)
536 (setq def-fun-txt "\"C-c prefix\""))
537 ((eq def-fun 'Control-X-prefix)
538 (setq def-fun-txt "\"C-x prefix\""))
539 ((eq def-fun 'ESC-prefix)
540 (setq def-fun-txt "\"ESC prefix\"")))
541 (setq where "Same key")
543 ;; viper-mode specials:
544 ((and (boundp 'viper-mode-string)
545 (boundp 'viper-current-state)
546 (eq viper-current-state 'vi-state)
547 (or (and (eq def-fun 'isearch-forward)
548 (eq key-fun 'viper-isearch-forward))
549 (and (eq def-fun 'isearch-backward)
550 (eq key-fun 'viper-isearch-backward))))
551 ;; These bindings works as the default bindings,
554 ((when normal-erase-is-backspace
555 (or (and (equal key [C-delete])
556 (equal key-fun 'kill-word))
557 (and (equal key [C-backspace])
558 (equal key-fun 'backward-kill-word))))
559 ;; This is the strange handling of C-delete and
560 ;; C-backspace, return t
563 ;; This key has indeed been rebound. Put information
564 ;; in `remark' and return nil
566 (list "more info" 'current-binding
567 key-fun def-fun key where))
569 (add-to-list 'changed-keys
570 (list key def-fun def-fun-txt where remark)))))
573 (defvar tutorial--tab-map
574 (let ((map (make-sparse-keymap)))
575 (define-key map [tab] 'forward-button)
576 (define-key map [(shift tab)] 'backward-button)
577 (define-key map [(meta tab)] 'backward-button)
579 "Keymap that allows tabbing between buttons.")
581 (defun tutorial--display-changes (changed-keys)
582 "Display changes to some default key bindings.
583 If some of the default key bindings that the tutorial depends on
584 have been changed then display the changes in the tutorial buffer
585 with some explanatory links.
587 CHANGED-KEYS should be a list in the format returned by
588 `tutorial--find-changed-keys'."
589 (when (or changed-keys
590 (boundp 'viper-mode-string))
591 ;; Need the custom button face for viper buttons:
592 (when (boundp 'viper-mode-string)
594 (let ((start (point))
596 (head (get-lang-string tutorial--lang 'tut-chgdhead))
597 (head2 (get-lang-string tutorial--lang 'tut-chgdhead2)))
598 (when (and head head2)
599 (goto-char tutorial--point-before-chkeys)
606 'tutorial--detailed-help
611 (dolist (tk changed-keys)
612 (let* ((def-fun (nth 1 tk))
614 (def-fun-txt (nth 2 tk))
617 (rem-fun (command-remapping def-fun))
618 (key-txt (key-description key))
619 (key-fun (key-binding key))
621 (unless (eq def-fun key-fun)
622 ;; Mark the key in the tutorial text
623 (unless (string= "Same key" where)
625 (case-fold-search nil)
626 (key-desc (key-description key)))
627 (cond ((string= "ESC" key-desc)
628 (setq key-desc "<ESC>"))
629 ((string= "RET" key-desc)
630 (setq key-desc "<Return>"))
631 ((string= "DEL" key-desc)
632 (setq key-desc "<Delback>")))
633 (while (re-search-forward
634 (concat "[[:space:]]\\("
635 (regexp-quote key-desc)
636 "\\)[[:space:]]") nil t)
637 (put-text-property (match-beginning 1)
639 'tutorial-remark 'only-colored)
640 (put-text-property (match-beginning 1)
642 'face 'tutorial-warning-face)
644 (let ((s (get-lang-string tutorial--lang 'tut-chgdkey))
645 (s2 (get-lang-string tutorial--lang 'tut-chgdkey2))
649 (setq s (format s key-desc where s2))
656 'tutorial--detailed-help
657 'explain-key-desc key-desc
663 (put-text-property start end 'local-map tutorial--tab-map)
664 ;; Add a property so we can remove the remark:
665 (put-text-property start end 'tutorial-remark t)
666 (put-text-property start end
667 'face 'tutorial-warning-face)
668 (put-text-property start end 'read-only t))))
669 (goto-char here)))))))
673 ;; Make the area with information about change key
674 ;; bindings stand out:
675 (put-text-property start end 'tutorial-remark t)
676 (put-text-property start end
677 'face 'tutorial-warning-face)
678 ;; Make it possible to use Tab/S-Tab between fields in
680 (put-text-property start end 'local-map tutorial--tab-map)
681 (setq tutorial--point-after-chkeys (point-marker))
682 ;; Make this area read-only:
683 (put-text-property start end 'read-only t)))))
685 (defun tutorial--saved-dir ()
686 "Directory where to save tutorials."
687 (expand-file-name ".emacstut" "~/"))
689 (defun tutorial--saved-file ()
690 "File name in which to save tutorials."
691 (let ((file-name tutorial--lang)
692 (ext (file-name-extension tutorial--lang)))
695 (setq file-name (concat file-name ".tut")))
696 (expand-file-name file-name (tutorial--saved-dir))))
698 (defun tutorial--remove-remarks()
699 "Remove the remark lines that was added to the tutorial buffer."
701 (goto-char (point-min))
705 ;; Catch the case when we already are on a remark line
706 (while (if (get-text-property (point) 'tutorial-remark)
707 (setq prop-start (point))
708 (setq prop-start (next-single-property-change (point) 'tutorial-remark)))
709 (setq prop-end (next-single-property-change prop-start 'tutorial-remark))
710 (setq prop-val (get-text-property prop-start 'tutorial-remark))
712 (setq prop-end (point-max)))
714 (if (eq prop-val 'only-colored)
715 (put-text-property prop-start prop-end 'face '(:background nil))
716 (let ((orig-text (get-text-property prop-start 'tutorial-orig)))
717 (delete-region prop-start prop-end)
718 (when orig-text (insert orig-text))))))))
720 (defun tutorial--save-tutorial ()
721 "Save the tutorial buffer.
722 This saves the part of the tutorial before and after the area
723 showing changed keys. It also saves the point position and the
724 position where the display of changed bindings was inserted."
725 ;; This runs in a hook so protect it:
727 (tutorial--save-tutorial-to (tutorial--saved-file))
728 (error (message "Error saving tutorial state: %s" (error-message-string err))
731 (defun tutorial--save-tutorial-to (saved-file)
732 "Save the tutorial buffer to SAVED-FILE.
733 See `tutorial--save-tutorial' for more information."
735 (when (or (buffer-modified-p)
737 (let ((tutorial-dir (tutorial--saved-dir))
739 ;; The tutorial is saved in a subdirectory in the user home
740 ;; directory. Create this subdirectory first.
741 (unless (file-directory-p tutorial-dir)
743 (make-directory tutorial-dir nil)
744 (error (setq save-err t)
745 (warn "Could not create directory %s: %s" tutorial-dir
746 (error-message-string err)))))
747 ;; Make sure we have that directory.
748 (if (file-directory-p tutorial-dir)
749 (let ((tut-point (if (= 0 tutorial--point-after-chkeys)
750 ;; No info about changed keys is
753 (if (< (point) tutorial--point-after-chkeys)
755 (- (point) tutorial--point-after-chkeys))))
757 ;; Use a special undo list so that we easily can undo
758 ;; the changes we make to the tutorial buffer. This is
759 ;; currently not needed since we now delete the buffer
760 ;; after saving, but kept for possible future use of
763 (inhibit-read-only t))
764 ;; Delete the area displaying info about changed keys.
765 ;; (when (< 0 tutorial--point-after-chkeys)
766 ;; (delete-region tutorial--point-before-chkeys
767 ;; tutorial--point-after-chkeys))
768 ;; Delete the remarks:
769 (tutorial--remove-remarks)
770 ;; Put the value of point first in the buffer so it will
771 ;; be saved with the tutorial.
772 (goto-char (point-min))
773 (insert (number-to-string tut-point)
775 (number-to-string (marker-position
776 tutorial--point-before-chkeys))
779 (write-region nil nil saved-file)
780 (error (setq save-err t)
781 (warn "Could not save tutorial to %s: %s"
783 (error-message-string err))))
784 ;; An error is raised here?? Is this a bug?
789 (goto-char old-point)
791 (message "Could not save tutorial state.")
792 (message "Saved tutorial state.")))
793 (message "Can't save tutorial: %s is not a directory"
798 (defun help-with-tutorial (&optional arg dont-ask-for-revert)
799 "Select the Emacs learn-by-doing tutorial.
800 If there is a tutorial version written in the language
801 of the selected language environment, that version is used.
802 If there's no tutorial in that language, `TUTORIAL' is selected.
803 With ARG, you are asked to choose which language.
804 If DONT-ASK-FOR-REVERT is non-nil the buffer is reverted without
805 any question when restarting the tutorial.
807 If any of the standard Emacs key bindings that are used in the
808 tutorial have been changed then an explanatory note about this is
809 shown in the beginning of the tutorial buffer.
811 When the tutorial buffer is killed the content and the point
812 position in the buffer is saved so that the tutorial may be
815 (if (boundp 'viper-current-state)
817 "You can not run the Emacs tutorial directly because you have \
819 (prompt2 "\nThere is however a Viper tutorial you can run instead.
820 Run the Viper tutorial? "))
821 (if (fboundp 'viper-tutorial)
822 (if (y-or-n-p (concat prompt1 prompt2))
824 (funcall 'viper-tutorial 0))
825 (message "Tutorial aborted by user"))
828 (let ((minibuffer-setup-hook minibuffer-setup-hook))
829 (add-hook 'minibuffer-setup-hook
830 'minibuffer-completion-help)
831 (read-language-name 'tutorial "Language: " "English"))
832 (if (get-language-info current-language-environment 'tutorial)
833 current-language-environment
835 (filename (get-language-info lang 'tutorial))
836 ;; Choose a buffer name including the language so that
837 ;; several languages can be tested simultaneously:
838 (tut-buf-name (concat "TUTORIAL (" lang ")"))
839 (old-tut-buf (get-buffer tut-buf-name))
840 (old-tut-win (when old-tut-buf (get-buffer-window old-tut-buf t)))
841 (old-tut-is-ok (when old-tut-buf
842 (not (buffer-modified-p old-tut-buf))))
845 (setq tutorial--point-after-chkeys (point-min))
846 ;; Try to display the tutorial buffer before asking to revert it.
847 ;; If the tutorial buffer is shown in some window make sure it is
848 ;; selected and displayed:
852 (select-window (get-buffer-window old-tut-buf t))))
853 ;; Else, is there an old tutorial buffer? Then display it:
855 (switch-to-buffer old-tut-buf)))
856 ;; Use whole frame for tutorial
857 (delete-other-windows)
858 ;; If the tutorial buffer has been changed then ask if it should
860 (when (and old-tut-buf
863 (if dont-ask-for-revert
866 "You have changed the Tutorial buffer. Revert it? ")))))
867 ;; (Re)build the tutorial buffer if it is not ok
868 (unless old-tut-is-ok
869 (switch-to-buffer (get-buffer-create tut-buf-name))
870 (unless old-tut-buf (text-mode))
871 (unless lang (error "Variable lang is nil"))
872 (setq tutorial--lang lang)
873 (setq old-tut-file (file-exists-p (tutorial--saved-file)))
874 (let ((inhibit-read-only t))
876 (message "Preparing tutorial ...") (sit-for 0)
878 ;; Do not associate the tutorial buffer with a file. Instead use
879 ;; a hook to save it when the buffer is killed.
880 (setq buffer-auto-save-file-name nil)
881 (add-hook 'kill-buffer-hook 'tutorial--save-tutorial nil t)
883 ;; Insert the tutorial. First offer to resume last tutorial
885 (when dont-ask-for-revert
886 (setq old-tut-file nil))
889 (y-or-n-p "Resume your last saved tutorial? ")))
892 (insert-file-contents (tutorial--saved-file))
893 (goto-char (point-min))
896 (buffer-substring-no-properties
897 (line-beginning-position) (line-end-position))))
899 (setq tutorial--point-before-chkeys
901 (buffer-substring-no-properties
902 (line-beginning-position) (line-end-position))))
904 (delete-region (point-min) (point))
905 (goto-char tutorial--point-before-chkeys)
906 (setq tutorial--point-before-chkeys (point-marker)))
907 (insert-file-contents (expand-file-name filename data-directory))
909 (setq tutorial--point-before-chkeys (point-marker)))
912 ;; Check if there are key bindings that may disturb the
913 ;; tutorial. If so tell the user.
914 (let ((changed-keys (tutorial--find-changed-keys tutorial--default-keys)))
916 (tutorial--display-changes changed-keys)))
920 (unless dont-ask-for-revert
921 (message "") (sit-for 0))
925 ;; Just move to old point in saved tutorial.
927 (if (> 0 old-tut-point)
929 (+ old-tut-point tutorial--point-after-chkeys))))
930 (when (< old-point 1)
932 (goto-char old-point))
933 (goto-char (point-min))
934 (search-forward "\n<<")
936 ;; Convert the <<...>> line to the proper [...] line,
937 ;; or just delete the <<...>> line if a [...] line follows.
938 (cond ((save-excursion
941 (delete-region (point) (progn (forward-line 1) (point))))
942 ((looking-at "<<Blank lines inserted.*>>")
943 (replace-match "[Middle of page left blank for didactic purposes. Text continues below]"))
947 (search-forward ">>")
948 (replace-match "]")))
950 (let ((n (- (window-height (selected-window))
951 (count-lines (point-min) (point))
955 ;; For a short gap, we don't need the [...] line,
957 (delete-region (point) (progn (end-of-line) (point)))
959 ;; Some people get confused by the large gap.
962 ;; Skip the [...] line (don't delete it).
964 (newline (- n (/ n 2)))))
965 (goto-char (point-min)))
966 (setq buffer-undo-list nil)
967 (set-buffer-modified-p nil)))))
970 ;; Below is some attempt to handle language specific strings. These
971 ;; are currently only used in the tutorial.
973 (defconst lang-strings
977 (tut-chgdkey . "** The key %s has been rebound, but you can use %s instead [")
978 (tut-chgdkey2 . "More information")
980 NOTICE: The main purpose of the Emacs tutorial is to teach you
981 the most important standard Emacs commands (key bindings).
982 However, your Emacs has been customized by changing some of
983 these basic editing commands, so it doesn't correspond to the
984 tutorial. We have inserted colored notices where the altered
985 commands have been introduced. [")
986 (tut-chgdhead2 . "Details")
990 "Language specific strings for Emacs.
991 This is an association list with the keys equal to the strings
992 that can be returned by `read-language-name'. The elements in
993 the list are themselves association lists with keys that are
994 string ids and values that are the language specific strings.
996 See `get-lang-string' for more information.")
998 (defun get-lang-string(lang stringid &optional no-eng-fallback)
999 "Get a language specific string for Emacs.
1000 In certain places Emacs can replace a string showed to the user with a language specific string.
1001 This function retrieves such strings.
1003 LANG is the language specification. It should be one of those
1004 strings that can be returned by `read-language-name'. STRINGID
1005 is a symbol that specifies the string to retrieve.
1007 If no string is found for STRINGID in the choosen language then
1008 the English string is returned unless NO-ENG-FALLBACK is non-nil.
1010 See `lang-strings' for more information.
1012 Currently this feature is only used in `help-with-tutorial'."
1013 (let ((my-lang-strings (assoc lang lang-strings))
1015 (when my-lang-strings
1016 (let ((entry (assoc stringid (cdr my-lang-strings))))
1018 (setq found-string (cdr entry)))))
1019 ;; Fallback to English strings
1020 (unless (or found-string
1022 (setq found-string (get-lang-string "English" stringid t)))
1025 ;;(get-lang-string "English" 'tut-chgdkey)
1029 ;; arch-tag: c8e80aef-c3bb-4ffb-8af6-22171bf0c100
1030 ;;; tutorial.el ends here