From 94d2fc1815a919734353c942f224db1de4b4fcb8 Mon Sep 17 00:00:00 2001 From: Tom Willemsen Date: Mon, 7 Mar 2011 09:04:49 +0100 Subject: Django, org * Added nxhtml, mostly for django support. * Changed some org settings. --- emacs.d/nxhtml/util/viper-tut.el | 1009 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1009 insertions(+) create mode 100644 emacs.d/nxhtml/util/viper-tut.el (limited to 'emacs.d/nxhtml/util/viper-tut.el') 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! 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 + ;; + ;; (more info current-binding (keymap (118 . cua-repeat-replace-region)) viper-intercept-ESC-key [27] ))) + + +;;;;;;;;;;;;;; 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 WRITE contents of the file (without quitting) + + ;; :e filename 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 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 + ;; ]) + (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 -- cgit v1.2.3-54-g00ecf