summaryrefslogtreecommitdiffstats
path: root/emacs.d/nxhtml/util/tabkey2.el
diff options
context:
space:
mode:
Diffstat (limited to 'emacs.d/nxhtml/util/tabkey2.el')
-rw-r--r--emacs.d/nxhtml/util/tabkey2.el1701
1 files changed, 1701 insertions, 0 deletions
diff --git a/emacs.d/nxhtml/util/tabkey2.el b/emacs.d/nxhtml/util/tabkey2.el
new file mode 100644
index 0000000..d35e651
--- /dev/null
+++ b/emacs.d/nxhtml/util/tabkey2.el
@@ -0,0 +1,1701 @@
+;;; tabkey2.el --- Use second tab key pressed for what you want
+;;
+;; Author: Lennart Borgman (lennart O borgman A gmail O com)
+;; Created: 2008-03-15
+(defconst tabkey2:version "1.40")
+;; Last-Updated: 2009-07-15 Wed
+;; URL: http://www.emacswiki.org/cgi-bin/wiki/tabkey2.el
+;; Keywords:
+;; Compatibility:
+;;
+;; Features that might be required by this library:
+;;
+ ;; `appmenu', `cl'.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Commentary:
+;;
+;; The tab key is in Emacs often used for indentation. However if you
+;; press the tab key a second time and Emacs tries to do indentation
+;; again, then usually nothing exciting will happen. Then why not use
+;; second tab key in a row for something else?
+;;
+;; Commonly used completion functions in Emacs is often bound to
+;; something corresponding to Alt-Tab. Unfortunately this is unusable
+;; if you have a window manager that have an apetite for it (like that
+;; on MS Windows for example, and several on GNU/Linux).
+;;
+;; Then using the second tab key press for completion might be a good
+;; choice and perhaps also easy to remember.
+;;
+;; This little library tries to make it easy to do use the second tab
+;; press for completion. Or you can see this library as a swizz army
+;; knife for the tab key ;-)
+;;
+;; See `tabkey2-mode' for more information.
+;;
+;;
+;; This is a generalized of an idea Sebastien Rocca Serra once
+;; presented on Emacs Wiki and called "Smart Tab". (It seems like
+;; many others have also been using Tab for completion in one way or
+;; another for years.)
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Change log:
+;;
+;; Version 1.04:
+;; - Add overlay to display state after first tab.
+;;
+;; Version 1.05:
+;; - Fix remove overlay problem.
+;;
+;; Version 1.06:
+;; - Add completion function choice.
+;; - Add support for popcmp popup completion.
+;;
+;; Version 1.07:
+;; - Add informational message after first tab.
+;;
+;; Version 1.08:
+;; - Give better informational message after first tab.
+;;
+;; Version 1.09:
+;; - Put flyspell first.
+;;
+;; Version 1.09:
+;; - Give the overlay higher priority.
+;;
+;; Version 1.10:
+;; - Correct tabkey2-completion-functions.
+;; - Add double-tab for modes where tab can not be typed again.
+;; - Use better condition for when completion can be done, so that it
+;; can be done later while still on the same line.
+;; - Add a better message handling for the "Tab completion state".
+;; - Add C-g break out of the "Tab completion state".
+;; - Add faces for highlight.
+;; - Make it work in custom mode buffers.
+;; - Fix documentation for `tabkey2-first'
+;;
+;; Version 1.11:
+;; - Don't call chosen completion function directly. Instead make it
+;; default for current buffer.
+;;
+;; Version 1.12:
+;; - Simplify code.
+;; - Add help to C-f1 during "Tab completion state".
+;; - Fix documentation basics.
+;; - Add customization of state message and line marking.
+;; - Fix handling of double-Tab modes.
+;; - Make user interaction better.
+;; - Handle read-only in custom buffers better.
+;; - Add more flexible check for if completion function is active.
+;; - Support predictive mode.
+;; - Reorder and simplify.
+;;
+;; Version 1.13:
+;; - Add org-mode to the double-tab gang.
+;; - Make it possible to use double-tab in normal buffers.
+;; - Add cycling through completion functions to S-tab.
+;;
+;; Version 1.14:
+;; - Fix bug in handling of read-only.
+;; - Show completion binding in help message.
+;; - Add binding to make current choice buffer local when cycling.
+;;
+;; Version 1.15:
+;; - Fix problem at buffer end.
+;; - Add S-tab to enter completion state without indentation.
+;; - Add backtab bindings too for this.
+;; - Remove double-tab, S-tab is better.
+;; - Add list of modes that uses more tabs.
+;; - Add list of modes that uses tab only for completion.
+;; - Move first overlay when indentation changes.
+;; - Make mark at line beginning 1 char long.
+;;
+;; Version 1.16:
+;; - Don't call tab function when alternate key is pressed.
+;;
+;; Version 1.17:
+;; - Let alternate key cycle completion functions instead of complete.
+;; - Bind backtab.
+;; - Fix bug when only one completion funciton was available.
+;; - Fix bug when alt key and major without fix indent.
+;;
+;; Version 1.18:
+;; - Add popup style messages.
+;; - Add delay to first message.
+;; - Use different face for indicator on line and message.
+;; - Use different face for echo area and popup messages.
+;; - Add anything to completion functions.
+;; - Put help funciton on f1.
+;; - Always bind alternate key to cycle.
+;; - Change defcustoms to simplify (excuse me).
+;; - Work around end of buffer problems.
+;; - Work around start of buffer problems.
+;; - Assure popup messages are visible.
+;; - Reorder code in more logical order.
+;;
+;; Version 1.19:
+;; - Make overlay keymap end advance.
+;; - Remove overlay keymap parent.
+;;
+;; Version 1.20:
+;; - Fix bug on emtpy line.
+;; - Fix some text problems.
+;; - Make f1 c/k work in tab completion state.
+;;
+;; Version 1.20:
+;; - Fixed bug in overlay removal.
+;;
+;; Version 1.21:
+;; - Fixed bug in minibuffer setup.
+;;
+;; Version 1.22:
+;; - Honour widget-forward, button-forward.
+;;
+;; Version 1.23:
+;; - Remove binding of shift tab.
+;; - Check if use-region-p is defined.
+;;
+;; Version 1.24:
+;; - Add option for completion state mode line marker.
+;; - Fix bug in tabkey2-show-completion-functions.
+;; - Move off completion point cancels completion state.
+;; - Fix bugs in help.
+;; - Try to fix some problems with invisible text, at least in
+;; org-mode.
+;; - Restore window config, completions often leaves without.
+;;
+;; Version 1.25:
+;; - Fix bug in tabkey2-completion-state-p.
+;;
+;; Version 1.26:
+;; - Make tabkey2-mode a buffer local mode.
+;; - Add tabkey2-global-mode.
+;; - Fix some bugs.
+;;
+;; Version 1.27:
+;; - Fix some bugs in customization.
+;;
+;; Version 1.28:
+;; - Use invisible-p.
+;;
+;; Version 1.29:
+;; - Remove tabkey2-global-mode because of problem with minibuffers.
+;;
+;; Version 1.30:
+;; - Add Semantic's smart completion to completion functions.
+;; (Thanks Eric.)
+;;
+;; Version 1.31:
+;; - Add yasnippet and pabbrev completion functions. (Thanks Eric.)
+;; - Reorder completion functions.
+;;
+;; Version 1.32:
+;; - Add support for pcomplete.
+;; - Inform about other key bindings in completion functions list.
+;; - Remove no longer used "preferred" from completion functions list.
+;;
+;; Version 1.33:
+;; -- Automatically select next function on completion failure.
+;; -- Add completion functions reset functions.
+;;
+;; Version 1.34:
+;; - Set this-command on call-interactively.
+;; - Avoid setting last-command.
+;;
+;; Version 1.35:
+;; - Do not complete in or nearby mumamo chunk borders.
+;; - Finish completion mode unless last command was a tabkey2 command.
+;; - Finish when there are no more active completion functions.
+;;
+;; Version 1.36:
+;; - Actually check if completion function is a defined command.
+;; - Integrate better with YASnippet.
+;; - Give YASnippet higher priority since that seems what is wanted.
+;;
+;; Version 1.37:
+;; - Fix bug revealed by 1.36 changes.
+;;
+;; Version 1.38:
+;; - Fix typo in completion function list.
+;; - Fix corresponding part of check if function is active.
+;;
+;; Version 1.39:
+;; - Try first [tab] and then [?\t] when looking for command.
+;;
+;; Version 1.40:
+;; - Added Company Mode completion.
+;;
+;; Fix-me: maybe add \\_>> option to behave like smart-tab. But this
+;; will only works for modes that does not do completion of empty
+;; words (like in smart-tab).
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Known bugs
+;;
+;; - Maybe problems with comint shell.
+;; - Does not check visibility very carefully.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; 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., 51 Franklin Street, Fifth
+;; Floor, Boston, MA 02110-1301, USA.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(eval-when-compile (require 'appmenu nil t))
+(eval-when-compile (require 'mumamo nil t))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; Custom
+
+;;;###autoload
+(defgroup tabkey2 nil
+ "Customization of second tab key press."
+ :group 'nxhtml
+ :group 'convenience)
+
+(defface tabkey2-highlight-line
+ '((t :inherit highlight))
+ "Face for marker on line when default function is active."
+ :group 'tabkey2)
+
+(defface tabkey2-highlight-line2
+ '((t :inherit isearch-fail))
+ "Face for marker on line when non-default function is active."
+ :group 'tabkey2)
+
+(defface tabkey2-highlight-message
+ '((t :inherit tabkey2-highlight-line))
+ "Face for messages in echo area."
+ :group 'tabkey2)
+
+(defface tabkey2-highlight-popup
+ '((default :box t :inherit tabkey2-highlight-message)
+ (((class color) (background light)) :foreground "black")
+ (((class color) (background dark)) :foreground "yellow"))
+ "Face for popup messages."
+ :group 'tabkey2)
+
+(defcustom tabkey2-show-mark-on-active-line t
+ "Show mark on active line if non-nil.
+This mark is shown during 'Tab completion state'."
+ :type 'boolean
+ :group 'tabkey2)
+
+(defvar tabkey2-completion-lighter nil)
+(defcustom tabkey2-completion-lighter-on nil
+ "Mode line lighter for function `tabkey2-completion-state-mode'."
+ :type 'boolean
+ :set (lambda (symbol value)
+ (set-default symbol value)
+ (setq tabkey2-completion-lighter (if value " Tab2" nil))
+ (setq minor-mode-alist
+ (assq-delete-all 'tabkey2-completion-state-mode
+ minor-mode-alist)))
+ :group 'tabkey2)
+
+(defcustom tabkey2-show-message-on-enter 2.0
+ "If non-nil show message when entering 'Tab completion state'.
+If value is a number then delay message that number of seconds."
+ :type '(choice (const :tag "Don't show" nil)
+ (const :tag "Show at once" t)
+ (float :tag "Show, but delayed (seconds)"))
+ :group 'tabkey2)
+
+
+;; (setq tabkey2-message-style 'popup)
+;; (setq tabkey2-message-style 'echo-area)
+(defcustom tabkey2-message-style 'popup
+ "How to show messages."
+ :type '(choice (const :tag "Popup" popup)
+ (const :tag "Echo area" echo-area))
+ :group 'tabkey2)
+
+(defcustom tabkey2-in-minibuffer nil
+ "If non-nil use command `tabkey2-mode' also in minibuffer."
+ :type 'boolean
+ :group 'tabkey2)
+
+(defcustom tabkey2-in-appmenu t
+ "Show a completion menu in command `appmenu-mode' if t."
+ :type 'boolean
+ :set (lambda (sym val)
+ (set-default sym val)
+ (when (fboundp 'appmenu-add)
+ (if val
+ (appmenu-add 'tabkey2 nil t "Completion" 'tabkey2-appmenu)
+ (appmenu-remove 'tabkey2))))
+ :group 'tabkey2)
+
+(defun yas/expandable-at-point ()
+ "Return non-nil if a snippet can be expanded here."
+ (when (and (fboundp 'yas/template-condition-predicate)
+ (boundp 'yas/buffer-local-condition))
+ (yas/template-condition-predicate
+ yas/buffer-local-condition)))
+
+(defvar tabkey2-company-backends
+ "List of frontends and their backends."
+ '((company-mode (NONE company-abbrev . "Abbrev")
+ (NONE company-css . "CSS")
+ (dabbrev-expan company-dabbrev . "dabbrev for plain text")
+ (NONE company-dabbrev-code . "dabbrev for code")
+ (NONE company-eclim . "eclim (an Eclipse interace)")
+ (lisp-symbol-complete company-elisp . "Emacs Lisp")
+ (complete-tag company-etags . "etags")
+ (NONE company-files . "Files")
+ (NONE company-gtags . "GNU Global")
+ (ispell-complete-word company-ispell . "ispell")
+ (flyspell-correct-word-before-point company-ispell . "ispell")
+ (NONE company-keywords . "Programming language keywords")
+ (nxml-complete company-nxml . "nxml")
+ (NONE company-oddmuse . "Oddmuse")
+ (NONE company-pysmell . "PySmell")
+ (NONE company-ropemacs . "ropemacs")
+ (senator-complete-symbol company-semantic . "CEDET Semantic")
+ (NONE company-tempo . "Tempo templates")
+ (NONE company-xcode . "Xcode"))))
+
+(defun tabkey2-find-front-end (fun)
+ (let ((
+ ))))
+
+(defcustom tabkey2-completion-functions
+ '(
+ ;; Front ends (should take care of the rest, ie temporary things,
+ ;; snippets etc...)
+ ("Company Mode completion" company-complete company-mode)
+ ;; Temporary things
+ ("Spell check word" flyspell-correct-word-before-point)
+ ;; Snippets
+ ("Yasnippet" yas/expand (yas/expandable-at-point))
+ ;; Main mode related, often used
+ ("Semantic Smart Completion" senator-complete-symbol senator-minor-mode)
+ ("Programmable completion" pcomplete)
+ ("nXML completion" nxml-complete)
+ ("Complete Emacs symbol" lisp-complete-symbol)
+ ("Widget complete" widget-complete)
+ ("Comint Dynamic Complete" comint-dynamic-complete)
+ ("PHP completion" php-complete-function)
+ ("Tags completion" complete-tag)
+ ;; General word completion
+ ("Predictive word" complete-word-at-point predictive-mode)
+ ("Predictive abbreviations" pabbrev-expand-maybe)
+ ("Dynamic word expansion" dabbrev-expand nil (setq dabbrev--last-abbrev-location nil))
+ ("Ispell complete word" ispell-complete-word)
+ ;; The catch all
+ ("Anything" anything (commandp 'anything))
+ )
+ "List of completion functions.
+The first 'active' entry in this list is normally used during the
+'Tab completion state' by `tabkey2-complete'. An entry in the
+list should have either of this forms
+
+ \(TITLE COMPLETION-FUNCTION ACTIVE-FORM RESET-FORM)
+
+TITLE to show in menus etc.
+
+COMPLETION-FUNCTION is the completion function symbol.
+
+The entry is considered active if the symbol COMPLETION-FUNCTION
+is bound to a command and
+
+ - This function has a key binding at point.
+
+or
+
+ - The elisp expression ACTIVE-FORM evaluates to non-nil. If it
+ is a single symbol then its variable value is used, otherwise
+ the elisp form is evaled.
+
+RESET-FORM is used to reset the completion function before
+calling it.
+
+When choosing with `tabkey2-cycle-completion-functions'
+only the currently active entry in this list are shown."
+ :type '(repeat (list string (choice (command :tag "Currently known command")
+ (symbol :tag "Command not known yet"))
+ (choice (const :tag "Active only if it has a key binding at point" nil)
+ (sexp :tag "Elisp, if evals to non-nil then active"))
+ (sexp :tag "Elisp, reset completion function")))
+ :group 'tabkey2)
+
+;; Use emulation mode map for first Tab key
+(defconst tabkey2-mode-emul-map (make-sparse-keymap)
+ "This keymap just binds tab and alternate key all the time.
+By default this binds Tab to `tabkey2-first'. The actual keys
+bound are in `tabkey2-first-key' and `tabkey2-alternate-key'.")
+
+(defvar tabkey2--emul-keymap-alist nil)
+
+;; (setq tabkey2-keymap-overlay nil)
+(defconst tabkey2-completion-state-emul-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [(control ?c) tab] 'tabkey2-make-current-default)
+
+ ;;(define-key map tabkey2-alternate-key 'tabkey2-cycle-completion-functions)
+ (define-key map [backtab] 'tabkey2-cycle-completion-functions)
+
+ (define-key map [(control f1)] 'tabkey2-completion-function-help)
+ (define-key map [(meta f1)] 'tabkey2-show-completion-functions)
+ (define-key map [f1] 'tabkey2-completion-state-help)
+
+ (define-key map [(control ?g)] 'tabkey2-completion-state-off)
+ (define-key map [tab] 'tabkey2-complete)
+ map)
+ "This keymap is for `tabkey2-keymap-overlay'.")
+
+(defun tabkey2-bind-keys (first-key alternate-key)
+ (let ((mode-map tabkey2-mode-emul-map)
+ (comp-map tabkey2-completion-state-emul-map))
+ ;; First key
+ (when (and (boundp 'tabkey2-first-key)
+ tabkey2-first-key)
+ (define-key mode-map tabkey2-first-key nil))
+ (when first-key
+ (define-key mode-map first-key 'tabkey2-first))
+ ;; Alternate key
+ (when (and (boundp 'tabkey2-alternate-key)
+ tabkey2-alternate-key)
+ (define-key mode-map tabkey2-alternate-key nil)
+ (define-key comp-map tabkey2-alternate-key nil))
+ (when alternate-key
+ (define-key mode-map alternate-key 'tabkey2-cycle-completion-functions)
+ (define-key comp-map alternate-key 'tabkey2-cycle-completion-functions))
+ (when (and (boundp 'tabkey2-completion-state-mode)
+ tabkey2-completion-state-mode)
+ (tabkey2-completion-state-mode -1)
+ (tabkey2-completion-state-mode 1))))
+
+(defcustom tabkey2-first-key [tab]
+ "First key, first time indents, more invocations completes.
+This key is always bound to `tabkey2-first'."
+ :set (lambda (sym val)
+ (set-default sym val)
+ (tabkey2-bind-keys
+ val
+ (when (boundp 'tabkey2-alternate-key)
+ tabkey2-alternate-key)))
+ :type 'key-sequence
+ :group 'tabkey2)
+
+(defcustom tabkey2-alternate-key [f8]
+ "Alternate key, bound to cycle and show completion functions.
+This key is always bound to `tabkey2-cycle-completion-functions'."
+ :set (lambda (sym val)
+ (set-default sym val)
+ (tabkey2-bind-keys (when (boundp 'tabkey2-first-key) tabkey2-first-key) val))
+ :type 'key-sequence
+ :group 'tabkey2)
+
+(tabkey2-bind-keys tabkey2-first-key tabkey2-alternate-key)
+
+;;;###autoload
+(define-minor-mode tabkey2-mode
+ "More fun with Tab key number two (completion etc).
+This global minor mode by default binds Tab in a way that let you
+do completion with Tab in all buffers \(where it is possible).
+
+The Tab key is easy to type on your keyboard. Then why not use
+it for completion, something that is very useful? Shells usually
+use Tab for completion so many are used to it. This was the idea
+of Smart Tabs and this is a generalization of that idea.
+
+However in Emacs the Tab key is usually used for indentation.
+The idea here is that if Tab has been pressed once for
+indentation, then as long as point stays further Tab keys might
+as well do completion.
+
+So you kind of do Tab-Tab for first completion \(and then just
+Tab for further completions as long as point is not moved).
+
+And there is even kind of Tab-Tab-Tab completion: If completion
+fails the next completion function will be the one you try with
+next Tab. \(You get some notification of this, of course.)
+
+See `tabkey2-first' for more information about usage.
+
+Note: If you do not want the Tab-Tab behaviour above, but still
+want an easy way to reach the available completion functions,
+then you can instead of turning on tabkey2-mode enter this in
+your .emacs:
+
+ \(global-set-key [f8] 'tabkey2-cycle-completion-functions)
+
+After hitting f8 you will then be in the same state as after the
+first in tabkey2-mode."
+ :keymap nil
+ :global t
+ :group 'tabkey2
+ (if tabkey2-mode
+ (progn
+ (add-hook 'minibuffer-setup-hook 'tabkey2-minibuffer-setup)
+ (add-hook 'post-command-hook 'tabkey2-post-command)
+ ;; Update emul here if keymap have changed
+ (setq tabkey2--emul-keymap-alist
+ (list (cons 'tabkey2-mode
+ tabkey2-mode-emul-map)))
+ (add-to-list 'emulation-mode-map-alists 'tabkey2--emul-keymap-alist))
+ (tabkey2-completion-state-mode -1)
+ (remove-hook 'post-command-hook 'tabkey2-post-command)
+ (remove-hook 'minibuffer-setup-hook 'tabkey2-minibuffer-setup)
+ (setq emulation-mode-map-alists (delq 'tabkey2--emul-keymap-alist
+ emulation-mode-map-alists))))
+
+(defcustom tabkey2-modes-that-use-more-tabs
+ '(python-mode
+ haskell-mode
+ makefile-mode
+ org-mode
+ Custom-mode
+ custom-mode ;; For Emacs 22
+ ;; other
+ cmd-mode
+ )
+ "In those modes use must use S-Tab to start completion state.
+In those modes pressing Tab several types may make sense so you
+can not go into 'Tab completion state' just because one Tab has
+been pressed. Instead you use S-Tab to go into that state.
+After that Tab does completion.
+
+You can do use S-Tab in other modes too if you want too."
+ :type '(repeat (choice (command :tag "Currently known command")
+ (symbol :tag "Command not known yet")))
+ :group 'tabkey2)
+
+(defcustom tabkey2-modes-that-just-complete
+ '(shell-mode
+ fundamental-mode
+ text-mode)
+ "Tab is only used for completion in these modes.
+Therefore `tabkey2-first' just calls the function on Tab."
+ :type '(repeat (choice (command :tag "Currently known command")
+ (symbol :tag "Command not known yet")))
+ :group 'tabkey2)
+
+;;(setq tabkey2-use-popup-menus nil)
+;; (defcustom tabkey2-use-popup-menus (when (featurep 'popcmp) t)
+;; "Use pop menus if available."
+;; :type 'boolean
+;; :group 'tabkey2)
+
+;; (defvar tabkey2-preferred nil
+;; "Preferred function for second tab key press.")
+;; (make-variable-buffer-local 'tabkey2-preferred)
+;; (put 'tabkey2-preferred 'permanent-local t)
+
+(defvar tabkey2-fallback nil
+ "Fallback function for second tab key press.")
+(make-variable-buffer-local 'tabkey2-fallback)
+(put 'tabkey2-fallback 'permanent-local t)
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; State
+
+(defvar tabkey2-overlay nil
+ "Show when tab key 2 action is to be done.")
+(defvar tabkey2-keymap-overlay nil
+ "Hold the keymap for tab key 2.")
+
+(defvar tabkey2-current-tab-info nil
+ "Saved information message for Tab completion state.")
+(defvar tabkey2-current-tab-function nil
+ "Tab completion state current completion function.")
+(make-variable-buffer-local 'tabkey2-current-tab-function)
+
+(defun tabkey2-completion-state-p ()
+ "Return t if Tab completion state should continue.
+Otherwise return nil."
+ (when (and (eq (current-buffer) (overlay-buffer tabkey2-keymap-overlay))
+ (eq (overlay-get tabkey2-keymap-overlay 'window) (selected-window)))
+ (let* ((start (overlay-start tabkey2-keymap-overlay))
+ (end (overlay-end tabkey2-keymap-overlay))
+ (chars (append (buffer-substring-no-properties start end) nil)))
+ (and (not (memq ?\n chars))
+ (not (eq ?\ (car (last chars))))
+ (not (eq ?\ last-input-event))
+ (<= start (point))
+ (<= (point) end)
+ tabkey2-current-tab-function
+ (or (memq this-original-command '(tabkey2-first tabkey2-complete))
+ (let* ((last-name (symbol-name this-original-command))
+ (name-prefix "tabkey2-")
+ (prefix-len (length name-prefix)))
+ (and (> (length last-name) prefix-len)
+ (string= name-prefix (substring last-name 0 prefix-len)))))
+ ))))
+
+(defun tabkey2-read-only-p ()
+ "Return non-nil if buffer seems to be read-only at point."
+ (or buffer-read-only
+ (get-char-property (min (+ 0 (point)) (point-max)) 'read-only)
+ (let ((remap (command-remapping 'self-insert-command (point))))
+ (memq remap '(Custom-no-edit)))))
+
+;;;; Minor mode active after first tab
+
+(defun tabkey2-get-highlight-face ()
+ (if (eq tabkey2-current-tab-function
+ (tabkey2-first-active-from-completion-functions))
+ 'tabkey2-highlight-line
+ 'tabkey2-highlight-line2))
+
+(defun tabkey2-move-overlays ()
+ "Move overlays that mark the state and carries the state keymap."
+ (let* ((beg (let ((inhibit-field-text-motion t))
+ (line-beginning-position)))
+ (ind (current-indentation))
+ (end (+ beg 1)) ;(if (> ind 0) ind 1)))
+ (inhibit-read-only t))
+ (unless tabkey2-overlay
+ (setq tabkey2-overlay (make-overlay beg end)))
+ ;; Fix-me: gets some strange errors, try avoid moving:
+ (unless (and (eq (current-buffer) (overlay-buffer tabkey2-overlay))
+ (= beg (overlay-start tabkey2-overlay))
+ (= end (overlay-end tabkey2-overlay)))
+ (move-overlay tabkey2-overlay beg end (current-buffer)))
+ ;; Give it a high priority, it is very temporary
+ (overlay-put tabkey2-overlay 'priority 1000)
+ (if tabkey2-show-mark-on-active-line
+ (progn
+ (overlay-put tabkey2-overlay 'face
+ ;;'tabkey2-highlight-line
+ (tabkey2-get-highlight-face)
+ )
+ (overlay-put tabkey2-overlay 'help-echo
+ "This highlight shows that Tab completion state is on"))
+ (overlay-put tabkey2-overlay 'face nil)
+ (overlay-put tabkey2-overlay 'help-echo nil)))
+ ;; The keymap overlay
+ (let ((beg (line-beginning-position))
+ (end (line-end-position)))
+ ;;(when (= end (point-max)) (setq end (1+ end)))
+ (setq beg (point))
+ (setq end (point))
+
+ (unless tabkey2-keymap-overlay
+ ;; Make the rear of the overlay advance so that the keymap works
+ ;; at the end of a line and the end of the buffer.
+ (setq tabkey2-keymap-overlay (make-overlay 0 0 nil nil t)))
+ (overlay-put tabkey2-keymap-overlay 'priority 1000)
+ ;;(overlay-put tabkey2-keymap-overlay 'face 'secondary-selection)
+ (overlay-put tabkey2-keymap-overlay 'keymap
+ tabkey2-completion-state-emul-map)
+ (overlay-put tabkey2-keymap-overlay 'window (selected-window))
+ (move-overlay tabkey2-keymap-overlay beg end (current-buffer))))
+
+(defun tabkey2-is-active (fun chk)
+ "Return t FUN is active.
+Return t if CHK is a symbol with non-nil value or a form that
+evals to non-nil.
+
+Otherwise return t if FUN has a key binding at point."
+ (when (and (fboundp fun)
+ (commandp fun))
+ (or (if (symbolp chk)
+ (when (boundp chk) (symbol-value chk))
+ (eval chk))
+ (let* ((emulation-mode-map-alists
+ ;; Remove keymaps from tabkey2 in this copy:
+ (delq 'tabkey2--emul-keymap-alist
+ (copy-sequence emulation-mode-map-alists)))
+ (keys (tabkey2-symbol-keys fun))
+ kb-bound)
+ (dolist (key keys)
+ (unless (memq (car (append key nil))
+ '(menu-bar))
+ (setq kb-bound t)))
+ kb-bound))))
+
+(defun tabkey2-is-active-p (fun)
+ "Return FUN is active.
+Look it up in `tabkey2-completion-functions' to find out what to
+check and return the value from `tabkey2-is-active'."
+ (let ((chk (catch 'chk
+ (dolist (rec tabkey2-completion-functions)
+ (when (eq fun (nth 1 rec))
+ (throw 'chk (nth 2 rec)))))))
+ (tabkey2-is-active fun chk)))
+
+(defvar tabkey2-chosen-completion-function nil)
+(make-variable-buffer-local 'tabkey2-chosen-completion-function)
+(put 'tabkey2-chosen-completion-function 'permanent-local t)
+
+(defun tabkey2-first-active-from-completion-functions ()
+ "Return first active completion function.
+Look in `tabkey2-completion-functions' for the first function
+that has an active key binding."
+ (catch 'active-fun
+ (dolist (rec tabkey2-completion-functions)
+ (let ((fun (nth 1 rec))
+ (chk (nth 2 rec)))
+ (when (tabkey2-is-active fun chk)
+ (throw 'active-fun fun))))))
+
+(defun tabkey2-get-default-completion-fun ()
+ "Return the default completion function.
+See `tabkey2-first' for the list considered."
+ (or (when (and tabkey2-chosen-completion-function
+ (tabkey2-is-active-p
+ tabkey2-chosen-completion-function))
+ tabkey2-chosen-completion-function)
+ ;;tabkey2-preferred
+ (tabkey2-first-active-from-completion-functions)
+ tabkey2-fallback))
+
+(defvar tabkey2-overlay-message nil)
+
+(defvar tabkey2-completion-state-mode nil)
+;;(make-variable-buffer-local 'tabkey2-completion-state-mode)
+(defun tabkey2-completion-state-mode (arg)
+ "Tab completion state minor mode.
+This pseudo-minor mode holds the 'Tab completion state'. When this
+minor mode is on completion key bindings are available.
+
+With ARG a positive number turn on, otherwise turn off this minor
+mode.
+
+See `tabkey2-first' for more information."
+ ;;(assq-delete-all 'tabkey2-completion-state-mode minor-mode-alist)
+ (unless (assoc 'tabkey2-completion-state-mode minor-mode-alist)
+ ;;(setq minor-mode-alist (cons '(tabkey2-completion-state-mode " Tab2")
+ (setq minor-mode-alist (cons (list 'tabkey2-completion-state-mode
+ tabkey2-completion-lighter)
+ minor-mode-alist)))
+ (let ((emul-map (cdr (car tabkey2--emul-keymap-alist)))
+ (old-wincfg tabkey2-completion-state-mode))
+ (setq tabkey2-completion-state-mode (when (and (numberp arg)
+ (> arg 0))
+ ;;t
+ (current-window-configuration)
+ ))
+ (if tabkey2-completion-state-mode
+ (progn
+ ;; Set default completion function
+ (tabkey2-make-message-and-set-fun
+ (tabkey2-get-default-completion-fun))
+ ;; Message
+ ;;(setq tabkey2-message-is-shown nil)
+ (when tabkey2-show-message-on-enter
+ (tabkey2-show-current-message
+ (when (numberp tabkey2-show-message-on-enter)
+ tabkey2-show-message-on-enter)))
+ ;; Move overlays
+ (tabkey2-move-overlays)
+ ;; Work around eob keymap problem ...
+ ;;(set-keymap-parent emul-map (overlay-get tabkey2-keymap-overlay
+ ;; 'keymap))
+ ;; Set up for pre/post-command-hook
+ (add-hook 'pre-command-hook 'tabkey2-completion-state-pre-command)
+ (add-hook 'post-command-hook 'tabkey2-completion-state-post-command))
+ ;;(set-keymap-parent emul-map nil)
+ (setq tabkey2-current-tab-function nil)
+ (when (and old-wincfg
+ tabkey2-keymap-overlay
+ (eq (overlay-get tabkey2-keymap-overlay 'window) (selected-window))
+ (not (active-minibuffer-window)))
+ (set-window-configuration old-wincfg))
+ (let ((inhibit-read-only t))
+ (when tabkey2-keymap-overlay
+ (delete-overlay tabkey2-keymap-overlay))
+ (when tabkey2-overlay
+ (delete-overlay tabkey2-overlay)))
+ (remove-hook 'pre-command-hook 'tabkey2-completion-state-pre-command)
+ (remove-hook 'post-command-hook 'tabkey2-completion-state-post-command)
+ (tabkey2-overlay-message nil)
+ ;;(message "")
+ )))
+
+(defun tabkey2-completion-state-off ()
+ "Quit Tab completion state."
+ (interactive)
+ (tabkey2-completion-state-mode -1)
+ (let ((C-g-binding (or (key-binding [(control ?g)])
+ (key-binding "\C-g")))
+ did-more)
+ (when (and (boundp 'company-mode)
+ company-mode)
+ ;;(message "tabkey2:company-abort")
+ (company-abort)
+ (setq did-more t))
+ (when (and C-g-binding
+ (not (eq C-g-binding this-command)))
+ ;;(message "tabkey2:c-g=%s" C-g-binding)
+ (call-interactively C-g-binding)
+ (setq did-more t))
+ (message "Quit")))
+
+(defvar tabkey2-message-is-shown nil)
+(defun tabkey2-message-is-shown ()
+ (case tabkey2-message-style
+ ('popup
+ (when tabkey2-overlay-message
+ (overlay-buffer tabkey2-overlay-message)))
+ ('echo-area
+ (get (current-message) 'tabkey2))))
+
+(defun tabkey2-completion-state-pre-command ()
+ "Run this in `pre-command-hook'.
+Check if message is shown.
+Remove overlay message.
+Cancel delayed message."
+ ;;(message "=====> tabkey2-completion-state-pre-command")
+ (condition-case err
+ (progn
+ (setq tabkey2-message-is-shown (tabkey2-message-is-shown))
+ ;;(message "tabkey2-overlay-message=%s, is-shown=%s" tabkey2-overlay-message tabkey2-message-is-shown)
+ (tabkey2-overlay-message nil)
+ (tabkey2-cancel-delayed-message)
+ ;;(message "here buffer=%s, this-command=%s" (current-buffer) this-command)
+ )
+ (error (message "tabkey2 pre: %s" (error-message-string err)))))
+
+(defun tabkey2-completion-state-post-command ()
+ "Turn off Tab completion state if not feasable any more.
+This is run in `post-command-hook' after each command."
+ (condition-case err
+ ;;(save-match-data
+ ;; Delayed messages
+ (if (not (tabkey2-completion-state-p))
+ (tabkey2-completion-state-mode -1)
+ ;;(message "tabkey2-current-tab-function=%s" tabkey2-current-tab-function)
+ (tabkey2-move-overlays))
+ ;;)
+ (error (message "tabkey2 post: %s" (error-message-string err)))))
+
+(defun tabkey2-minibuffer-setup ()
+ "Activate/deactivate function `tabkey2-mode' in minibuffer."
+ (set (make-local-variable 'tabkey2-mode)
+ (and tabkey2-mode
+ tabkey2-in-minibuffer))
+ (unless tabkey2-mode
+ (set (make-local-variable 'emulation-mode-map-alists)
+ (delq 'tabkey2--emul-keymap-alist
+ (copy-sequence emulation-mode-map-alists)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; Message functions
+
+;; Fix-me: Included in Emacs 23.
+(unless (fboundp 'invisible-p)
+ (defun invisible-p (pos)
+ "Return non-nil if the character after POS is currently invisible."
+ (let ((prop
+ (get-char-property pos 'invisible)))
+ (if (eq buffer-invisibility-spec t)
+ prop
+ (if (listp prop)
+ (catch 'invis
+ (dolist (p prop)
+ (when (or (memq p buffer-invisibility-spec)
+ (assq p buffer-invisibility-spec))
+ (throw 'invis t))))
+ (or (memq prop buffer-invisibility-spec)
+ (assq prop buffer-invisibility-spec)))))))
+
+;; (defun test-scroll ()
+;; (interactive)
+;; (setq debug-on-error t)
+;; (let* ((buffer-name "test-scroll")
+;; (buffer (get-buffer buffer-name)))
+;; (when buffer (kill-buffer buffer))
+;; (setq buffer (get-buffer-create buffer-name))
+;; (switch-to-buffer buffer)
+;; (message "here 1") (sit-for 1)
+;; (condition-case err
+;; (scroll-up 1)
+;; (error (message "scroll-up error: %s" err)
+;; (sit-for 1)))
+;; (message "here 2") (sit-for 1)
+;; (scroll-up 1)
+;; (message "here 3") (sit-for 1)
+;; ))
+
+(defun tabkey2-overlay-message (txt)
+ "Display TXT below or above current line using an overlay."
+ ;;(setq tabkey2-message-is-shown txt)
+ (if (not txt)
+ (when tabkey2-overlay-message
+ (delete-overlay tabkey2-overlay-message)
+ (setq tabkey2-overlay-message nil))
+ (let ((ovl tabkey2-overlay-message)
+ (column (current-column))
+ (txt-len (length txt))
+ (here (point))
+ beg end
+ (before "")
+ (after "")
+ ovl-str too-much
+ (is-eob (eobp))
+ (direction 1))
+ (unless ovl (setq ovl (make-overlay 0 0)))
+ (when tabkey2-overlay-message
+ (delete-overlay tabkey2-overlay-message))
+ (setq tabkey2-overlay-message ovl)
+
+ (when is-eob
+ (setq direction -1))
+ (when (and (/= (point-min) (window-start))
+ (not (pos-visible-in-window-p (min (point-max) (1+ (line-end-position))))))
+ ;; Go back inside window to avoid aggressive scrolling:
+ (forward-line -1)
+ (scroll-up 1)
+ (forward-line 1))
+ (forward-line direction)
+ ;; Fix-me: Emacs bug workaround
+ (if (when (< 1 (point))
+ (invisible-p (1- (line-end-position))))
+ (progn
+ (goto-char here)
+ (tabkey2-echo-area-message txt))
+ ;; Fix-me: Does this really do anything now:
+ (when (invisible-p (point))
+ (while (invisible-p (point))
+ (forward-line direction)))
+ (setq beg (line-beginning-position))
+ (setq end (line-end-position))
+
+ (if (or (invisible-p beg) (invisible-p end))
+ ;; Give up, do not fight invisibility:
+ (progn
+ (tabkey2-overlay-message nil)
+ (tabkey2-echo-area-message txt))
+
+ ;; string before
+ (move-to-column column)
+ (setq before (buffer-substring beg (point)))
+ (when (< (current-column) column)
+ (setq before
+ (concat before
+ (make-string (- column (current-column)) ? ))))
+ (setq too-much (- (+ 1 txt-len (length before))
+ (window-width)))
+ (when (> too-much 0)
+ (setq before (substring before 0 (- too-much))))
+
+ (unless (> too-much 0)
+ (move-to-column (+ txt-len (length before)))
+ (setq after (buffer-substring (point) end)))
+
+ (setq ovl-str (concat before
+ (propertize txt 'face 'tabkey2-highlight-popup)
+ after
+ ))
+
+ (overlay-put ovl 'after-string ovl-str)
+ (overlay-put ovl 'display "")
+ (overlay-put ovl 'window (selected-window))
+ (move-overlay ovl beg end (current-buffer)))
+
+ (goto-char here)
+ ))))
+
+;; Fix-me: This was not usable IMO. Too much flickering.
+;; (defun tabkey2-tooltip (txt)
+;; (let* ((params tooltip-frame-parameters)
+;; (coord (car (point-to-coord (point))))
+;; (left (car coord))
+;; (top (cadr coord))
+;; tooltip-frame-parameters
+;; )
+;; ;; Fix-me: how do you get char height??
+;; (setq top (+ top 50))
+;; (setq params (tooltip-set-param params 'left left))
+;; (setq params (tooltip-set-param params 'top top))
+;; (setq params (tooltip-set-param params 'top top))
+;; (setq tooltip-frame-parameters params)
+;; (tooltip-hide)
+;; (tooltip-show txt nil)))
+
+(defun tabkey2-echo-area-message (txt)
+ "Show TXT in the echo area with a special face.
+Shown with the face `tabkey2-highlight-message'."
+ (message "%s" (propertize txt
+ 'face 'tabkey2-highlight-message
+ 'tabkey2 t)))
+
+(defun tabkey2-deliver-message (txt)
+ "Show message TXT to user."
+ (case tabkey2-message-style
+ (popup (tabkey2-overlay-message txt))
+ (t (tabkey2-echo-area-message txt))))
+
+(defun tabkey2-timer-deliver-message (txt where)
+ "Show message TXT to user.
+Protect from errors cause this is run during a timer."
+ (save-match-data ;; runs in timer
+ (when (and tabkey2-completion-state-mode
+ (equal (point-marker) where))
+ (condition-case err
+ (tabkey2-deliver-message txt)
+ (error (message "tabkey2-timer-deliver-message: %s"
+ (error-message-string err)))))))
+
+(defvar tabkey2-delayed-timer nil)
+
+(defun tabkey2-cancel-delayed-message ()
+ "Cancel delayed message."
+ (when tabkey2-delayed-timer
+ (cancel-timer tabkey2-delayed-timer)
+ (setq tabkey2-delayed-timer)))
+
+(defun tabkey2-maybe-delayed-message (txt delay)
+ "Show message TXT, delay it if DELAY is non-nil."
+ (if delay
+ (setq tabkey2-delayed-timer
+ (run-with-idle-timer
+ delay nil
+ 'tabkey2-timer-deliver-message txt (point-marker)))
+ (tabkey2-deliver-message txt)))
+
+(defun tabkey2-message (delay format-string &rest args)
+ "Show, if DELAY delayed, otherwise immediately message.
+FORMAT-STRING and ARGS are like for `message'."
+ (let ((txt (apply 'format format-string args)))
+ (tabkey2-maybe-delayed-message txt delay)))
+
+(defun tabkey2-show-current-message (&optional delay)
+ "Show current completion message, delayed if DELAY is non-nil."
+ (tabkey2-cancel-delayed-message)
+ (tabkey2-message delay "%s" tabkey2-current-tab-info))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; Completion function selection etc
+
+(defun tabkey2-symbol-keys (comp-fun)
+ "Get a list of all key bindings for COMP-FUN."
+ (let* ((remapped (command-remapping comp-fun)))
+ (where-is-internal comp-fun
+ nil ;;overriding-local-map
+ nil nil remapped)))
+
+(defun tabkey2-get-active-completion-functions ()
+ "Get a list of active completion functions.
+Consider only those in `tabkey2-completion-functions'."
+ (delq nil
+ (mapcar (lambda (rec)
+ (let ((fun (nth 1 rec))
+ (chk (nth 2 rec)))
+ (when (tabkey2-is-active fun chk) rec)))
+ tabkey2-completion-functions)))
+
+(defun tabkey2-make-current-default ()
+ "Make current Tab completion function default.
+Set the current Tab completion function at point as default for
+the current buffer."
+ (interactive)
+ (let ((set-it
+ (y-or-n-p
+ (format
+ "Make %s default for Tab completion in current buffer? "
+ tabkey2-current-tab-function))))
+ (when set-it
+ (setq tabkey2-chosen-completion-function
+ tabkey2-current-tab-function))
+ (unless set-it
+ (when (local-variable-p 'tabkey2-chosen-completion-function)
+ (when (y-or-n-p "Use default Tab completion selection in buffer? ")
+ (setq set-it t))
+ (kill-local-variable 'tabkey2-chosen-completion-function)))
+ (when (tabkey2-completion-state-p)
+ (tabkey2-message nil "%s%s" tabkey2-current-tab-info
+ (if set-it " - Done" "")))))
+
+(defun tabkey2-activate-next-completion-function (wrap)
+ (let* ((active (mapcar (lambda (rec)
+ (nth 1 rec))
+ (tabkey2-get-active-completion-functions)))
+ (first (car active))
+ next)
+ ;;(message "is-shown=%s current=%s active=%s overlay=%s" tabkey2-message-is-shown tabkey2-current-tab-function active tabkey2-overlay)
+ (when tabkey2-current-tab-function
+ (while (and active (not next))
+ (when (eq (car active) tabkey2-current-tab-function)
+ (setq next (cadr active)))
+ (setq active (cdr active))))
+ (unless next
+ (when wrap (setq next first)))
+ ;;(if (eq first next)
+ (tabkey2-make-message-and-set-fun next)))
+
+(defun tabkey2-cycle-completion-functions (prefix)
+ "Cycle through cnd display ompletion functions.
+If 'Tab completion state' is not on then turn it on.
+
+If PREFIX is given just show what this command will do."
+ (interactive "P")
+ (if (tabkey2-read-only-p)
+ (message "Buffer is read only at point")
+ (unless tabkey2-completion-state-mode (tabkey2-completion-state-mode 1))
+ (save-match-data
+ (if prefix
+ ;; fix-me
+ (message "(TabKey2) %s: show/cycle completion function"
+ last-input-event)
+ (when tabkey2-message-is-shown
+ ;; Message is shown currently so change
+ (tabkey2-activate-next-completion-function 'wrap))
+ (tabkey2-show-current-message)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; Handling of Tab and alternate key
+
+;;;###autoload
+(defun tabkey2-emma-without-tabkey2 ()
+ ;; Remove keymaps from tabkey2 in this copy:
+ (delq 'tabkey2--emul-keymap-alist
+ (copy-sequence emulation-mode-map-alists)))
+
+(defvar tabkey2-step-out-of-the-way nil)
+;;(remove-hook 'pre-command-hook 'tabkey2-pre-command)
+;;(remove-hook 'post-command-hook 'tabkey2-pre-command)
+;;(remove-hook 'post-command-hook 'tabkey2-post-command-2)
+(defun tabkey2-post-command ()
+ (setq tabkey2-step-out-of-the-way nil)
+ (condition-case err
+ (when tabkey2-mode
+ (when (and (boundp 'company-overriding-keymap-bound) company-overriding-keymap-bound)
+ (setq tabkey2-step-out-of-the-way
+ (let ((emulation-mode-map-alists (tabkey2-emma-without-tabkey2)))
+ (key-binding (this-command-keys))))
+ ;;(message "tabkey2-step-out=%s, %s" (this-command-keys) tabkey2-step-out-of-the-way)
+ ))
+ (error "tabkey2-pre-command: %s" err)))
+ ;; (and (boundp 'company-preview-overlay)
+ ;; (or company-preview-overlay
+ ;; company-pseudo-tooltip-overlay)))
+(defun tabkey2-first (prefix)
+ "Do something else after first Tab.
+This function is bound to the Tab key \(or whatever key
+`tabkey2-first-key' is) when minor mode command `tabkey2-mode' is
+on. It works like this:
+
+1. The first time Tab is pressed do whatever Tab would have done
+ if minor mode command `tabkey2-mode' was off.
+
+ Then before next command enter a new temporary 'Tab completion
+ state' for just the next command. Show this by a highlight on
+ the indentation and a marker \"Tab2\" in the mode line.
+
+ However if either
+ - the minibuffer is active and `tabkey2-in-minibuffer' is nil
+ - `major-mode' is in `tabkey2-modes-that-use-more-tabs' then
+ do not enter this temporary 'Tab completion state'.
+
+ For major modes where it make sense to press Tab several times
+ you can use `tabkey2-alternate-key' to enter 'Tab completion
+ state'.
+
+
+2. As long as point is not move do completion when Tab is pressed
+ again. Show that this state is active with a highlighting at
+ the line beginning, a marker on the mode line (Tab2) and a
+ message in the echo area which tells what kind of completion
+ will be done.
+
+ When deciding what kind of completion to do look in the table
+ below and do whatever it found first that is not nil:
+
+ - `tabkey2-preferred'
+ - `tabkey2-completion-functions'
+ - `tabkey2-fallback'
+
+3. Of course, there must be some way for you to easily determine
+ what kind of completion because there are many in Emacs. If
+ you do not turn it off this function will show that to you.
+ And if you turn it off you can still display it, see the key
+ bindings below.
+
+ If this function is used with a PREFIX argument then it just
+ shows what Tab will do.
+
+ If the default kind of completion is not what you want then
+ you can choose completion function from any of the candidates
+ in `tabkey2-completion-functions'. During the 'Tab completion
+ state' the following extra key bindings are available:
+
+\\{tabkey2-completion-state-emul-map}
+
+Of course, some languages does not have a fixed indent as is
+assumed above. You can put major modes for those in
+`tabkey2-modes-that-just-complete'.
+
+Some major modes uses tab for something else already. Those are
+in `tabkey2-modes-that-use-more-tabs'. There is an alternate
+key, `tabkey2-alternate-key' if you want to do completion
+there. Note that this key does not do completion. It however
+enters 'Tab completion state' in which you have access to the
+keys above for completion etc. \(This key also lets you cycle
+through the completion functions too choose which one to use.)
+
+-----
+NOTE: This uses `emulation-mode-map-alists' and it supposes that
+nothing else is bound to Tab there."
+ (interactive "P")
+ ;;(message "first:tabkey2-step-out=%s, %s" (this-command-keys) tabkey2-step-out-of-the-way)
+ (if tabkey2-step-out-of-the-way
+ (progn
+ (message "step-out=%s" tabkey2-step-out-of-the-way)
+ (call-interactively tabkey2-step-out-of-the-way))
+ (if (and tabkey2-keymap-overlay
+ (eq (overlay-buffer tabkey2-keymap-overlay) (current-buffer))
+ (eq (overlay-get tabkey2-keymap-overlay 'window) (selected-window))
+ (>= (point) (overlay-start tabkey2-keymap-overlay))
+ (<= (point) (overlay-end tabkey2-keymap-overlay)))
+ ;; We should maybe not be here, but the keymap does not work at
+ ;; the end of the buffer so we call the second tab function from
+ ;; here:
+ (if (memq 'shift (event-modifiers last-input-event))
+ (call-interactively 'tabkey2-cycle-completion-functions)
+ (call-interactively 'tabkey2-complete prefix))
+ (let* ((emma-without-tabkey2 (tabkey2-emma-without-tabkey2))
+ (at-word-end (looking-at "\\_>"))
+ (just-complete (or (memq major-mode tabkey2-modes-that-just-complete)
+ at-word-end))
+ (what (if just-complete
+ 'complete
+ (if (or (unless tabkey2-in-minibuffer
+ (active-minibuffer-window))
+ (when (fboundp 'use-region-p) (use-region-p))
+ (not at-word-end)
+ (memq major-mode tabkey2-modes-that-use-more-tabs))
+ 'indent
+ 'indent-complete
+ )))
+ (to-do-1 (unless (or
+ ;; Skip action on tab if shift tab,
+ ;; backtab or a mode in the "just
+ ;; complete" list
+ (memq 'shift (event-modifiers last-input-event))
+ (equal [backtab] (this-command-keys-vector))
+ )
+ (let ((emulation-mode-map-alists emma-without-tabkey2))
+ ;; Fix-me: Is this the way to pick up "tab keys"?
+ (or (key-binding [tab] t)
+ (key-binding [?\t] t))
+ )))
+ (to-do-2 (unless (or ;;(memq what '(complete))
+ (memq what '(indent))
+ (memq to-do-1 '(widget-forward button-forward)))
+ (tabkey2-get-default-completion-fun))))
+ ;;(message "step-out-of-the-way=%s to-do=%s/%s, emmaa-without-tabkey2=%s" step-out-of-the-way to-do-1 to-do-2 emma-without-tabkey2)
+ (if prefix
+ (if (memq 'shift (event-modifiers last-input-event))
+ (message
+ "(TabKey2) First shift %s: turn on 'Tab completion state'"
+ last-input-event)
+ (message "(TabKey2) First %s: %s, next: maybe %s"
+ last-input-event to-do-1
+ (if to-do-2 to-do-2 "(same)")))
+ (when to-do-1
+ (let (xmumamo-multi-major-mode)
+ (tabkey2-call-interactively to-do-1)))
+ (unless (tabkey2-read-only-p)
+ (when to-do-2
+ (tabkey2-completion-state-mode 1))))))))
+
+(defun tabkey2-call-interactively (function)
+ "Like `call-interactively, but handle `this-command'."
+ (setq this-command function)
+ (call-interactively function))
+
+(defcustom tabkey2-choose-next-on-error t
+ "Choose next completion function on error."
+ :type 'boolean
+ :group 'tabkey2)
+
+(defun tabkey2-complete (prefix)
+ "Call current completion function.
+If used with a PREFIX argument then just show what Tab will do."
+ (interactive "P")
+ (if (and (boundp 'mumamo-multi-major-mode)
+ mumamo-multi-major-mode
+ (not (mumamo-syntax-maybe-completable (point))))
+ (message "Please move out of chunk border before trying to complete.")
+ (if prefix
+ (message "(TabKey2) %s: %s"
+ last-input-event tabkey2-current-tab-function)
+ (let ((here (point))
+ (res (if tabkey2-choose-next-on-error
+ (condition-case err
+ (tabkey2-call-interactively tabkey2-current-tab-function)
+ (error (message "%s" (error-message-string err))
+ nil))
+ (tabkey2-call-interactively tabkey2-current-tab-function))))
+ (when (and (not res) (= here (point)))
+ (tabkey2-activate-next-completion-function nil)
+ ;;(message "complete.tabkey2-current-tab-function=%s" tabkey2-current-tab-function)
+ (if tabkey2-current-tab-function
+ (tabkey2-show-current-message)
+ (message "No more active completion functions in this buffer")))))))
+
+;; Fix-me: I am not sure that it really is useful with a globalized
+;; minor mode here because there are so many other ways to control
+;; what happens in a specific buffer. Maybe it would just be
+;; confusing?
+;;
+;; If found another problem with making it globalized: tabkey2-mode
+;; uses emulation-mode-map-alist. I decided to remove this therefore.
+;;
+;; (defun tabkey2-turn-on ()
+;; "Turn on `tabkey2-mode' in current buffer."
+;; (tabkey2-mode 1))
+
+;; (defvar tabkey2-turn-on-function 'tabkey2-turn-on
+;; "Function used to mabye turn on `tabkey2-mode' in current-buffer.
+;; This function is used by `tabkey2-global-mode' to turn on
+;; `tabkey2-mode'.")
+
+;; (defun tabkey2-turn-on-in-buffer ()
+;; (funcall tabkey2-turn-on-function))
+
+;; (define-globalized-minor-mode tabkey2-global-mode
+;; tabkey2-mode tabkey2-turn-on-in-buffer)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; Help functions
+
+(defun tabkey2-show-completion-state-help ()
+ "Help for 'Tab completion state'.
+To get out of this state you can move out of the current line.
+
+During this state the keymap below is active. This state stops
+as soon as you leave the current row.
+
+\\{tabkey2-completion-state-emul-map}
+See function `tabkey2-mode' for more information.
+
+If you want to use Emacs normal help function then press F1
+again.")
+
+(defun tabkey2-completion-state-help ()
+ "Show help for 'Tab completion state'."
+ (interactive)
+ ;;(message "tckv=%s" (this-command-keys-vector)) ;;(sit-for 1)
+ ;; Fix-me: There seems to be an Emacs bug lurking here. Sometimes
+ ;; invoked-by-f1 is not [f1].
+ (let ((invoked-by-f1 (equal (this-command-keys-vector) [f1]))
+ normal-help)
+ ;;(message "invoked-by-f1=%s" invoked-by-f1) ;; fix-me
+ (if (not invoked-by-f1)
+ (describe-function 'tabkey2-show-completion-state-help)
+ (setq normal-help
+ (read-event
+ (propertize
+ (concat "Type a key for Emacs help."
+ " Or, wait for Tab completion state help: ")
+ 'face 'highlight)
+ nil
+ 4))
+ (case normal-help
+ ((nil)
+ ;;(message "Tab completion state help")
+ (describe-function 'tabkey2-show-completion-state-help))
+ (?c
+ (call-interactively 'describe-key-briefly))
+ (?k
+ (call-interactively 'describe-key))
+ (t
+ (tabkey2-completion-state-mode -1)
+ (setq unread-command-events
+ (reverse
+ (cons
+ normal-help
+ (append (this-command-keys) nil)))))))))
+
+(defun tabkey2-completion-function-help ()
+ "Show help for current completion function."
+ (interactive)
+ (describe-function tabkey2-current-tab-function))
+
+
+
+
+(defun tabkey2-get-key-binding (fun t2)
+ "Get key binding for FUN during 'Tab completion state'."
+ (let* ((remapped (command-remapping fun))
+ (key (where-is-internal fun
+ (when t2 tabkey2-completion-state-emul-map)
+ t
+ nil
+ remapped)))
+ key))
+
+;; (defun tabkey2-reset-completion-function (comp-fun)
+;; "Reset states for functions in `tabkey2-completion-functions'."
+;; ;; Fix-me: remove hard-coding
+;; (setq dabbrev--last-abbrev-location nil))
+
+(defun tabkey2-make-message-and-set-fun (comp-fun)
+ "Set current completion function to COMP-FUN.
+Build message but don't show it."
+ ;;(tabkey2-reset-completion-functions)
+ (let* ((chs-fun 'tabkey2-cycle-completion-functions)
+ (key (tabkey2-get-key-binding chs-fun t))
+ ;;(def-fun (tabkey2-get-default-completion-fun))
+ what
+ (comp-fun-key (tabkey2-get-key-binding comp-fun nil))
+ reset)
+ (setq tabkey2-current-tab-function comp-fun)
+ (dolist (rec tabkey2-completion-functions)
+ (let ((fun (nth 1 rec))
+ (txt (nth 0 rec))
+ (res (nth 3 rec)))
+ (when (eq fun comp-fun)
+ (eval res)
+ (setq what txt))))
+ (let ((info (concat (format "Tab: %s" what)
+ (if comp-fun-key
+ (format " (%s)" (key-description comp-fun-key))
+ "")
+ (if (cdr (tabkey2-get-active-completion-functions))
+ (format ", other %s, help F1"
+ (key-description key))
+ ""))))
+ (setq tabkey2-current-tab-info info))))
+
+(defun tabkey2-get-active-string (bnd fun buf)
+ "Get string to show for state.
+BND: means active
+FUN: function
+BUF: buffer"
+ (if bnd
+ (if (with-current-buffer buf (tabkey2-read-only-p))
+ (propertize "active, but read-only" 'face '( :foreground "red"))
+ (propertize "active" 'face '( :foreground "green3")))
+ (if (and (fboundp fun)
+ (commandp fun))
+ (propertize "not active" 'face '( :foreground "red2"))
+ (propertize "not defined" 'face '( :foreground "gray")))))
+
+(defun tabkey2-show-completion-functions ()
+ "Show what currently may be used for completion."
+ (interactive)
+ (let ((orig-buf (current-buffer))
+ (orig-mn mode-name)
+ (active-mark (concat " "
+ (propertize "<= default"
+ 'face '( :background "yellow"))))
+ (act-found nil)
+ (chosen-fun tabkey2-chosen-completion-function)
+ what
+ chosen)
+ (when chosen-fun
+ (dolist (rec tabkey2-completion-functions)
+ (let ((fun (nth 1 rec))
+ (txt (nth 0 rec)))
+ (when (eq fun chosen-fun) (setq what txt))))
+ (setq chosen (list what chosen-fun)))
+ (with-output-to-temp-buffer (help-buffer)
+ (help-setup-xref (list #'tabkey2-show-completion-functions)
+ (interactive-p))
+ (with-current-buffer (help-buffer)
+ (insert (concat "The completion functions available for"
+ " 'Tab completion' in buffer\n'"
+ (buffer-name orig-buf)
+ "' at point with mode " orig-mn " are shown below.\n"
+ "The first active function is used by default.\n\n"))
+ (if (not chosen)
+ (insert " No completion function is set as default.")
+ (let* ((txt (nth 0 chosen))
+ (fun (nth 1 chosen))
+ (chk (nth 2 chosen))
+ (bnd (with-current-buffer orig-buf
+ (tabkey2-is-active fun chk)))
+ (act (tabkey2-get-active-string bnd fun orig-buf)))
+ (insert (format " Default is set to\n %s (%s): %s"
+ txt fun act))
+ (when bnd (insert active-mark) (setq act-found t))))
+ (insert "\n\n")
+;;; (if (not tabkey2-preferred)
+;;; (insert " None is preferred")
+;;; (let* ((txt (nth 0 tabkey2-preferred))
+;;; (fun (nth 1 tabkey2-preferred))
+;;; (chk (nth 2 chosen))
+;;; (bnd (with-current-buffer orig-buf
+;;; (tabkey2-is-active fun chk)))
+;;; (act (tabkey2-get-active-string bnd fun orig-buf)))
+;;; (insert (format " Preferred is %s (`%s')': %s"
+;;; txt fun act))
+;;; (when bnd (insert active-mark) (setq act-found t))))
+;;; (insert "\n\n")
+ (dolist (comp-fun tabkey2-completion-functions)
+ (let* ((txt (nth 0 comp-fun))
+ (fun (nth 1 comp-fun))
+ (chk (nth 2 comp-fun))
+ (bnd (with-current-buffer orig-buf
+ (tabkey2-is-active fun chk)))
+ (act (tabkey2-get-active-string bnd fun orig-buf))
+ (keys (where-is-internal fun)))
+ (if (not keys)
+ (setq keys "")
+ (setq keys (mapconcat 'key-description keys ", "))
+ (when (and (< 9 (length keys))
+ (string= "<menu-bar>" (substring keys 0 10)))
+ (setq keys "Menu"))
+ (setq keys (propertize keys 'face 'highlight))
+ (setq keys (concat ", " keys))
+ )
+ (insert
+ (format
+ " %s (`%s'%s): %s"
+ txt fun keys act))
+ (when (and (not act-found) bnd)
+ (insert active-mark) (setq act-found t))
+ (insert "\n")))
+ (insert "\n")
+ (if (not tabkey2-fallback)
+ (insert " There is no fallback")
+ (let* ((txt (nth 0 tabkey2-fallback))
+ (fun (nth 1 tabkey2-fallback))
+ (chk (nth 2 tabkey2-fallback))
+ (bnd (with-current-buffer orig-buf
+ (tabkey2-is-active fun chk)))
+ (act (tabkey2-get-active-string bnd fun orig-buf)))
+ (insert (format " Fallback is %s (`%s'): %s"
+ txt fun act))
+ (when (and (not act-found) bnd)
+ (insert active-mark)
+ (setq act-found t))))
+ (insert "\n\nYou an ")
+ (insert-text-button "customize this list"
+ 'action (lambda (button)
+ (customize-option
+ 'tabkey2-completion-functions)))
+ (insert ".\nSee function `tabkey2-mode' for more information.")
+ (with-no-warnings (print-help-return-message))))))
+
+(defvar tabkey2-completing-read 'completing-read)
+
+(defun tabkey2-set-fun (fun)
+ "Use function FUN for Tab in 'Tab completion state'."
+ (setq tabkey2-chosen-completion-function fun)
+ (unless fun
+ (setq fun (tabkey2-first-active-from-completion-functions)))
+ (tabkey2-make-message-and-set-fun fun)
+ (when (tabkey2-completion-state-p)
+ (message "%s" tabkey2-current-tab-info)))
+
+(defun tabkey2-appmenu ()
+ "Make a menu for minor mode command `appmenu-mode'."
+ (unless (tabkey2-read-only-p)
+ (let* ((cf-r (reverse (tabkey2-get-active-completion-functions)))
+ (tit "Complete")
+ (map (make-sparse-keymap tit)))
+ (define-key map [tabkey2-usage]
+ (list 'menu-item "Show Available Completion Functions for TabKey2"
+ 'tabkey2-show-completion-functions))
+ (define-key map [tabkey2-divider-1] (list 'menu-item "--"))
+ (let ((set-map (make-sparse-keymap "Set Completion")))
+ (define-key map [tabkey2-choose]
+ (list 'menu-item "Set Primary TabKey2 Tab Completion in Buffer" set-map))
+ (dolist (cf-rec cf-r)
+ (let ((dsc (nth 0 cf-rec))
+ (fun (nth 1 cf-rec)))
+ (define-key set-map
+ (vector (intern (format "tabkey2-set-%s" fun)))
+ (list 'menu-item dsc
+ `(lambda ()
+ (interactive)
+ (tabkey2-set-fun ',fun))
+ :button
+ `(:radio
+ . (eq ',fun tabkey2-chosen-completion-function))))))
+ (define-key set-map [tabkey2-set-div] (list 'menu-item "--"))
+ (define-key set-map [tabkey2-set-default]
+ (list 'menu-item "Default Tab completion"
+ (lambda ()
+ (interactive)
+ (tabkey2-set-fun nil))
+ :button
+ '(:radio . (null tabkey2-chosen-completion-function))))
+ (define-key set-map [tabkey2-set-header-div] (list 'menu-item "--"))
+ (define-key set-map [tabkey2-set-header]
+ (list 'menu-item "Set Primary Tab Completion for Buffer"))
+ )
+ (define-key map [tabkey2-divider] (list 'menu-item "--"))
+ (dolist (cf-rec cf-r)
+ (let ((dsc (nth 0 cf-rec))
+ (fun (nth 1 cf-rec)))
+ (define-key map
+ (vector (intern (format "tabkey2-call-%s" fun)))
+ (list 'menu-item dsc fun
+ :button
+ `(:toggle
+ . (eq ',fun tabkey2-chosen-completion-function))
+ ))))
+ map)))
+
+;; (defun tabkey2-completion-menu-popup ()
+;; "Pop up a menu with completion alternatives."
+;; (interactive)
+;; (let ((menu (tabkey2-appmenu)))
+;; (popup-menu-at-point menu)))
+
+;; (defun tabkey2-choose-completion-function ()
+;; "Set current completion function.
+;; Let user choose completion function from those in
+;; `tabkey2-completion-functions' that have some key binding at
+;; point.
+
+;; Let the chosen completion function be the default for subsequent
+;; completions in the current buffer."
+;; ;; Fix-me: adjust to mumamo.
+;; (interactive)
+;; (save-match-data
+;; (if (and (featurep 'popcmp)
+;; tabkey2-use-popup-menus)
+;; (tabkey2-completion-menu-popup)
+;; (when (eq 'completing-read tabkey2-completing-read) (isearch-unread 'tab))
+;; (let* ((cf-r (reverse (tabkey2-get-active-completion-functions)))
+;; (cf (cons '("- Use default Tab completion" nil) cf-r))
+;; (hist (mapcar (lambda (rec)
+;; (car rec))
+;; cf))
+;; (tit (funcall tabkey2-completing-read "Set current completion function: " cf
+;; nil ;; predicate
+;; t ;; require-match
+;; nil ;; initial-input
+;; 'hist ;; hist
+;; ))
+;; (fun-rec (assoc-string tit cf))
+;; (fun (cadr fun-rec)))
+;; (setq tabkey2-chosen-completion-function fun)
+;; (unless fun
+;; (setq fun (tabkey2-first-active-from-completion-functions)))
+;; (tabkey2-make-message-and-set-fun fun)
+;; (when (tabkey2-completion-state-p)
+;; (tabkey2-show-current-message))))))
+
+;; (defun tabkey2-add-to-appmenu ()
+;; "Add a menu to function `appmenu-mode'."
+;; (appmenu-add 'tabkey2 nil t "Completion" 'tabkey2-appmenu))
+
+
+(provide 'tabkey2)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; tabkey2.el ends here