1 ;;; tinytab.el --- Programmers TAB minor mode. Very flexible.
3 ;; This file is not part of Emacs
7 ;; Copyright (C) 1995-2007 Jari Aalto
10 ;; Maintainer: Jari Aalto
12 ;; To get information on this program, call M-x tinytab-version.
13 ;; Look at the code with folding.el.
17 ;; This program is free software; you can redistribute it and/or modify it
18 ;; under the terms of the GNU General Public License as published by the Free
19 ;; Software Foundation; either version 2 of the License, or (at your option)
22 ;; This program is distributed in the hope that it will be useful, but
23 ;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 ;; You should have received a copy of the GNU General Public License
28 ;; along with program; see the file COPYING. If not, write to the
29 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
30 ;; Boston, MA 02110-1301, USA.
32 ;; Visit <http://www.gnu.org/copyleft/gpl.html> for more information
37 ;; ....................................................... &t-install ...
38 ;; Put this file on your Emacs-Lisp load path, add following into your
39 ;; ~/.emacs startup file.
43 ;; or use this; your .emacs loads up a bit quicker
45 ;; (autoload 'tinytab-mode "tinytab" "" t)
46 ;; (autoload 'tinytab-return-key-mode "tinytab" "" t)
48 ;; Suggested keybindings
50 ;; (global-set-key "\C-cT" 'tinytab-mode)
51 ;; (global-set-key [(shift tab)] 'tinytab-tab-del-key)
52 ;; (global-set-key "\C-c\C-m" 'tinytab-return-key-mode)
54 ;; For more customisation, do this:
56 ;; (add-hook 'tinytab-mode-define-keys-hook 'my-tinytab-keys)
58 ;; (defun my-tinytab-keys ()
59 ;; "My tinytab key additions, override settings."
66 ;; ..................................................... &t-commentary ...
72 ;; There was a post in gnu.emacs.sources (what an source of
73 ;; inspiration), where someone asked:
75 ;; "Is there anyway to reset the number of spaces that TAB does?
76 ;; Like, I want to make it jump four spaces instead of the
77 ;; usual whatever.How can I set the tabs to 4?"
79 ;; and the typical answer was:
81 ;; "In .emacs, set the variable tab-stop-list, like so:
82 ;; (setq tab-stop-list (list 4 8 12 ...))"
84 ;; Well, A regular user does not want to touch the original
85 ;; `tab-stop-list', because the 8 spaces per tab is the norm. But for
86 ;; programming the 4 tabs is norm, like for shell programming or for
87 ;; simple memos and text documents. The goal was to write a minor
88 ;; mode, which you can turn on and off, which handles _only_ tab key.
89 ;; This mode was supposed to be plain rigid. The tab goes where you
90 ;; want it, and you can control the amount of movement to either
91 ;; direction, back or forward.
93 ;; Overview of features
95 ;; o Programmable TAB. If you set the count to to 4,
96 ;; you can virtually program "blindly" without any other modes.
97 ;; o Selectable: 2, 4, 8 .. space indent.
98 ;; o moving commands: tab-forward, tab-backward
99 ;; o indent commands: tab indent forward, tab indent backward
100 ;; o Simple positioning of braces { } with TAB key.
104 ;; o Special auto-indent function offered for return key.
105 ;; Switch it on, and you can continue your shell, awk, SQL, C++,
106 ;; Perl comments and more.
107 ;; o C-c TAB enters interactive indentation mode where
108 ;; keys "qw" "as" abd "zx" control the amount of indentation.
110 ;; What this package does?
112 ;; Mimic `tab-stop-list' with minor mode if some analogy can be
113 ;; drawn. You only set one variable, that controls the amount of
114 ;; movement, whereas you would have to put many values inside
115 ;; `tab-stop-list'. The variable to control tab widths is:
117 ;; tinytab-:width-table
119 ;; When the mode is off, the tab key behaves as the mode thinks
120 ;; it should behave. The tab step forward and backward keys
121 ;; respect `tinytab-:width'. Normally the current position
122 ;; in the line is advanced, but if you select a region, all the
123 ;; lines are indented:
129 ;; -- Supposing all of the above text was selected and TAB was pressed
135 ;; -- Select all lines and press ESC-tab (or Shift-Tab) and lines
142 ;; -- If you have to "shoot" carefully how much indentation is needed,
143 ;; -- select region and call C-c TAB
145 ;; This text here Use keys q - w (un/indent by 1)
146 ;; More text Here a - s (un/indent by 2)
147 ;; And so on. z - x (un/indent by 4)
149 ;; To change permanently current tab division, use function
150 ;; `tinytab-change-tab-width' which steps through list
151 ;; `tinytab-:width-table'; tab factors 2, 4, and 8.
153 ;; Major modes and this minor mode
155 ;; When you use some programming mode, say C++ mode, it usually
156 ;; provides function to indent the line right with tab key.
157 ;; If you then turn on this mode, you loose the mode specific
158 ;; indenting, because turning on minor mode overrides the underlying
159 ;; major mode bindings. However this package co-operates with
160 ;; major modes so that it preserves the original indenting style in some
161 ;; extent. In variable `tinytab-:tab-insert-hook' there is function
162 ;; `tinytab-tab-mode-control' which looks at variable
164 ;; tinytab-:mode-table
166 ;; If the mode is listed in the table _and_ current point is at the
167 ;; *beginning* of line, then the line is handled by original major mode
168 ;; and not by this minor mode.
170 ;; However, this minor mode is normally meant to be used as turn
171 ;; on/off basis in such programming modes that indent lines when you
172 ;; pressing tab key. Current compatibility function
173 ;; `tinytab-tab-mode-control' only allows you to get some flexibility
174 ;; when this mode is temporarily on. Bind this mode to some fast key
175 ;; which you can use to toggle this mode on/off when you need tab for
176 ;; a moment in programming modes.
178 ;; (global-set-key "\C-cT" 'tinytab-mode)
180 ;; If you don't want any support to major modes, put following
181 ;; into your $HOME/.emacs
183 ;; (setq tinytab-:mode-table nil)
185 ;; Return key addition
187 ;; This package also includes a little function
188 ;; `tinytab-return-key-mode' which will keep the line's indentation.
189 ;; You can bind it to key C-c RET:
191 ;; (global-set-key "\C-c\C-m" 'tinytab-return-key-mode)
193 ;; When the function is active, you can continue indenting from
194 ;; the current position, like this:
196 ;; // Comment here. Call C-c C-m...and press RET
197 ;; // And it automatically indents here.
201 ;; tinytab-:auto-indent-regexp
203 ;; what line prefixes are "copied" along with the indented spaces.
213 ;; (require 'tinylibm)
218 (defvar tinytab-:version-id
219 "$Id: tinytab.el,v 2.61 2007/05/06 23:15:20 jaalto Exp $")
224 ;;;###autoload (autoload 'tinytab-mode "tinytab" "" t)
225 ;;;###autoload (autoload 'turn-on-tinytab-mode "tinytab" "" t)
226 ;;;###autoload (autoload 'turn-off-tinytab-mode "tinytab" "" t)
227 ;;;###autoload (autoload 'tinytab-commentary "tinytab" "" t)
228 ;;;###autoload (autoload 'tinytab-version "tinytab" "" t)
232 (ti::macrof-minor-mode-wizard
234 " " ;; This used to be " +" to indicate "Plussed tab"
238 "tinytab-:" ;parameters 1-6
240 "Tab movement minor mode. Adjustable movement step.
241 If you're running non/windowed version, Try to figure out which key
242 combinations work there best, In X, you have more flexible bindings.
244 If region is active, the indentation (backward or forward) is
245 applied to whole region.
253 \\{tinytab-:mode-map}
259 (tinytab-set-mode-name)))
262 tinytab-:mode-easymenu-name
263 ["Insert" tinytab-tab-key t]
264 ["Delete" tinytab-tab-del-key t]
265 ["Indent region forward" tinytab-indent-by-tab-width t]
266 ["Indent region backward" tinytab-indent-by-tab-width-back t]
267 ["Indent region dynamically" tinytab-indent-region-dynamically t]
268 ["Forward" tinytab-tab-forward t]
269 ["Backward" tinytab-tab-backward t]
270 ["Change step factor" tinytab-change-tab-width t]
271 ["Return-key indent mode" tinytab-return-key-mode t]
273 ["Package version" tinytab-version t]
274 ["Package commentary" tinytab-commentary t]
275 ["Mode help" tinytab-mode-help t]
276 ["Mode off" turn-off-tinytab-mode t])
278 ;; ... ... ... ... ... ... ... ... ... ... ... ... ... non-X keys . .
279 (define-key root-map "\t" 'tinytab-tab-key)
280 (define-key root-map "\e\t" 'tinytab-tab-del-key)
281 (define-key root-map "\C-c\t" 'tinytab-indent-region-dynamically)
282 (define-key root-map "\C-c\C-m" 'tinytab-return-key-mode)
283 ;; ........................................................ X-keys ...
285 (define-key root-map (kbd "<S-tab>") 'tinytab-tab-del-key)
287 (define-key root-map [(shift backtab)] 'tinytab-tab-del-key)
288 (define-key root-map [(shift hpBackTab)] 'tinytab-tab-del-key) ;; XEmacs
289 (define-key root-map [(shift kp-tab)] 'tinytab-tab-del-key)
290 (define-key root-map [(shift iso-lefttab)] 'tinytab-tab-del-key))))
295 (defcustom tinytab-:load-hook nil
296 "*Hook that is run when package is loaded."
300 (add-hook 'tinytab-:load-hook 'tinytab-install-mode)
302 (defcustom tinytab-:tab-insert-hook
303 '(tinytab-tab-mode-control
304 tinytab-tab-brace-control
305 tinytab-tab-forward-insert
307 "*List of functions to call for inserting logical TAB.
308 If any of these functions return non-nil, it is assumed,
309 that the tab key was handled."
313 (defcustom tinytab-:tab-delete-hook
314 '(tinytab-tab-backward-del
315 tinytab-bol-forward-del)
316 "*List of functions to delete a logical TAB backward.
317 If any of these functions return non-nil, it is assumed,
318 that the tab handling was performed."
323 ;;{{{ setup: public, user configurable
325 ;; Simple name is enough. Think this as "Tab +" or "extended tab" -mode
327 (defcustom tinytab-:mode-name-base " +"
328 "*Minor mode's base name. Default value is ` +'."
332 ;; If I accidentally press key I didn't meant to, I want to know
333 ;; about it. Like in empty line, where is no visual aids
335 (defcustom tinytab-:verbose nil
336 "*Enable verbose messages."
340 (defcustom tinytab-:width-table '(2 4 8)
341 "*After call to \\[tinytab-change-tab-width], cycle through list of tab positions.
342 Default values are '(2 4 8)"
343 :type '(repeat integer)
346 (defcustom tinytab-:mode-table
347 '(c++-mode cc-mode c-mode perl-mode cperl-mode java-mode)
348 "*List of mode name symbols where the TAB key calls mode's TAB function.
349 But, only if the point is at the beginning of line."
350 :type '(repeat (symbol
351 :tag "Mode name symbols"))
354 (defcustom tinytab-:indent-region-key-message
355 "Dynamic Indent <>: [qw]=1 [as]=2 [zx]=4 [Esc]=exit"
356 "*Message displayed while in dynamic indent mode.
357 If you change this, see also `tinytab-:indent-region-key-list'."
361 (defcustom tinytab-:indent-region-key-list
366 "*List of keys to control dynamic indenting. Not case sensitive.
367 The first 6 keys go in pairs.
369 elt 0 1 left and right by 1
370 elt 2 3 left and right by 2
371 elt 4 5 left and right by 4
374 If you chnage this variable, change also
375 `tinytab-:indent-region-key-message'."
383 (defcustom tinytab-:auto-indent-regexp "[#!;*/]\\|REM\\|//"
384 "*If previous line match this regexp, it is copied when you hit RET.
385 This allows e.g. continuing C++'s // comments.
386 See function `tinytab-return-key-mode' to turn on this auto-indent feature."
393 (defvar tinytab-:width 4
394 "Current tab division.")
397 ;;{{{ extra functions
399 ;;; ----------------------------------------------------------------------
401 (defsubst tinytab-activate-region (beg end)
402 "Activate region which was previously selected.")
405 ;;; ----------------------------------------------------------------------
407 (defmacro tinytab-message (&rest body)
408 "Run BODY if `tinytab-:verbose' is non nil."
410 (when tinytab-:verbose
411 (message (,@ body)))))
413 ;;; ----------------------------------------------------------------------
415 (defsubst tinytab-region-bounds (&optional beg end)
416 "Set variables BEG and END if region is active.
417 Otherwise use current line's end points."
421 (if (and (region-active-p)
422 ;; Must be active too, otherwise may cause suprises to indent
423 ;; many lines in the buffer
425 (list (region-beginning)
427 ;; Interactive call. Single line
430 ;;; ----------------------------------------------------------------------
432 (defsubst tinytab-width ()
433 "Return TAB advance."
434 (if (not (integerp tinytab-:width))
435 (setq tinytab-:width 4))
438 ;;; ----------------------------------------------------------------------
440 (defun tinytab-indent-by-tab-width (&optional beg end back)
441 "Indent region BEG END by current tab division.
442 Optional BACK indents backward. If BEG is nil and region is active,
443 determine BEG and END."
444 ;; (interactive "*r")
445 (let* ((width (tinytab-width))
449 (multiple-value-bind (b e)
450 (tinytab-region-bounds beg end)
452 (tinytab-tab-forward-insert)
453 ;; This deactivates region, keep it on
454 (indent-rigidly b e div)
455 (tinytab-activate-region b e)))))
457 ;;; ----------------------------------------------------------------------
458 ;;; - So that you can bind this to fast key
460 (defun tinytab-indent-by-tab-width-back (&optional beg end)
461 "Just shortcut to `tinytab-indent-by-tab-width'. Indent BEG END backward.
462 If BEG and END are nil, indent current line. (interactive call on current line)
463 If region is active, use that. (interactive + region selected)."
465 (multiple-value-bind (b e)
466 (tinytab-region-bounds beg end)
467 (tinytab-indent-by-tab-width b e 'back)))
469 ;;; ----------------------------------------------------------------------
471 (defun tinytab-bol-forward-del ()
472 "If at beginning of line, delete `tinytab-:width' spaces to the right."
475 ;; They may be \t, so convert all to spaces first and
476 ;; then we know if we can delete enough spcaes.
477 (let* ((line (buffer-substring (line-beginning-position)
478 (line-end-position)))
479 (width (tinytab-width))
483 ;; Only convert from the start, not whole line
484 (untabify (point-min) (min
485 (+ (point-min) width)
487 (goto-char (point-min))
491 (make-string width ?\ )))
493 (buffer-substring (point) (point-max)))))))
496 (delete-region (point) (line-end-position))
500 (message "TinyTab: Cannot delete %d spaces" width))))))
502 ;;; ----------------------------------------------------------------------
504 (defun tinytab-tab-mode-control ()
505 "If `mode-name' in in the list `tinytab-:mode-table', call mode's tab key.
507 o point is at the beginning of line.
510 This way you can partly mix e.g. C++ mode and this minor mode."
512 (let* ((sym (intern (format "%s-map" (symbol-name major-mode))))
516 ;; If we're at the beginnning of line, see if there is keymap for
517 ;; this current mode. Then try to find function for "\t" key
520 (when (and (or (bolp)
523 (looking-at "^[ \t]+$")))
524 (memq major-mode tinytab-:mode-table)
526 (keymapp (setq map (eval sym)))
527 (setq func (lookup-key map "\t")))
528 (call-interactively func)
529 (if (eq (point) point)
530 ;; Not moved? Then continue calling other functions.
534 ;;; ----------------------------------------------------------------------
535 ;;; - For a little more smarter TAB key to line up { } braces
536 ;;; in variaous programming modes I made this. It's simple,
537 ;;; but suffices for most common needs.
538 ;;; - I don't know how the C-mode or cc-mode does this, but, hey,
539 ;;; this is one way :-)
542 (defun tinytab-tab-brace-control ()
543 "When hitting TAB, line up {} braces, otherwise do nothing special.
544 Remember that opening brace, the {, follows previous line's indentation
545 and } follows the \"{\".
549 t ,if TAB handled in this function.
560 ;; ... ... ... ... ... ... ... ... ... ... ... ... ... check brace ...
563 ;; ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... { . .
565 ((looking-at "^\\([ \t]*\\)\\({.*\\)")
566 (setq indent (or (match-string 1) "")
567 rest (match-string 2)
570 (forward-line -1) ; peek previous line indent
571 (let ((line (buffer-substring (line-beginning-position)
572 (line-end-position))))
573 (setq pindent (if (string-match "^[ \t]+" line)
574 (match-string 1 line)
576 ;; ... ... ... ... ... ... ... ... ... ... ... ... ... ... .. } ..
577 ((looking-at "^\\([ \t]*\\)\\(}.*\\)")
578 (setq indent (or (match-string 1) "")
579 rest (match-string 2)
583 ((re-search-backward "^\\([ \t]*\\){" nil t)
584 (setq pindent (or (match-string 1) ""))))))))
585 ;; ... ... ... ... ... ... ... ... ... ... ... ... .. adjust brace ...
586 (setq equal (and indent pindent (string= indent pindent))
587 col (and indent (length (subst-char-with-string indent))))
593 (< (current-column) col))
594 ;; Pressing TAB, before the {, puts cursor to brace.
599 (not (string= indent pindent)))
600 ;; This is reindent case: { and } didn't line up.
601 (setq line (concat pindent rest)
604 (setq col (current-column))
605 (delete-region (line-beginning-position) (line-end-position))
607 ;; If user is in the LEFT side of brace, put cursor to brace
608 ;; If user if in the RIGHT side, then move-to-column will
609 ;; preserve position.
612 (when (< col (length (subst-char-with-string pindent)))
613 (re-search-forward "{\\|}")
618 ;;{{{ code: return key
620 ;;; ----------------------------------------------------------------------
621 ;;; Replaces the RET key
622 ;;; The arg is just due to: (newline &optional ARG1)
624 (defun tinytab-auto-indent (&optional arg)
625 "Automatically indent according to previous line.
626 If optional ARG is given, behave exactly like 'newline' function."
628 ;; The RE matches few common comments and empty whitespaces
632 ;; ! = .Xdefaults comments
634 ;; REM = oracle SQL comments
636 (let ((re (concat "^[ \t]*\\(" tinytab-:auto-indent-regexp "\\)*[ \t]*"))
639 (arg ;; We do not do anything special if user has given arg.
641 ((not (eolp)) ;; Now let's see if user wanted fresh line
642 ;; User wanted to divide a line.
643 ;; Read the line up till cursor point
644 (if (> (current-column) 0)
645 (setq str (buffer-substring (line-beginning-position) (point))))
646 ;; Ignore portion match --> nothing important matched
648 (not (and (string-match re str)
650 ;; The position (column in string)
652 (newline) ;something else than re, break line
653 (let ((left-margin 0)) ;Can't add string right otherwise
657 ;; ... ... ... ... ... ... ... ... ... ... ... ... ... .. else ...
658 ;; Let's peek current line
659 (if (> (current-column) 0)
662 (setq str (if (looking-at re)
664 (if (null str) ;Nothing important here
666 (let ((left-margin 0))
673 ;;; ----------------------------------------------------------------------
675 (defun tinytab-set-mode-name ()
676 "Set mode name according to tab count in effect."
678 (let* ((base tinytab-:mode-name-base)
679 (val (tinytab-width)))
680 (setq tinytab-:mode-name (format "%s%d" (or base "") val))
681 (if (fboundp 'force-mode-line-update)
682 (force-mode-line-update))))
684 ;;; ----------------------------------------------------------------------
686 (defun tinytab-change-tab-width ()
687 "Toggle tab width according to `tinytab-:width-table'."
689 (let* ((verb (interactive-p))
690 (val (tinytab-width))
691 (table tinytab-:width-table)
694 ((not (integerp val))
695 (setq val (car table))) ;default value
696 ((setq elt (memq val table))
697 (if (eq 1 (length elt)) ;it's last item
698 (setq val (car table)) ;pick first value
699 (setq val (nth 1 elt)))) ;get next in the list
701 (t ;can't find value from table ?
702 (setq val (car table)))) ;get first then.
703 (setq tinytab-:width val) ;update
704 (tinytab-set-mode-name)
705 (if verb ;this does no harm....
706 (message "TinyTab: Tab factor is now %d" val))))
708 ;;; ----------------------------------------------------------------------
710 (defun tinytab-tab-backward-del ()
712 Delete whitespace if all characters preceding the point are white spaces
713 _and_ the final position is in divide-able by current div-factor.
715 Eg. If you factor is 4, and there is 2 spaces before your cursor \"*\",
716 This function will not delete the extra spaces, because it can't reach
723 In this case, calling the function is no-op.
727 `tinytab-:tab-delete-hook'
730 (let* ((div (tinytab-width))
731 (col (current-column))
732 (dest (- col (% col div)))
738 (setq MARK (save-excursion
741 (forward-char 1)) ;push marker one forward
743 (if (= col dest ) ; would be exact
744 (setq dest (- col div )))
747 (if (= col 0) ;beg of line
749 (move-to-column dest t) ;converts tabs to spaces.
750 ;; consider following:
752 ;; 12345678 123456789
753 ;; ----------------------------------
754 ;; #\thello "# hello" ,suppose cursor is in "h"
759 ;; Now you indent back by 4, this is what happens
766 ;; The tab is converted and it caused all point to be altered.
767 ;; That's why we have to use the marker, because it stays
768 ;; releative to text, in this case just _behind_ the letter "h"
771 (marker-position MARK)
772 (1- (marker-position MARK))))
774 (setq str (buffer-substring p2 p))
775 (if (not (string-match "^[ \t]+$" str))
777 (tinytab-message "TinyTab: Can't reach previous tab position")
778 (goto-char p)) ;do not move. Stay put.
780 (tinytab-message "Tinytab: Deleted")))
781 (setq MARK nil))) ;kill the marker
783 ;;; ----------------------------------------------------------------------
785 (defun tinytab-tab-backward ()
786 "Logical tab movement backward, until reach beginning of line."
788 (let* ((div (tinytab-width))
789 (dest (- (current-column) div)))
792 (move-to-column dest t)
793 (if (looking-at "[ \t]+$")
794 (tinytab-message "TinyTab: Moved."))))
796 ;;; ----------------------------------------------------------------------
798 (defun tinytab-tab-forward-insert ()
799 "Move tab forward, insert spaces or tabs, see variable `indent-tabs-mode'.
805 (let* ((col (current-column))
806 (div (tinytab-width))
807 (nbr (- div (% col div)))
813 (setq str (make-string div ?\ ))
814 (setq str (make-string nbr ?\ )))
816 (when indent-tabs-mode
817 ;; - When we insert non-tabs, like in mode "tab 4", what happens is
818 ;; that we insert " " + " " ie. 4 + 4 spaces.
819 ;; - but, we really like them to be like one "\t" code in text,
820 ;; So, let's fix the line every time something is inserted.
821 ;; - We have to use markers again due to tabify.
822 ;; - The EOB is special case
824 (setq MARK (save-excursion
829 (tabify (line-beginning-position) (point))
832 (1- (marker-position MARK))))
834 (setq MARK nil)) ;kill it
837 ;;; ----------------------------------------------------------------------
839 (defun tinytab-tab-forward ()
840 "Step logical tab forward. Does not insert anything. Stops at EOL.
841 Tabs are converted to spaces when needed; because you can't step inside
842 '\t' character in the line otherwise.."
844 (let* ((div (tinytab-width))
845 (col (current-column))
846 (nbr (- div (% col div)))
847 (ecol (save-excursion (end-of-line) (current-column)))
852 (tinytab-message "End of line."))
854 (move-to-column dest t)
855 (if (looking-at "[ \t]+$")
856 (tinytab-message "Tinytab: Moved."))))))
858 ;;; ----------------------------------------------------------------------
860 (defun tinytab-tab-key-insert ()
861 "Run all functions in `tinytab-:tab-insert-hook' until success."
862 ;; We could use this instead:
864 ;; (run-hook-with-args-until-success 'tinytab-:tab-insert-hook)
866 ;; But then it would not be possible to debug which function gets
868 (dolist (function tinytab-:tab-insert-hook)
869 (when (funcall function)
870 (tinytab-message "TinyTab: %s" (symbol-name function))
873 ;;; ----------------------------------------------------------------------
876 (defun tinytab-tab-key (&optional beg end)
877 "Run list of function to handle TAB key. See variable `tinytab-:tab-insert-hook'.
878 If region is active and BEG and END are nil, then call function
879 `tinytab-indent-by-tab-width'."
884 (tinytab-indent-by-tab-width))
886 ;; Integrate this function with tinymail.el tab-key.
887 (let* ((sym 'tinymail-:complete-key-hook)
888 (tinymail-:complete-key-hook (if (boundp sym)
889 (symbol-value sym))))
890 ;; No-op: byte compiler silencer
891 (if (null tinymail-:complete-key-hook)
892 (setq tinymail-:complete-key-hook nil))
893 (remove-hook sym 'tinymail-complete-guest-packages)
894 ;; keep this at the end
895 (when (memq 'tab-to-tab-stop tinytab-:tab-insert-hook)
896 (remove-hook 'tinytab-:tab-insert-hook 'tab-to-tab-stop)
897 (add-hook 'tinytab-:tab-insert-hook 'tab-to-tab-stop 'append))
898 (tinytab-tab-key-insert)))))
900 ;;; ----------------------------------------------------------------------
903 (defun tinytab-tab-del-key (&optional beg end)
904 "Remove indentation. See variable `tinytab-:tab-delete-hook'.
905 If region is active, indent all lines backward."
908 ((and (region-active-p)
910 (tinytab-indent-by-tab-width-back)
911 (tinytab-activate-region beg end))
913 (run-hook-with-args-until-success 'tinytab-:tab-delete-hook))))
915 ;;; ----------------------------------------------------------------------
918 (defun turn-on-tinytab-return-key-mode ()
919 "Turn on auto indent after RET key."
920 (tinytab-return-key-mode 1 (interactive-p)))
922 ;;; ----------------------------------------------------------------------
925 (defun turn-off-tinytab-return-key-mode ()
926 "Turn on auto indent after RET key."
927 (tinytab-return-key-mode 1 (interactive-p)))
929 ;;; ----------------------------------------------------------------------
932 (defun tinytab-return-key-mode (&optional mode verb)
933 "Toggle auto indent MODE / regular newline mode. VERB."
935 (let* ((func 'tinytab-auto-indent)
938 ;; e.g. in fundamental-map this value is nil and
939 ;; nil cannot be used as an keymap for lookup-key
942 (lookup-key (current-local-map) "\C-m"))
943 (lookup-key (current-global-map) "\C-m")))
945 ;; If we redefine return key here, user will nver get out.
946 ;; C-m is exit-minibuffer.
948 (if (string-match "minibuf" (buffer-name))
949 (error "TinyTab: Return key-mode not allowed in minibuffer."))
950 (setq verb (interactive-p))
952 ((or (null mode) (not (integerp mode)))
953 (setq to (if (eq now 'tinytab-auto-indent)
960 (local-set-key "\C-m" to)
962 (message "TinyTab Return key auto indent %s"
968 ;;; ----------------------------------------------------------------------
970 (defun tinytab-indent-region-dynamically (beg end)
971 "Move region BEG END until exit key is pressed.
972 For ey setup, see `tinytab-:indent-region-key-list'. The default keys are:
980 (k tinytab-:indent-region-key-list)
981 (msg tinytab-:indent-region-key-message)
984 (if (not (eq (length k) 7))
985 (error "Not enough members in tinytab-:indent-region-key-list."))
986 (setq EXIT (nth 6 k))
987 (while (not (eq EXIT (setq ch
989 (read-char-exclusive msg)))))
1005 (indent-rigidly (region-beginning) (region-end) i)))))
1009 (add-hook 'tinytab-:mode-define-keys-hook 'tinytab-mode-define-keys)
1012 (run-hooks 'tinytab-:load-hook)
1014 ;;; tinytab.el ends here