summaryrefslogtreecommitdiffstats
path: root/emacs.d/nxhtml/util/viper-tut.el
diff options
context:
space:
mode:
Diffstat (limited to 'emacs.d/nxhtml/util/viper-tut.el')
-rw-r--r--emacs.d/nxhtml/util/viper-tut.el1009
1 files changed, 1009 insertions, 0 deletions
diff --git a/emacs.d/nxhtml/util/viper-tut.el b/emacs.d/nxhtml/util/viper-tut.el
new file mode 100644
index 0000000..a941045
--- /dev/null
+++ b/emacs.d/nxhtml/util/viper-tut.el
@@ -0,0 +1,1009 @@
+;;; viper-tut.el --- Viper tutorial
+;;
+;; Author: Lennart Borgman
+;; Created: Fri Sep 08 2006
+(defconst viper-tut:version "0.2") ;;Version: 0.2
+;; Last-Updated:
+;; Keywords:
+;; Compatibility: Emacs 22
+;;
+;; Features that might be required by this library:
+;;
+;; `button', `cus-edit', `cus-face', `cus-load', `cus-start',
+;; `help-mode', `tutorial', `view', `wid-edit'.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Commentary:
+;;
+;;
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Change log:
+;;
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Code:
+
+(eval-when-compile (require 'mumamo))
+(eval-when-compile (require 'ourcomments-util))
+(require 'tutorial)
+(require 'cus-edit)
+
+(defface viper-tut-header-top
+ '((t (:foreground "black" :background "goldenrod3")))
+ "Face for headers."
+ :group 'web-vcs)
+
+(defface viper-tut-header
+ '((t (:foreground "black" :background "goldenrod2" :height 1.8)))
+ "Face for headers."
+ :group 'web-vcs)
+
+(defvar tutorial--tab-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [tab] 'forward-button)
+ (define-key map [(shift tab)] 'backward-button)
+ (define-key map [(meta tab)] 'backward-button)
+ map)
+ "Keymap that allows tabbing between buttons.")
+
+(defconst viper-tut--emacs-part 6)
+
+(defconst viper-tut--default-keys
+ `(
+;;;;;;;;;;;;;; Part 1
+ ;; ^D Move DOWN one half-screen
+ ;;(viper-scroll-up [(control ?d)])
+ (viper-scroll-up [?\C-d])
+
+ ;; ^U Move UP one half-screen
+ ;;(viper-scroll-down [(control ?u)])
+ (viper-scroll-down [?\C-u])
+
+ ;; h Move left one character
+ (viper-backward-char [?h])
+
+ ;; j Move down one line
+ (viper-next-line [?j])
+
+ ;; k Move up one line
+ (viper-previous-line [?k])
+
+ ;; l Move right one character
+ (viper-forward-char [?l])
+
+ ;; dd DELETE one line
+ (viper-command-argument [?d])
+
+ ;; x X-OUT one character
+ (viper-delete-char [?x])
+
+ ;; u UNDO last change
+ (viper-undo [?u])
+
+ ;; :q!<RETURN> QUIT without saving changes
+ (viper-ex [?:])
+
+ ;; ZZ Exit and save any changes
+ (viper-save-kill-buffer [?Z ?Z])
+
+ ;; o OPEN a line for inserting text
+ (viper-open-line [?o])
+
+ ;; i INSERT starting at the cursor
+ (viper-insert [?i])
+
+ ;; ESC ESCAPE from insert mode
+ ;;(viper-intercept-ESC-key [(escape)])
+ ;(viper-intercept-ESC-key [27])
+ (viper-intercept-ESC-key [escape])
+ ;; chagned-keys=
+ ;; (([27]
+ ;; viper-intercept-ESC-key
+ ;; viper-intercept-ESC-key
+ ;; <escape>
+ ;; (more info current-binding (keymap (118 . cua-repeat-replace-region)) viper-intercept-ESC-key [27] <escape>)))
+
+
+;;;;;;;;;;;;;; Part 2
+ ;; w Move to the beginning of the next WORD
+ (viper-forward-word [?w])
+ ;; e Move to the END of the next word
+ (viper-end-of-word [?e])
+ ;; b Move BACK to the beginning to the previous word
+ (viper-backward-word [?b])
+
+ ;; $ Move to the end of the line
+ (viper-goto-eol [?$])
+
+ ;; ^ Move to the first non-white character on the line
+ (viper-bol-and-skip-white [?^])
+
+ ;; 0 Move to the first column on the line (column zero)
+ (viper-beginning-of-line [?0])
+ ;; #| Move to an exact column on the line (column #) e.g. 5| 12|
+ (viper-goto-col [?|])
+
+ ;; f char FIND the next occurrence of char on the line
+ (viper-find-char-forward [?f])
+ ;; t char Move 'TIL the next occurrence of char on the line
+ (viper-goto-char-forward [?t])
+
+ ;; F char FIND the previous occurrence of char on the line
+ (viper-find-char-backward [?F])
+ ;; T char Move 'TIL the previous occurrence of char on the line
+ (viper-goto-char-backward [?T])
+
+ ;; ; Repeat the last f, t, F, or T
+ (viper-repeat-find [?\;])
+ ;; , Reverse the last f, t, F, or T
+ (viper-repeat-find-opposite [?,])
+
+ ;; % Show matching () or {} or []
+ (viper-exec-mapped-kbd-macro [?%])
+
+ ;; H Move to the HIGHEST position in the window
+ (viper-window-top [?H])
+ ;; M Move to the MIDDLE position in the window
+ (viper-window-middle [?M])
+ ;; L Move to the LOWEST position in the window
+ (viper-window-bottom [?L])
+
+ ;; m char MARK this location and name it char
+ (viper-mark-point [?m])
+ ;; ' char (quote character) return to line named char
+ ;; '' (quote quote) return from last movement
+ (viper-goto-mark-and-skip-white [?'])
+
+ ;; G GO to the last line in the file
+ ;; #G GO to line #. (e.g., 3G , 5G , 175G )
+ (viper-goto-line [?G])
+
+ ;; { (left brace) Move to the beginning of a paragraph
+ ;; } (right brace) Move to the end of a paragraph
+ (viper-backward-paragraph [?{])
+ (viper-forward-paragraph [?}])
+
+ ;; ( (left paren) Move to the beginning of a sentence
+ ;; ) (right paren) Move to the beginning of the next sentence
+ (viper-backward-sentence [?\(])
+ (viper-forward-sentence [?\)])
+
+ ;; [[ Move to the beginning of a section
+ ;; ]] Move to the end of a section
+ (viper-brac-function [?\[])
+ (viper-ket-function [?\]])
+
+ ;; /string Find string looking forward
+ (viper-exec-mapped-kbd-macro [?/])
+ ;; ?string Find string looking backward
+ (viper-search-backward [??])
+
+ ;; n Repeat last / or ? command
+ ;; N Reverse last / or ? command
+ (viper-search-next [?n])
+ (viper-search-Next [?N])
+
+
+;;;;;;;;;;;;;; Part 3
+
+ ;; #movement repeat movement # times
+ (viper-digit-argument [?1])
+ (viper-digit-argument [?2])
+ (viper-digit-argument [?3])
+ (viper-digit-argument [?4])
+ (viper-digit-argument [?5])
+ (viper-digit-argument [?6])
+ (viper-digit-argument [?7])
+ (viper-digit-argument [?8])
+ (viper-digit-argument [?9])
+
+ ;; dmovement DELETE to where "movement" command specifies
+ ;; d#movement DELETE to where the #movement command specifies
+ ;; d runs the command viper-command-argument
+
+ ;; ymovement YANK to where "movement" command specifies
+ ;; y#movement YANK to where the #movement command specifies
+ (viper-command-argument [?y])
+
+ ;; P (upper p) PUT the contents of the buffer before the cursor
+ ;; p (lower p) PUT the contents of the buffer after the cursor
+ (viper-put-back [?p])
+ (viper-Put-back [?P])
+
+ ;; "#P (upper p) PUT contents of buffer # before the cursor
+ ;; "#p (lower p) PUT contents of buffer # after the cursor
+ ;;
+ ;; "aDELETE DELETE text into buffer a
+ ;; "aYANK YANK text into buffer a
+ ;; "aPUT PUT text from named buffer a
+ (viper-command-argument [?\"])
+
+ ;; :w<RETURN> WRITE contents of the file (without quitting)
+
+ ;; :e filename<RETURN> Begin EDITing the file called "filename"
+
+
+
+;;;;;;;;;;;;;; Part 4
+
+
+ ;; o OPEN a line below the cursor
+ ;; O OPEN a line above the cursor
+ (viper-open-line [?o])
+ (viper-Open-line [?O])
+
+ ;; i INSERT starting before the cursor
+ ;; I INSERT at the beginning of the line
+ (viper-insert [?i])
+ (viper-Insert [?I])
+
+ ;; a APPEND starting after the cursor
+ ;; A APPEND at the end of the line
+ (viper-append [?a])
+ (viper-Append [?A])
+
+ ;; ESC ESCAPE from insert mode
+ (viper-intercept-ESC-key [(escape)])
+
+ ;; J JOIN two lines
+ (viper-join-lines [?J])
+
+ ;; #s SUBSTITUTE for # characters
+ ;; #S SUBSTITUTE for # whole lines
+ (viper-substitute [?s])
+ (viper-substitute-line [?S])
+
+ ;; r REPLACE character (NO need to press ESC)
+ ;; R enter over-type mode
+ (viper-replace-char [?r])
+ (viper-overwrite [?R])
+
+ ;; cmovement CHANGE to where the movement commands specifies
+ (viper-command-argument [?c])
+
+
+;;;;;;;;;;;;;; Part 5
+
+ ;; ~ (tilde) Convert case of current character
+ (viper-toggle-case [?~])
+ ;; U (upper u) UNDO all changes made to the current line
+ ;; not implemented
+ ;;(viper-undo [?U])
+
+ ;; . (dot) repeat last change
+ (viper-repeat [?.])
+
+ ;; ^F Move FORWARD one full-screen
+ ;; ^B Move BACKWARD one full-screen
+ ;;(viper-scroll-screen [(control ?f)])
+ (viper-scroll-screen [?\C-f])
+ ;;(viper-scroll-screen-back [(control ?b)])
+ (viper-scroll-screen-back [?\C-b])
+
+ ;; ^E Move the window down one line without moving cursor
+ ;; ^Y Move the window up one line without moving cursor
+ ;;(viper-scroll-up-one [(control ?e)])
+ (viper-scroll-up-one [?\C-e])
+ ;;(viper-scroll-down-one [(control ?y)])
+ (viper-scroll-down-one [?\C-y])
+
+ ;; z<RETURN> Position the current line to top of window
+ ;; z. Position the current line to middle of window
+ ;; z- Position the current line to bottom of window
+ (viper-line-to-top "z\C-m")
+ (viper-line-to-middle [?z ?.])
+ (viper-line-to-bottom [?z ?-])
+
+ ;; ^G Show status of current file
+ ;;(viper-info-on-file [(control ?c)(control ?g)])
+ (viper-info-on-file [?\C-c ?\C-g])
+ ;; ^L Refresh screen
+ ;;(recenter [(control ?l)])
+ (recenter-top-bottom [?\C-l])
+
+ ;; !}fmt Format the paragraph, joining and filling lines to
+ ;; !}sort Sort lines of a paragraph alphabetically
+ (viper-command-argument [?!])
+
+ ;; >movement Shift right to where the movement command specifies
+ ;; <movement Shift left to where the movement command specifies
+ (viper-command-argument [?>])
+ (viper-command-argument [?<])
+
+ ))
+
+(defun viper-tut--detailed-help (button)
+ "Give detailed help about changed keys."
+ (with-output-to-temp-buffer (help-buffer)
+ (help-setup-xref (list #'viper-tut--detailed-help button)
+ (interactive-p))
+ (with-current-buffer (help-buffer)
+ (let* ((tutorial-buffer (button-get button 'tutorial-buffer))
+ ;;(tutorial-arg (button-get button 'tutorial-arg))
+ (explain-key-desc (button-get button 'explain-key-desc))
+ (part (button-get button 'part))
+ (changed-keys (with-current-buffer tutorial-buffer
+ (let ((tutorial--lang "English"))
+ (tutorial--find-changed-keys
+ (if (= part viper-tut--emacs-part)
+ tutorial--default-keys
+ viper-tut--default-keys))))))
+ (when changed-keys
+ (insert
+ "The following key bindings used in the tutorial had been changed\n"
+ (if (= part viper-tut--emacs-part)
+ "from Emacs default in the "
+ "from Viper default in the ")
+ (buffer-name tutorial-buffer) " buffer:\n\n" )
+ (let ((frm " %-9s %-27s %-11s %s\n"))
+ (insert (format frm "Key" "Standard Binding" "Is Now On" "Remark")))
+ (dolist (tk changed-keys)
+ (let* ((def-fun (nth 1 tk))
+ (key (nth 0 tk))
+ (def-fun-txt (nth 2 tk))
+ (where (nth 3 tk))
+ (remark (nth 4 tk))
+ (rem-fun (command-remapping def-fun))
+ (key-txt (key-description key))
+ (key-fun (with-current-buffer tutorial-buffer (key-binding key)))
+ tot-len)
+ (unless (eq def-fun key-fun)
+ ;; Insert key binding description:
+ (when (string= key-txt explain-key-desc)
+ (put-text-property 0 (length key-txt) 'face '(:background "yellow") key-txt))
+ (insert " " key-txt " ")
+ (setq tot-len (length key-txt))
+ (when (> 9 tot-len)
+ (insert (make-string (- 9 tot-len) ? ))
+ (setq tot-len 9))
+ ;; Insert a link describing the old binding:
+ (insert-button def-fun-txt
+ 'help-echo (format "Describe function '%s" def-fun-txt)
+ 'action `(lambda(button) (interactive)
+ (describe-function ',def-fun))
+ 'follow-link t)
+ (setq tot-len (+ tot-len (length def-fun-txt)))
+ (when (> 36 tot-len)
+ (insert (make-string (- 36 tot-len) ? )))
+ (when (listp where)
+ (setq where "list"))
+ ;; Tell where the old binding is now:
+ (insert (format " %-11s " where))
+ ;; Insert a link with more information, for example
+ ;; current binding and keymap or information about
+ ;; cua-mode replacements:
+ (insert-button (car remark)
+ 'help-echo "Give more information about the changed key binding"
+ 'action `(lambda(b) (interactive)
+ (let ((value ,(cdr remark)))
+ ;; Fix-me:
+ (tutorial--describe-nonstandard-key value)))
+ 'follow-link t)
+ (insert "\n")))))
+
+
+
+ (insert "
+It is legitimate to change key bindings, but changed bindings do not
+correspond to what the tutorial says.
+\(See also " )
+ (insert-button "Key Binding Conventions"
+ 'action
+ (lambda(button) (interactive)
+ (info
+ "(elisp) Key Binding Conventions")
+ (message "Type C-x 0 to close the new window"))
+ 'follow-link t)
+ (insert ".)\n\n")
+ (with-no-warnings (print-help-return-message))))))
+
+
+(defvar viper-tut--part nil
+ "Viper tutorial part.")
+(make-variable-buffer-local 'viper-tut--part)
+
+(defun viper-tut--saved-file ()
+ "File name in which to save tutorials."
+ (let* ((file-name
+ (file-name-nondirectory (viper-tut--file viper-tut--part)))
+ (ext (file-name-extension file-name)))
+ (when (or (not ext)
+ (string= ext ""))
+ (setq file-name (concat file-name ".tut")))
+ (expand-file-name file-name (tutorial--saved-dir))))
+
+(defun viper-tut--save-tutorial ()
+ "Save the tutorial buffer.
+This saves the part of the tutorial before and after the area
+showing changed keys. It also saves point position and the
+position where the display of changed bindings was inserted.
+
+Do not save anything if not `viper-mode' is enabled in the
+tutorial buffer."
+ ;; This runs in a hook so protect it:
+ (condition-case err
+ (when (boundp 'viper-mode-string)
+ (tutorial--save-tutorial-to (viper-tut--saved-file)))
+ (error (warn "Error saving tutorial state: %s" (error-message-string err)))))
+
+
+(defvar viper-tut--parts
+ '(
+ (0 "0intro" "Introduction")
+ (1 "1basics" "Basic Editing")
+ (2 "2moving" "Moving Efficiently")
+ (3 "3cutpaste" "Cutting and Pasting")
+ (4 "4inserting" "Inserting Techniques")
+ (5 "5tricks" "Tricks and Timesavers")
+ (6 "(no file)" "Emacs tutorial for Viper Users")
+ ))
+
+(defcustom viper-tut-directory
+ (let* ((this-file (if load-file-name
+ load-file-name
+ (buffer-file-name)))
+ (this-dir (file-name-directory this-file)))
+ (file-name-as-directory
+ (expand-file-name "../etc/viper-tut" this-dir)))
+ "Directory where the Viper tutorial files lives."
+ :type 'directory
+ :group 'viper)
+
+(defun viper-tut--file(part)
+ "Get file name for part."
+ (let ((tut-file))
+ (mapc (lambda(rec)
+ (when (= part (nth 0 rec))
+ (setq tut-file
+ (if (= part viper-tut--emacs-part)
+ (let ((tf (expand-file-name (get-language-info "English" 'tutorial) tutorial-directory)))
+ (unless (file-exists-p tf)
+ (error "Can't find the English tutorial file for Emacs: %S" tf))
+ tf)
+ (expand-file-name (nth 1 rec) viper-tut-directory)))))
+ viper-tut--parts)
+ tut-file))
+
+(defun viper-tut-viper-is-on ()
+ ;;(message "viper-tut-viper-is-on, vms=%s, cb=%s" (boundp 'viper-mode-string) (current-buffer))
+ ;;(boundp 'viper-mode-string)
+ (boundp 'viper-current-state))
+
+(defun viper-tut--display-changes (changed-keys part)
+ "Display changes to some default Viper key bindings.
+If some of the default key bindings that the Viper tutorial
+depends on have been changed then display the changes in the
+tutorial buffer with some explanatory links.
+
+CHANGED-KEYS should be a list in the format returned by
+`tutorial--find-changed-keys'."
+ (when (or changed-keys
+ (viper-tut-viper-is-on))
+ ;; Need the custom button face for viper buttons:
+ ;;(when (and (boundp 'viper-mode) viper-mode) (require 'cus-edit))
+ (goto-char tutorial--point-before-chkeys)
+ (let* ((start (point))
+ end
+ (head
+ (if (viper-tut-viper-is-on)
+ (if (= part viper-tut--emacs-part)
+ "
+ NOTICE: This part of the Viper tutorial runs the Emacs tutorial.
+ Several keybindings are changed from Emacs default (either
+ because of Viper or some other customization) and doesn't
+ correspond to the tutorial.
+
+ We have inserted colored notices where the altered commands have
+ been introduced. If you change Viper state (vi state, insert
+ state, etc) these notices will be changed to reflect the new
+ state. ["
+ "
+ NOTICE: The main purpose of the Viper tutorial is to teach you
+ the most important vi commands (key bindings). However, your
+ Emacs has been customized by changing some of these basic Viper
+ editing commands, so it doesn't correspond to the tutorial. We
+ have inserted colored notices where the altered commands have
+ been introduced. [")
+ "
+ NOTICE: You have currently not turned on Viper. Nothing in this
+ tutorial \(the Viper Tutorial\) will work unless you do that. ["
+ ))
+ (head2 (if (viper-tut-viper-is-on)
+ (get-lang-string tutorial--lang 'tut-chgdhead2)
+ "More information")))
+ (when (and head head2)
+ (insert head)
+ (insert-button head2
+ 'tutorial-buffer
+ (current-buffer)
+ ;;'tutorial-arg arg
+ 'part part
+ 'action
+ (if (viper-tut-viper-is-on)
+ 'viper-tut--detailed-help
+ 'go-home-blaha)
+ 'follow-link t
+ 'echo "Click for more information"
+ 'face '(:inherit link :background "yellow"))
+ (insert "]\n\n" )
+ (when changed-keys
+ (dolist (tk changed-keys)
+ (let* ((def-fun (nth 1 tk))
+ (key (nth 0 tk))
+ (def-fun-txt (nth 2 tk))
+ (where (nth 3 tk))
+ (remark (nth 4 tk))
+ (rem-fun (command-remapping def-fun))
+ (key-txt (key-description key))
+ (key-fun (key-binding key))
+ tot-len)
+ (unless (eq def-fun key-fun)
+ ;; Mark the key in the tutorial text
+ (unless (string= "Same key" where)
+ (let* ((here (point))
+ (key-desc (key-description key))
+ (vi-char (= 1 (length key-desc)))
+ vi-char-pos
+ hit)
+ (when (string= "RET" key-desc)
+ (setq key-desc "Return"))
+ (when (string= "DEL" key-desc)
+ (setq key-desc "Delback"))
+ (while (if (not vi-char)
+ (unless hit ;; Only tell once
+ (setq hit t)
+ (re-search-forward
+ (concat "[^[:alpha:]]\\("
+ (regexp-quote key-desc)
+ "\\)[^[:alpha:]]") nil t))
+ (setq vi-char-pos
+ (next-single-property-change
+ (point) 'vi-char)))
+ (if (not vi-char)
+ (put-text-property (match-beginning 0)
+ (match-end 0)
+ 'tutorial-remark nil) ;;'only-colored)
+ (put-text-property (match-beginning 0)
+ (match-end 0)
+ 'face '(:background "yellow"))
+ (goto-char (1+ vi-char-pos))
+ (setq hit (string= key-desc (char-to-string (char-before))))
+ (when hit
+ (put-text-property vi-char-pos (1+ vi-char-pos)
+ 'face '(:background "yellow"))))
+ (when hit
+ (forward-line)
+ (let ((s (get-lang-string tutorial--lang 'tut-chgdkey))
+ (s2 (get-lang-string tutorial--lang 'tut-chgdkey2))
+ (start (point))
+ end)
+ ;; key-desc " has been rebound, but you can use " where " instead ["))
+ (when (and s s2)
+ (when (or (not where) (= 0 (length where)))
+ (setq where (concat "`M-x " def-fun-txt "'")))
+ (setq s (format s key-desc where s2))
+ (insert s " [")
+ (insert-button s2
+ 'tutorial-buffer
+ (current-buffer)
+ ;;'tutorial-arg arg
+ 'part part
+ 'action
+ 'viper-tut--detailed-help
+ 'explain-key-desc key-desc
+ 'follow-link t
+ 'face '(:inherit link :background "yellow"))
+ (insert "] **")
+ (insert "\n")
+ (setq end (point))
+ (put-text-property start end 'local-map tutorial--tab-map)
+ (put-text-property start end 'tutorial-remark t)
+ (put-text-property start end
+ 'face '(:background "yellow" :foreground "#c00"))
+ (put-text-property start end 'read-only t)))))
+ (goto-char here)))))))
+
+
+ (setq end (point))
+ ;; Make the area with information about change key
+ ;; bindings stand out:
+ (put-text-property start end
+ 'face
+ ;; The default warning face does not
+ ;;look good in this situation. Instead
+ ;;try something that could be
+ ;;recognized from warnings in normal
+ ;;life:
+ ;; 'font-lock-warning-face
+ (list :background "yellow" :foreground "#c00"))
+ ;; Make it possible to use Tab/S-Tab between fields in
+ ;; this area:
+ (put-text-property start end 'local-map tutorial--tab-map)
+ (put-text-property start end 'tutorial-remark t)
+ (setq tutorial--point-after-chkeys (point-marker))
+ ;; Make this area read-only:
+ (put-text-property start end 'read-only t)))))
+
+(defun viper-tut--at-change-state()
+ (condition-case err
+ (progn
+ (let ((inhibit-read-only t)
+ (here (point)))
+ ;; Delete the remarks:
+ ;;(tutorial--remove-remarks)
+ ;; Add them again
+ ;;(viper-tut--add-remarks)
+ (goto-char here)
+ )
+ )
+ (error (message "error in viper-tut--at-change-state: %s" (error-message-string err)))))
+
+
+;;;###autoload
+(defun viper-tutorial(part &optional dont-ask-for-revert)
+ "Run a tutorial for Viper.
+
+A simple classic tutorial in 5 parts that have been used by many
+people starting to learn vi keys. You may learn enough to start
+using `viper-mode' in Emacs.
+
+Some people find that vi keys helps against repetetive strain
+injury, see URL
+
+ `http://www.emacswiki.org/emacs/RepeatedStrainInjury'.
+
+Note: There might be a few clashes between vi key binding and
+Emacs standard key bindings. You will be notified about those in
+the tutorial. Even more, if your own key bindings comes in
+between you will be notified about that too."
+ (interactive (list
+ ;; (condition-case nil
+ ;; (widget-choose "The following viper tutorials are available"
+ ;; (mapcar (lambda(rec)
+ ;; (cons (nth 2 rec) (nth 0 rec)))
+ ;; viper-tut--parts))
+ ;; (error nil))
+ 0
+ ))
+ (if (not (boundp 'viper-current-state))
+ (let ((prompt
+ "
+ You can not run the Viper tutorial in this Emacs because you
+ have not enabled Viper.
+
+ Do you want to run the Viper tutorial in a new Emacs? "))
+ (if (y-or-n-p prompt)
+ (let ((ret (funcall 'emacs--no-desktop
+ "-eval"
+ (concat
+ "(progn"
+ " (setq viper-mode t)"
+ " (require 'viper)"
+ " (require 'viper-tut)"
+ " (call-interactively 'viper-tutorial))"))))
+ (message "Starting Viper tutorial in a new Emacs"))
+ (message "Viper tutorial aborted by user")))
+
+ (let* ((filename (viper-tut--file part))
+ ;; Choose a buffer name including the language so that
+ ;; several languages can be tested simultaneously:
+ (tut-buf-name "Viper TUTORIAL")
+ (old-tut-buf (get-buffer tut-buf-name))
+ (old-tut-part (when old-tut-buf
+ (with-current-buffer old-tut-buf
+ viper-tut--part)))
+ (old-tut-win (when old-tut-buf (get-buffer-window old-tut-buf t)))
+ (old-tut-is-ok (when old-tut-buf
+ (and
+ (= part old-tut-part)
+ (not (buffer-modified-p old-tut-buf)))))
+ old-tut-file
+ (old-tut-point 1))
+ (unless (file-exists-p filename) (error "Can't fine %s" filename))
+ (setq tutorial--point-after-chkeys (point-min))
+ ;; Try to display the tutorial buffer before asking to revert it.
+ ;; If the tutorial buffer is shown in some window make sure it is
+ ;; selected and displayed:
+ (if old-tut-win
+ (raise-frame
+ (window-frame
+ (select-window (get-buffer-window old-tut-buf t))))
+ ;; Else, is there an old tutorial buffer? Then display it:
+ (when old-tut-buf
+ (switch-to-buffer old-tut-buf)))
+ ;; Use whole frame for tutorial
+ ;;(delete-other-windows)
+ ;; If the tutorial buffer has been changed then ask if it should
+ ;; be reverted:
+ (when (and old-tut-buf
+ (not old-tut-is-ok)
+ (= part old-tut-part))
+ (setq old-tut-is-ok
+ (if dont-ask-for-revert
+ nil
+ (not (y-or-n-p
+ "You have changed the Tutorial buffer. Revert it? ")))))
+ ;; (Re)build the tutorial buffer if it is not ok
+ (unless old-tut-is-ok
+ (switch-to-buffer (get-buffer-create tut-buf-name))
+ (unless old-tut-buf (text-mode))
+ (setq viper-tut--part part)
+ (setq old-tut-file (file-exists-p (viper-tut--saved-file)))
+ (when (= part 0) (setq old-tut-file nil)) ;; You do not edit in the intro
+ (setq buffer-read-only nil)
+ (let ((inhibit-read-only t)) ;; For the text property
+ (erase-buffer))
+ (message "Preparing Viper tutorial ...") (sit-for 0)
+
+ ;; Do not associate the tutorial buffer with a file. Instead use
+ ;; a hook to save it when the buffer is killed.
+ (setq buffer-auto-save-file-name nil)
+ (add-hook 'kill-buffer-hook 'viper-tut--save-tutorial nil t)
+
+ ;; Insert the tutorial. First offer to resume last tutorial
+ ;; editing session.
+ (when dont-ask-for-revert
+ (setq old-tut-file nil))
+ (when old-tut-file
+ (setq old-tut-file
+ (y-or-n-p
+ (format
+ "Resume your last saved Viper tutorial part %s? "
+ part))))
+ (if old-tut-file
+ (progn
+ (insert-file-contents (viper-tut--saved-file))
+ (goto-char (point-min))
+ (setq old-tut-point
+ (string-to-number
+ (buffer-substring-no-properties
+ (line-beginning-position) (line-end-position))))
+ (forward-line)
+ (setq tutorial--point-before-chkeys
+ (string-to-number
+ (buffer-substring-no-properties
+ (line-beginning-position) (line-end-position))))
+ (forward-line)
+ (delete-region (point-min) (point))
+ (goto-char tutorial--point-before-chkeys)
+ (setq tutorial--point-before-chkeys (point-marker)))
+ ;;(insert-file-contents (expand-file-name filename data-directory))
+ (insert-file-contents filename)
+ (viper-tut--replace-links)
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "'\\([][+a-zA-Z~<>!;,:.'\"%/?(){}$^0|-]\\)'" nil t)
+ (let ((matched-char (match-string 1))
+ (inhibit-read-only t))
+ (put-text-property 0 1 'vi-char t matched-char)
+ (put-text-property 0 1 'face '(:foreground "blue") matched-char)
+ (replace-match matched-char))))
+ (forward-line)
+ (setq tutorial--point-before-chkeys (point-marker)))
+
+ (viper-tut--add-remarks)
+
+ (goto-char (point-min))
+ (when old-tut-file
+ ;; Just move to old point in saved tutorial.
+ (let ((old-point
+ (if (> 0 old-tut-point)
+ (- old-tut-point)
+ (+ old-tut-point tutorial--point-after-chkeys))))
+ (when (< old-point 1)
+ (setq old-point 1))
+ (goto-char old-point)))
+
+ (viper-tut-fix-header-and-footer)
+
+ ;; Clear message:
+ (message "") (sit-for 0)
+
+ (setq buffer-undo-list nil)
+ (set-buffer-modified-p nil))
+ (setq buffer-read-only (= 0 part)))))
+
+;;(tutorial--find-changed-keys '((scroll-up [?\C-v])))
+(defun viper-tut--add-remarks()
+ ;; Check if there are key bindings that may disturb the
+ ;; tutorial. If so tell the user.
+ (let* ((tutorial--lang "English")
+ (changed-keys
+ (if (= viper-tut--part viper-tut--emacs-part)
+ (tutorial--find-changed-keys tutorial--default-keys)
+ (tutorial--find-changed-keys viper-tut--default-keys))))
+ (viper-tut--display-changes changed-keys viper-tut--part))
+
+ (if (= viper-tut--part viper-tut--emacs-part)
+ (progn
+ (add-hook 'viper-vi-state-hook 'viper-tut--at-change-state nil t)
+ (add-hook 'viper-insert-state-hook 'viper-tut--at-change-state nil t)
+ (add-hook 'viper-replace-state-hook 'viper-tut--at-change-state nil t)
+ (add-hook 'viper-emacs-state-hook 'viper-tut--at-change-state nil t)
+ )
+ (remove-hook 'viper-vi-state-hook 'viper-tut--at-change-state t)
+ (remove-hook 'viper-insert-statehook 'viper-tut--at-change-state t)
+ (remove-hook 'viper-replace-state-hook 'viper-tut--at-change-state t)
+ (remove-hook 'viper-emacs-state-hook 'viper-tut--at-change-state t)
+ ))
+
+(defun viper-tut-fix-header-and-footer ()
+ (save-excursion
+ (goto-char (point-min))
+ (add-text-properties (point) (1+ (line-end-position))
+ '( read-only t face viper-tut-header))
+ (goto-char (point-min))
+ (viper-tut--insert-goto-row nil)
+ (goto-char (point-max))
+ (viper-tut--insert-goto-row t)))
+
+(defun viper-tut--insert-goto-row(last)
+ (let ((start (point))
+ end)
+ (insert " Go to part: ")
+ (dolist (rec viper-tut--parts)
+ (let ((n (nth 0 rec))
+ (file (nth 1 rec))
+ (title (nth 2 rec)))
+ (if (= n viper-tut--part)
+ (insert (format "%s" n))
+ (insert-button (format "%s" n)
+ 'help-echo (concat "Go to part: " title)
+ 'follow-link t
+ 'action
+ `(lambda (button)
+ (viper-tutorial ,n t))))
+ (insert " ")))
+ (insert " ")
+ (insert-button "Exit Tutorial"
+ 'help-echo "Exit tutorial and close tutorial buffer"
+ 'follow-link t
+ 'action
+ (lambda (button)
+ (kill-buffer (current-buffer))))
+ (unless last (insert "\n"))
+ (setq end (point))
+ (put-text-property start end 'local-map tutorial--tab-map)
+ (put-text-property start end 'tutorial-remark t)
+ (put-text-property start end
+ 'face 'viper-tut-header-top)
+ (put-text-property start end 'read-only t)))
+
+(defun viper-tut--replace-links()
+ "Replace markers for links with actual links."
+ (let ((re-links (regexp-opt '("VIPER-MANUAL"
+ "README-FILE"
+ "DIGIT-ARGUMENT"
+ "KILL-BUFFER"
+ "ISEARCH-FORWARD"
+ "UNIVERSAL-ARGUMENT"
+ "SEARCH-COMMANDS"
+ "R-AND-R"
+ "CUA-MODE"
+ "KEYBOARD-MACROS"
+ "VIPER-TOGGLE-KEY"
+ "* EMACS-NOTICE:")))
+ (case-fold-search nil)
+ (inhibit-read-only t))
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward re-links nil t)
+ (let ((matched (match-string 0))
+ start
+ end)
+ (replace-match "")
+ (setq start (point))
+ (cond
+ ((string= matched "VIPER-TOGGLE-KEY")
+ (insert-button "viper-toggle-key"
+ 'action
+ (lambda(button) (interactive)
+ (describe-variable 'viper-toggle-key))
+ 'follow-link t))
+ ((string= matched "CUA-MODE")
+ (insert-button "cua-mode"
+ 'action
+ (lambda(button) (interactive)
+ (describe-function 'cua-mode))
+ 'follow-link t))
+ ((string= matched "ISEARCH-FORWARD")
+ (insert-button "isearch-forward"
+ 'action
+ (lambda(button) (interactive)
+ (describe-function 'isearch-forward))
+ 'follow-link t))
+ ((string= matched "KILL-BUFFER")
+ (insert-button "kill-buffer"
+ 'action
+ (lambda(button) (interactive)
+ (describe-function 'kill-buffer))
+ 'follow-link t))
+ ((string= matched "UNIVERSAL-ARGUMENT")
+ (insert-button "universal-argument"
+ 'action
+ (lambda(button) (interactive)
+ (describe-function 'universal-argument))
+ 'follow-link t))
+ ((string= matched "DIGIT-ARGUMENT")
+ (insert-button "digit-argument"
+ 'action
+ (lambda(button) (interactive)
+ (describe-function 'digit-argument))
+ 'follow-link t))
+ ((string= matched "* EMACS-NOTICE:")
+ (insert "* Emacs NOTICE:")
+ (while (progn
+ (forward-line 1)
+ (not (looking-at "^$"))))
+ (put-text-property start (point)
+ 'face '(:background
+ "#ffe4b5"
+ :foreground "#999999"))
+ (put-text-property start (point) 'read-only t)
+ )
+ ((string= matched "SEARCH-COMMANDS")
+ (insert-button "search commands"
+ 'action
+ (lambda(button) (interactive)
+ (info-other-window "(emacs) Search")
+ (message "Type C-x 0 to close the new window"))
+ 'follow-link t))
+ ((string= matched "KEYBOARD-MACROS")
+ (insert-button "keyboard macros"
+ 'action
+ (lambda(button) (interactive)
+ (info-other-window "(emacs) Keyboard Macros")
+ (message "Type C-x 0 to close the new window"))
+ 'follow-link t))
+ ((string= matched "VIPER-MANUAL")
+ (insert-button "Viper manual"
+ 'action
+ (lambda(button) (interactive)
+ (info-other-window "(viper)")
+ (message "Type C-x 0 to close the new window"))
+ 'follow-link t))
+ ((string= matched "R-AND-R")
+ (insert-button "r and R"
+ 'action
+ (lambda(button) (interactive)
+ (info-other-window "(viper) Basics")
+ (message "Type C-x 0 to close the new window"))
+ 'follow-link t))
+ ((string= matched "README-FILE")
+ (insert-button "README file"
+ 'action
+ (lambda(button) (interactive)
+ (find-file-other-window (expand-file-name "README" viper-tut-directory))
+ (message "Type C-x 0 to close the new window"))
+ 'follow-link t))
+ (t
+ (error "Unmatched text: %s" matched)))
+ (put-text-property start (point) 'tutorial-remark t)
+ (put-text-property start (point) 'tutorial-orig matched)
+ (put-text-property start (point) 'local-map tutorial--tab-map)
+ (put-text-property start (point) 'read-only t))))))
+
+(provide 'viper-tut)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; viper-tut.el ends here