[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/ergoemacs-mode 97a2107 243/325: Add back the command lo
From: |
Stefan Monnier |
Subject: |
[elpa] externals/ergoemacs-mode 97a2107 243/325: Add back the command loop. Part of it seems broken |
Date: |
Sat, 23 Oct 2021 18:49:02 -0400 (EDT) |
branch: externals/ergoemacs-mode
commit 97a21072a794199b54ad9000f7ebde49befc7894
Author: Matthew Fidler <514778+mattfidler@users.noreply.github.com>
Commit: Matthew Fidler <514778+mattfidler@users.noreply.github.com>
Add back the command loop. Part of it seems broken
---
ergoemacs-command-loop.el | 1646 ++++++++++++++++++++++++++++++++++++++++++++-
ergoemacs-macros.el | 34 +
ergoemacs-mode.el | 6 +
ergoemacs-themes.el | 106 +++
ergoemacs-translate.el | 207 +++++-
5 files changed, 1958 insertions(+), 41 deletions(-)
diff --git a/ergoemacs-command-loop.el b/ergoemacs-command-loop.el
index a8bbb22..af73e3e 100644
--- a/ergoemacs-command-loop.el
+++ b/ergoemacs-command-loop.el
@@ -35,6 +35,9 @@
(require 'ergoemacs-macros))
+(declare-function ergoemacs-translate--emacs-shift "ergoemacs-translate")
+(declare-function ergoemacs-warn "ergoemacs-lib")
+
(declare-function guide-key/close-guide-buffer "guide-key")
(declare-function guide-key/popup-function "guide-key")
@@ -43,6 +46,9 @@
(declare-function ergoemacs-mode-line "ergoemacs-mode")
+(declare-function ergoemacs-layout--regexp "ergoemacs-layouts")
+(declare-function ergoemacs-layouts--list "ergoemacs-layouts")
+
(declare-function ergoemacs-map-properties--movement-p
"ergoemacs-map-properties")
(declare-function ergoemacs-map-properties--put "ergoemacs-map-properties")
@@ -64,6 +70,7 @@
(declare-function ergoemacs-translation-struct-p "ergoemacs-translate")
(declare-function ergoemacs-translation-struct-text "ergoemacs-translate")
(declare-function ergoemacs-translation-struct-translation
"ergoemacs-translate")
+(declare-function ergoemacs-translation-struct-unchorded "ergoemacs-translate")
(declare-function ergoemacs-key-description--modifier
"ergoemacs-key-description")
@@ -83,10 +90,15 @@
(defvar ergoemacs-default-cursor-color)
(defvar ergoemacs-echo-function)
(defvar ergoemacs-map--quit-map)
+(defvar ergoemacs-modal-emacs-state-modes)
+(defvar ergoemacs-modal-ignored-buffers)
+(defvar ergoemacs-modal-ignored-keymap)
(defvar ergoemacs-mode-started-p)
(defvar guide-key/guide-key-sequence)
(defvar keyfreq-mode)
(defvar keyfreq-table)
+(defvar ergoemacs-translate--emacs-shift)
+(defvar ergoemacs-command-loop-start)
(defvar universal-argument-num-events) ;; Not in Emacs 24.5
@@ -96,6 +108,12 @@
(defvar ergoemacs-command-loop--mark-active nil
"Determines if mark was active before ergoemacs command loop.")
+(define-obsolete-variable-alias 'ergoemacs-universal-fns
'ergoemacs-command-loop--universal-functions "Ergoemacs-v5.16")
+
+
+(defvar ergoemacs-command-loop--universal-functions '(universal-argument
ergoemacs-universal-argument ergoemacs-command-loop--universal-argument)
+ "List of `ergoemacs-mode' recognized functions.")
+
(defvar ergoemacs-command-loop--next-key-hash
(let ((hash (make-hash-table)))
@@ -115,6 +133,14 @@
(defvar ergoemacs-command-loop--help-last-key nil)
+(define-obsolete-variable-alias 'ergoemacs-read-key-delay
'ergoemacs-command-loop--decode-event-delay "Ergoemacs-v5.16")
+
+(defvar ergoemacs-command-loop--decode-event-delay 0.01
+ "Timeout for `ergoemacs-command-loop--decode-event'.
+This is to distinguish events in a terminal, like xterm.
+
+It needs to be less than `ergoemacs-command-loop-blink-rate'.")
+
(defvar ergoemacs-command-loop--history nil
"History of command loop locations.")
@@ -155,15 +181,163 @@ ignore the post-command hooks.")
(defvar ergoemacs-command-loop--echo-keystrokes-complete nil
"Echoed keystrokes, keep echoing active.")
-(defvar ergoemacs-command-loop-swap-translation)
+(defvar ergoemacs-command-loop--modal-stack '()
+ "The Modal Stack.")
+
+(defcustom ergoemacs-command-loop-swap-translation
+ '(((:normal :normal) :unchorded-ctl)
+ ((:normal :unchorded-ctl) :ctl-to-alt)
+ ((:normal :unchorded-ctl) :normal)
+ ((:ctl-to-alt :ctl-to-alt) :unchorded-ctl)
+ ((:ctl-to-alt :unchorded-ctl) :ctl-to-alt)
+ ((:unchorded-ctl :unchorded-ctl) :ctl-to-alt)
+ ((:unchorded-ctl :ctl-to-alt) :unchorded-ctl))
+ "How the translation will be swapped."
+ :type '(repeat
+ (list
+ (list
+ (sexp :tag "First Type")
+ (sexp :tag "Current Type"))
+ (sexp :tag "Translated Type")))
+ :group 'ergoemacs-command-loop)
+
+(defcustom ergoemacs-command-loop-blink-character (ergoemacs :unicode-or-alt
"•" "·" "-")
+ "Blink character."
+ :type '(choice
+ (string :tag "Cursor")
+ (const :tag "No cursor" nil))
+ :group 'ergoemacs-command-loop)
+
+(defcustom ergoemacs-command-loop-blink-rate 0.4
+ "Rate that the ergoemacs-command loop cursor blinks."
+ :type 'number
+ :group 'ergoemacs-command-loop)
+
+(defcustom ergoemacs-command-loop-type nil
+ "Type of `ergoemacs-mode' command loop."
+ :type '(choice
+ (const :tag "Replace emacs command loop (full)" :full)
+ ;; (const :tag "Test mode; Don't actually run command " :test)
+ (const :tag "No command loop support" nil))
+ :group 'ergoemacs-comamnd-loop)
+
+(defcustom ergoemacs-command-loop-hide-shift-translations t
+ "Hide shift translations in the command loop help."
+ :type 'boolean
+ :group 'ergoemacs-command-loop)
+
+
+(defcustom ergoemacs-command-loop-echo-keystrokes 1
+ "The amount of time before `ergoemacs-mode' displays keystrokes."
+ :type 'number
+ :group 'ergoemacs-command-loop)
+
+(defcustom ergoemacs-command-loop-timeout 2
+ "The number of seconds before hook has froze."
+ :type 'number
+ :group 'ergoemacs-command-loop)
+
+(defcustom ergoemacs-echo-function :on-translation
+ "Shows the function evaluated with a key."
+ :type '(choice
+ (const :tag "Always echo" t)
+ (const :tag "For multi-key commands" :multi-key)
+ (const :tag "Echo on translations" :on-translation)
+ (const :tag "Don't Echo" nil))
+ :group 'ergoemacs-command-loop)
+
+
+
(defvar ergoemacs-command-loop-time-before-blink)
-(defvar ergoemacs-command-loop-blink-character)
-(defvar ergoemacs-command-loop-blink-rate)
+(defvar ergoemacs-command-loop-hide-shift-translations)
(defvar ergoemacs-mode)
(defvar ergoemacs-command-loop-type)
(defvar ergoemacs-keymap)
+(defvar ergoemacs-handle-ctl-c-or-ctl-x 'only-C-c-and-C-x)
+(defvar ergoemacs-ctl-c-or-ctl-x-delay)
+(defun ergoemacs-command-loop--modal-show ()
+ "Show modal translation.
+Returns the mode-line text."
+ (let (tmp color text)
+ (ergoemacs-save-buffer-state
+ (cond
+ ((setq tmp (ergoemacs :modal-p))
+ (setq color (ergoemacs-translation-struct-modal-color tmp))
+ (if color
+ (set-cursor-color color)
+ (when ergoemacs-default-cursor-color
+ (set-cursor-color ergoemacs-default-cursor-color)))
+ (setq text (ergoemacs-translation-struct-text tmp))
+ (when (functionp text)
+ (setq text (funcall text)))
+ (if text
+ (ergoemacs-mode-line ;; Indicate Alt+ in mode-line
+ text)
+ (ergoemacs-mode-line))
+ (or text "Unnamed"))
+ (t
+ (when ergoemacs-default-cursor-color
+ (set-cursor-color ergoemacs-default-cursor-color))
+ (ergoemacs-mode-line)
+ nil)))))
+
+(defun ergoemacs-command-loop--match-buffer-name-p (reg)
+ "Determine if the REG is found in `buffer-name'."
+ (and (stringp (buffer-name))
+ (string-match reg (buffer-name))))
+
+(defun ergoemacs-command-loop--modal-p ()
+ "Determine if the command should be modal.
+If so return the translation."
+ (if (not ergoemacs-command-loop--modal-stack) nil
+ (let* ((translation (nth 0 ergoemacs-command-loop--modal-stack))
+ (always)
+ ret)
+ (when (ergoemacs-translation-struct-p translation)
+ (setq always (ergoemacs-translation-struct-modal-always translation))
+ (cond
+ ((and (minibufferp)
+ (not always)))
+ ((and (not always)
+ (memq major-mode ergoemacs-modal-emacs-state-modes)))
+ ((and (not always)
+ (catch 'match-modal
+ (dolist (reg ergoemacs-modal-ignored-buffers)
+ (when (ergoemacs-command-loop--match-buffer-name-p reg)
+ (throw 'match-modal t)))
+ nil)))
+ (t
+ (setq ret translation))))
+ ret)))
+
+(defun ergoemacs-command-loop--modal-pop ()
+ "Turn off the last ergoemacs modal in the modal-stack."
+ (when ergoemacs-command-loop--modal-stack
+ (ergoemacs-command-loop--modal (ergoemacs-translation-struct-key (nth 0
ergoemacs-command-loop--modal-stack)))))
+
+(defun ergoemacs-command-loop--modal (type)
+ "Toggle ergoemacs command modes.
+
+The TYPE is the type of command translation/modal keymaps that are installed."
+ (cond
+ ((or (not ergoemacs-command-loop--modal-stack) ;; First time to turn on
+ (not (eq (ergoemacs-translation-struct-key (nth 0
ergoemacs-command-loop--modal-stack)) type)) ;; New modal
+ )
+ (push (ergoemacs-translate--get type) ergoemacs-command-loop--modal-stack)
+ (unless ergoemacs-default-cursor-color
+ (setq ergoemacs-default-cursor-color
+ (or (frame-parameter nil 'cursor-color) "black")))
+ (ergoemacs-command-loop--message "%s command mode installed"
(ergoemacs-command-loop--modal-show)))
+
+ (t ;; Turn off.
+ (setq ergoemacs-command-loop--modal-stack (cdr
ergoemacs-command-loop--modal-stack))
+ (if (ergoemacs :modal-p)
+ (ergoemacs-command-loop--message "%s command mode resumed."
(ergoemacs-command-loop--modal-show))
+ (ergoemacs-command-loop--modal-show)
+ (ergoemacs-command-loop--message "Resume regular ergoemacs-mode")))))
+
(defun ergoemacs-command-loop--redefine-quit-key (&optional key)
"Redefines the quit-key in Emacs to KEY or Ctrl+g.
@@ -196,6 +370,65 @@ with this function."
(throw 'found-quit t)))
nil))))
+(add-hook 'ergoemacs-mode-startup-hook
#'ergoemacs-command-loop--setup-quit-key)
+(add-hook 'ergoemacs-mode-shutdown-hook
#'ergoemacs-command-loop--redefine-quit-key)
+
+(defun ergoemacs-command-loop--universal-argument (&rest _ignore)
+ "`ergoemacs-mode' universal argument.
+This is called through `ergoemacs-command-loop'"
+ (interactive)
+ (cond
+ ((not (ergoemacs-command-loop-p))
+ ;; Command loop hasn't started.
+ (setq current-prefix-arg '(4))
+ (setq ergoemacs-command-loop-start t)
+ (ergoemacs-command-loop nil (ergoemacs-command-loop--modal-p) nil t))
+ ((not current-prefix-arg)
+ (setq current-prefix-arg '(4)
+ ergoemacs-command-loop--universal t
+ ergoemacs-command-loop--exit :ignore-post-command-hook))
+ ((listp current-prefix-arg)
+ ;; Change current prefix argument
+ (setq current-prefix-arg (list (* (nth 0 current-prefix-arg) 4))
+ ergoemacs-command-loop--universal t
+ ergoemacs-command-loop--exit :ignore-post-command-hook))
+ (t
+ (setq ergoemacs-command-loop--universal t
+ ergoemacs-command-loop--exit :ignore-post-command-hook))))
+
+(defalias 'ergoemacs-read-key--universal-argument
'ergoemacs-command-loop--universal-argument)
+
+(defalias 'ergoemacs-universal-argument
'ergoemacs-command-loop--universal-argument)
+
+(defun ergoemacs-command-loop--digit-argument (&optional type)
+ "Ergoemacs digit argument.
+
+This is called through `ergoemacs-command-loop'.
+
+TYPE is the keyboard translation type, defined by `ergoemacs-translate'.
+Ergoemacs-mode sets up: :ctl-to-alt :unchorded :normal."
+ (interactive)
+ (let* ((char (if (integerp last-command-event)
+ last-command-event
+ (get last-command-event 'ascii-character)))
+ (digit (- (logand char ?\177) ?0)))
+ (setq current-prefix-arg digit))
+ (ergoemacs-command-loop nil type nil t))
+
+(defalias 'ergoemacs-digit-argument 'ergoemacs-command-loop--digit-argument)
+
+(defun ergoemacs-command-loop--negative-argument (&optional type)
+ "Ergoemacs negative argument.
+
+This is called through `ergoemacs-command-loop'.
+
+TYPE is the keyboard translation type, defined by `ergoemacs-translate'
+Ergoemacs-mode sets up: :ctl-to-alt :unchorded :normal."
+ (setq current-prefix-arg '-)
+ (ergoemacs-command-loop nil type nil t))
+
+(defalias 'ergoemacs-negative-argument
'ergoemacs-command-loop--negative-argument)
+
(dolist (arg '((next-key-is-alt (meta))
(next-key-is-meta (meta))
(next-key-is-ctl (control))
@@ -205,7 +438,7 @@ with this function."
(next-key-is-control-meta (control meta))
(next-key-is-meta-control (control meta))
(next-key-is-quoted nil)))
- (eval (macroexpand-all
+ (eval (macroexpand-all ;FIXME: Why macroexpand-all?
`(progn
(defun ,(intern (concat "ergoemacs-command-loop--" (symbol-name
(nth 0 arg)))) ()
,(format "Ergoemacs function to allow %s to be the emacs
modifiers" (nth 1 arg))
@@ -220,7 +453,8 @@ with this function."
(message "Dummy Function for %s" (ergoemacs :modifier-desc ,(nth
1 arg))))
(defalias ',(intern (concat "ergoemacs-read-key-force-"
(symbol-name (nth 0 arg)))) ',(intern (concat "ergoemacs-command-loop--force-"
(symbol-name (nth 0 arg)))))
(puthash ',(intern (concat "ergoemacs-command-loop--force-"
(symbol-name (nth 0 arg)))) '(,(nth 1 arg) :force)
ergoemacs-command-loop--next-key-hash)
- (puthash ',(intern (concat "ergoemacs-read-key-force-"
(symbol-name (nth 0 arg)))) '(,(nth 1 arg) :force)
ergoemacs-command-loop--next-key-hash)))))
+ (puthash ',(intern (concat "ergoemacs-read-key-force-"
(symbol-name (nth 0 arg)))) '(,(nth 1 arg) :force)
ergoemacs-command-loop--next-key-hash)
+ t))))
(defvar ergoemacs-last-command-event nil
"`ergoemacs-mode' command loop last read command.")
@@ -321,12 +555,12 @@ UNIVERSAL"
(and (not universal) "")
(or (and (string= ergoemacs-command-loop--read-key-prompt
"") "") " ")
(and ergoemacs-command-loop-blink-character
- (or (and blink-on
ergoemacs-command-loop-blink-character)
+ (or (and blink-on (ergoemacs :unicode-or-alt
ergoemacs-command-loop-blink-character "-"))
" "))
" ")
(or
(and (not universal) "")
- "▸")))
+ (ergoemacs :unicode-or-alt "▸" ">"))))
(format
"%s%s%s %s "
(cond
@@ -335,13 +569,25 @@ UNIVERSAL"
(t current-prefix-arg))
(or (and (not universal) "")
(and ergoemacs-command-loop-blink-character
- (or (and blink-on ergoemacs-command-loop-blink-character)
+ (or (and blink-on (ergoemacs :unicode-or-alt
ergoemacs-command-loop-blink-character "-"))
" "))
" ")
(or (and (listp current-prefix-arg)
(format "%s" current-prefix-arg))
"")
- "▸")))
+ (ergoemacs :unicode-or-alt "▸" ">"))))
+
+(defun ergoemacs-command-loop--ensure-sane-variables ()
+ "Make sure that certain variables won't lock up Emacs.
+
+Currently this ensures:
+
+`ergoemacs-command-loop--decode-event-delay' is less than
`ergoemacs-command-loop-blink-rate'."
+ (when (>= ergoemacs-command-loop--decode-event-delay
ergoemacs-command-loop-blink-rate)
+ (ergoemacs-warn "ergoemacs-command-loop--decode-event-delay >=
ergoemacs-command-loop-blink-rate; Reset to ergoemacs-command-loop-blink-rate /
1000")
+ (setq ergoemacs-command-loop--decode-event-delay (/
ergoemacs-command-loop-blink-rate 1000))))
+
+(add-hook 'ergoemacs-mode-startup-hook
#'ergoemacs-command-loop--ensure-sane-variables)
(defun ergoemacs-command-loop--combine (current-key next-event)
"Combine CURRENT-KEY and NEXT-EVENT into a vector."
@@ -409,13 +655,19 @@ This is not done when the event is [ergoemacs-ignore]"
((not (stringp prompt)))
((not (string= ""
ergoemacs-command-loop--read-key-prompt)) prompt)
((or (string= prompt " ")
- (string-match-p prompt (concat " *"
ergoemacs-command-loop-blink-character " *")))
+ (string-match-p prompt (concat " *" (ergoemacs
:unicode-or-alt ergoemacs-command-loop-blink-character "-") " *")))
nil)
(ergoemacs-command-loop--universal prompt)
(ergoemacs-command-loop--echo-keystrokes-complete prompt)
((not (numberp ergoemacs-command-loop-echo-keystrokes))
prompt)
((= 0 ergoemacs-command-loop-echo-keystrokes) prompt)
((< last-event-time
ergoemacs-command-loop-echo-keystrokes) nil)
+ ;; ((and (not
ergoemacs-command-loop--echo-keystrokes-complete)
+ ;; (numberp ergoemacs-command-loop-echo-keystrokes)
+ ;; (or (= 0 ergoemacs-command-loop-echo-keystrokes)
+ ;; (< last-event-time
ergoemacs-command-loop-echo-keystrokes))) nil)
+ ;; ((and (< last-event-time
ergoemacs-command-loop-time-before-blink) (string= prompt "")) nil)
+ ;; ((and (< last-event-time
ergoemacs-command-loop-time-before-blink) ) nil)
(t
(setq ergoemacs-command-loop--echo-keystrokes-complete t)
prompt)))
@@ -455,6 +707,120 @@ This is not done when the event is [ergoemacs-ignore]"
last-event-frame (selected-frame))))
event)))
+(defvar ergoemacs-command-loop--decode-event-timeout-p nil
+ "Determines if `ergoemacs-command-loop--decode-event' timed out.")
+
+(defun ergoemacs-command-loop--decode-event (event keymap &optional
current-key)
+ "Change EVENT based on KEYMAP.
+
+Used to help with translation keymaps like `input-decode-map'.
+
+CURRENT-KEY is the current key being read. This is used
+inconjunction with `input-method-function' to translate keys if
+`set-input-method' is using a different keyboard layout."
+ (let* ((new-event event)
+ (old-ergoemacs-input unread-command-events)
+ new-ergoemacs-input
+ (current-test-key (or (and (listp event)
+ (vector
(ergoemacs-translate--event-convert-list
+ (append
(ergoemacs-translate--event-modifiers event)
+ (list
(ergoemacs-translate--event-basic-type event))))))
+ (vector event)))
+ (test-ret (lookup-key keymap current-test-key))
+ (timeout-key (key-binding (vconcat current-test-key
[ergoemacs-timeout])))
+ next-key)
+ (while (and current-test-key
+ (ergoemacs-keymapp test-ret))
+ ;; The translation needs more keys...
+ (if timeout-key
+ (setq next-key (with-timeout (ergoemacs-ctl-c-or-ctl-x-delay
+ (progn
+ (setq
ergoemacs-command-loop--decode-event-timeout-p t)
+ nil))
+ (ergoemacs-command-loop--history nil
ergoemacs-command-loop--decode-event-delay current-key)))
+ (setq next-key (ergoemacs-command-loop--history nil
ergoemacs-command-loop--decode-event-delay current-key)))
+ (when next-key ;; Since a key was read, save it to be read later.
+ (push last-command-event new-ergoemacs-input))
+ (if next-key
+ (setq current-test-key (ergoemacs :combine current-test-key next-key)
+ timeout-key (key-binding (vconcat current-test-key
[ergoemacs-timeout]))
+ test-ret (lookup-key keymap current-test-key))
+ (setq current-test-key nil)))
+ ;; Change strings to emacs keys.
+ (when (stringp test-ret)
+ ;; Should it be read-kbd-macro?
+ (setq test-ret (vconcat test-ret)))
+ (when (functionp test-ret)
+ (when (memq test-ret '(xterm-mouse-translate
xterm-mouse-translate-extended))
+ (message "xterm-mouse-translate: %s->%s" current-test-key (funcall
test-ret nil)))
+ (setq last-input-event event
+ test-ret (if (or (eq keymap input-decode-map)
+ (eq keymap key-translation-map)
+ (eq keymap local-function-key-map))
+ (funcall test-ret nil) ;; Pretend emacs called this
from command loop.
+ (funcall test-ret)))
+ (when (not (equal unread-command-events old-ergoemacs-input))
+ (push (pop unread-command-events) new-ergoemacs-input)))
+ (if (and (vectorp test-ret)
+ (= (length test-ret) 1))
+ (progn
+ (setq new-event (elt test-ret 0)))
+ ;; Not a new event, restore anything that was popped off the
+ ;; unread command events.
+ (when old-ergoemacs-input
+ (setq unread-command-events old-ergoemacs-input))
+ ;; Add anything read to the
+ ;; unread-command-events
+ (when new-ergoemacs-input
+ (setq unread-command-events (append new-ergoemacs-input
unread-command-events))))
+ new-event))
+
+(defun ergoemacs-command-loop--read-event (prompt &optional current-key)
+ "Read a single event.
+
+PROMPT is the prompt used when reading an event.
+
+CURRENT-KEY is the current key sequence that has alerady been
+read.
+
+This respects `input-decode-map', `local-function-key-map' and
+`key-translation-map'.
+
+It also inputs real read events into the history with
+`ergoemacs-command-loop--history'
+
+It will timeout after `ergoemacs-command-loop-blink-rate' and
+return nil."
+ (let ((input (ergoemacs-command-loop--history prompt
ergoemacs-command-loop-blink-rate current-key))
+ last-input
+ basic mods
+ binding gui)
+ ;; Fix issues with `input-decode-map'
+ (when input
+ ;; Fix input as if you defined C-i -> <C-i> on `input-decode-map'
+ ;;
http://emacs.stackexchange.com/questions/10271/how-to-bind-c-for-real-seriously-for-real-this-time/15174
+ (if (and (display-graphic-p)
+ (setq basic (event-basic-type input))
+ (memq basic (list 'i 'm '\[ ?i ?m ?\[))
+ (setq mods (event-modifiers input))
+ (memq 'control mods)
+ (setq gui (ergoemacs-translate--event-convert-list (append
(list 'ergoemacs-gui) mods (list basic))))
+ (setq binding (key-binding (ergoemacs :combine current-key
input) t)))
+ (setq input gui)
+ (setq input (ergoemacs-command-loop--decode-event input
input-decode-map current-key)
+ binding (key-binding (ergoemacs :combine current-key input) t)))
+ ;; These should only be replaced if they are not bound.
+ (unless binding
+ (setq last-input input
+ input (ergoemacs-command-loop--decode-event input
local-function-key-map current-key))
+ (unless (eq last-input input)
+ (setq binding (key-binding (ergoemacs :combine current-key input)
t))))
+ (setq last-input input
+ input (ergoemacs-command-loop--decode-event input
key-translation-map current-key))
+ (unless (eq last-input input)
+ (setq binding (key-binding (ergoemacs :combine current-key input) t))))
+ input))
+
(defun ergoemacs-command-loop--key-msg (blink-on universal text current-key
unchorded trans keys)
"Key message.
@@ -482,7 +848,7 @@ KEYS is the keys information"
(or (and (string= ergoemacs-command-loop--read-key-prompt "") "") " ")
(or (and universal "")
(and ergoemacs-command-loop-blink-character
- (or (and blink-on ergoemacs-command-loop-blink-character)
+ (or (and blink-on (ergoemacs :unicode-or-alt
ergoemacs-command-loop-blink-character "-"))
" "))
" ")
trans
@@ -495,6 +861,308 @@ KEYS is the keys information"
(defvar ergoemacs-command--timeout-timer nil)
(defvar ergoemacs-command--timeout-keys nil)
+(defun ergoemacs-command--timer-timeout ()
+ "Send the [ergoemacs-timeout] event (after timeout)."
+ (let ((keys (this-single-command-keys)))
+ (when ergoemacs-command--timeout-timer
+ (cancel-timer ergoemacs-command--timeout-timer)
+ (setq ergoemacs-command--timeout-timer nil)
+ (when (equal keys ergoemacs-command--timeout-keys)
+ (push 'ergoemacs-timeout unread-command-events))
+ (setq ergoemacs-command--timeout-keys nil))))
+
+(defvar ergoemacs-this-command-keys-shift-translated nil
+ "ergoemacs override of shift translation in command loop.")
+
+(defun ergoemacs-command--echo-prefix ()
+ "Echos prefix keys in the ergoemacs-mode way."
+ (let ((keys (this-single-command-keys)))
+ (when (and ergoemacs-command--timeout-timer
+ (not (equal keys ergoemacs-command--timeout-keys)))
+ (cancel-timer ergoemacs-command--timeout-timer)
+ (setq ergoemacs-command--timeout-keys nil
+ ergoemacs-command--timeout-timer nil))
+ (unless (or (equal [] keys)
+ (ergoemacs-command-loop-p))
+ (when (ergoemacs-keymapp (key-binding keys))
+ (when (key-binding (vconcat keys [ergoemacs-timeout]))
+ (cond
+ ((eq ergoemacs-handle-ctl-c-or-ctl-x 'only-copy-cut)
+ (push 'ergoemacs-timeout unread-command-events))
+ ((not (region-active-p))) ;; active
+ ((and (or ergoemacs-this-command-keys-shift-translated
this-command-keys-shift-translated)
+ (eq ergoemacs-handle-ctl-c-or-ctl-x 'both)))
+ ((and (not ergoemacs-ctl-c-or-ctl-x-delay) ;; Immediate
+ (eq ergoemacs-handle-ctl-c-or-ctl-x 'both))
+ (push 'ergoemacs-timeout unread-command-events))
+ (t
+ (setq ergoemacs-command--timeout-keys keys
+ ergoemacs-command--timeout-timer
+ (run-at-time t ergoemacs-ctl-c-or-ctl-x-delay
#'ergoemacs-command--timer-timeout)))))
+ (unless unread-command-events
+ (ergoemacs-command-loop--message
+ "%s" (ergoemacs-command-loop--key-msg
+ (setq ergoemacs-command--blink-on (not
ergoemacs-command--blink-on))
+ nil nil
+ (this-single-command-keys)
+ nil nil nil)))))))
+
+(defun ergoemacs-command--echo-timer ()
+ "Echo the keystrokes in the `ergoemacs-mode' way."
+ (when (and (not ergoemacs-command-loop-type)
+ (not erogemacs-command--echo-timer))
+ (unless ergoemacs-orig-echo-keystrokes
+ (setq ergoemacs-orig-echo-keystrokes echo-keystrokes))
+ (setq echo-keystrokes 0)
+ (setq erogemacs-command--echo-timer
+ (run-at-time t ergoemacs-command-loop-blink-rate
#'ergoemacs-command--echo-prefix))))
+
+(defun ergoemacs-command--echo-timer-off ()
+ "Turn off the timer."
+ (setq echo-keystrokes ergoemacs-orig-echo-keystrokes)
+ (when erogemacs-command--echo-timer
+ (cancel-timer erogemacs-command--echo-timer)))
+
+(add-hook 'ergoemacs-post-command-hook #'ergoemacs-command--echo-timer)
+(add-hook 'ergoemacs-shutdown-hook #'ergoemacs-command--echo-timer-off)
+
+(defun ergoemacs-command-loop--read-key (&optional current-key type universal)
+ "Read a key for the `ergoemacs-mode' command loop.
+
+This uses `ergoemacs-command-loop--read-event'.
+
+CURRENT-KEY is the current key that is being read, the next key
+read will be appended to this key.
+
+TYPE is the type of translation being applied. By default,
+the :normal traslation is used.
+
+UNIVERSAL flag telss if this is a univeral argument that is being
+read."
+ (let* ((universal universal)
+ (type (or type :normal))
+ (translation (ergoemacs-translate--get type))
+ (local-keymap (ergoemacs-translate--keymap translation))
+ (text (ergoemacs-translation-struct-text translation))
+ (unchorded (ergoemacs-translation-struct-unchorded translation))
+ (trans (ergoemacs-translation-struct-translation translation))
+ (modal (ergoemacs :modal-p))
+ (keys nil)
+ (blink-on nil)
+ input
+ raw-input
+ mod-keys tmp
+ reset-key-p
+ double)
+ ;; Setup modal translation
+ (when (and (eq type :normal) modal)
+ (setq type (ergoemacs-translation-struct-key modal)
+ local-keymap (ergoemacs-translation-struct-keymap-modal modal)
+ text (ergoemacs-translation-struct-text modal)
+ unchorded (ergoemacs-translation-struct-unchorded modal)
+ trans (ergoemacs-translation-struct-translation modal)
+ tmp translation
+ translation modal
+ modal tmp
+ tmp nil))
+
+ ;; (ergoemacs-command-loop--read-key (read-kbd-macro "C-x" t)
:unchorded-ctl)
+ (when (functionp text)
+ (setq text (funcall text)))
+
+ (when trans
+ ;; Don't echo the uncommon hyper/super/alt translations (alt is
+ ;; not the alt key...)
+ (dolist (tr trans)
+ (unless (or (memq 'hyper (nth 0 tr)) (memq 'super (nth 0 tr)) (memq
'alt (nth 0 tr))
+ (and ergoemacs-command-loop-hide-shift-translations (memq
'shift (nth 0 tr))))
+ (if (member (list (nth 1 tr) (nth 0 tr)) trans)
+ (when (not (member (list (nth 1 tr) (nth 0 tr)) double))
+ (push tr double))
+ (push tr tmp))))
+ (setq trans tmp))
+
+ (setq trans (or (and (or trans double)
+ (concat "\nTranslations: "
+ (or (and double
+ (mapconcat
+ (lambda(elt)
+ ;; (and (setq tmp (elt current-key
0))
+ ;; (or (and (consp tmp)
(symbolp (setq tmp (car tmp)))))
+ ;; (stringp tmp)
+ ;; (string-match-p
"\\<mouse\\>" tmp))
+ (format "%s%s%s"
+ (ergoemacs :modifier-desc
(nth 0 elt))
+ (ergoemacs
:unicode-or-alt "↔" "<->")
+ (ergoemacs :modifier-desc
(nth 1 elt))))
+ double ", "))
+ "")
+ (or (and double trans ", ") "")
+ (mapconcat
+ (lambda(elt)
+ (format "%s%s%s"
+ (ergoemacs :modifier-desc (nth 0
elt))
+ (ergoemacs :unicode-or-alt "→"
"->")
+ (ergoemacs :modifier-desc (nth 1
elt))))
+ trans ", "))) ""))
+ (maphash
+ (lambda(key item)
+ (let ((local-key (where-is-internal key local-keymap t))
+ tmp)
+ (when local-key
+ (setq tmp (format "%s%s%s"
+ (ergoemacs-key-description local-key)
+ (if (eq (nth 1 item) :force)
+ (ergoemacs :unicode-or-alt "⇒" "=>")
+ (ergoemacs :unicode-or-alt "→" "->"))
+ (ergoemacs :modifier-desc (nth 0 item))))
+ (push (elt local-key 0) mod-keys)
+ (setq keys (or (and (not keys) tmp)
+ (and keys (concat keys ", " tmp)))))))
+ ergoemacs-command-loop--next-key-hash)
+
+ (setq keys (or (and keys (concat "\nKeys: " keys)) ""))
+ (setq unchorded (or (and unchorded (concat " " (ergoemacs :modifier-desc
unchorded))) ""))
+
+ (while (not input)
+ (while (not input)
+ (setq blink-on (not blink-on)
+ input (ergoemacs-command-loop--read-event
+ (ergoemacs-command-loop--key-msg blink-on universal text
current-key unchorded trans keys)
+ current-key)))
+ (cond
+ ((and (setq trans (or (and (memq input mod-keys)
+ (ergoemacs-gethash (lookup-key local-keymap
(vector input)) ergoemacs-command-loop--next-key-hash))
+ (setq reset-key-p (ergoemacs-gethash (lookup-key
local-function-key-map (ergoemacs :combine current-key input))
ergoemacs-command-loop--next-key-hash))))
+ (or (eq :force (nth 1 trans)) ;; Override any keys
+ (not (key-binding (vconcat current-key
(ergoemacs-translate--event-mods input trans)) t)) ;; Don't use if bound.
+ ))
+ (setq trans (nth 0 trans)
+ unchorded (concat " " (ergoemacs :modifier-desc trans))
+ input nil)
+ ;; Changed behavior.
+ (while (not input)
+ (setq blink-on (not blink-on)
+ input (ergoemacs-command-loop--read-event
+ (ergoemacs-command-loop--key-msg blink-on universal text
current-key unchorded trans keys)
+ current-key)))
+ (setq raw-input input
+ input (ergoemacs-translate--event-mods input trans)
+ last-command-event input
+ last-input-event input
+ ergoemacs-last-command-event last-command-event))
+ (t
+ ;; Translate the key appropriately.
+ (when (and modal (lookup-key ergoemacs-modal-ignored-keymap (vector
input)))
+ ;; Swap back, or ignore the modal translation.
+ (setq type (ergoemacs-translation-struct-key modal)
+ local-keymap (ergoemacs-translation-struct-keymap-modal modal)
+ text (ergoemacs-translation-struct-text modal)
+ unchorded (ergoemacs-translation-struct-unchorded modal)
+ trans (ergoemacs-translation-struct-translation modal)
+ tmp translation
+ translation modal
+ modal tmp
+ tmp nil))
+ (setq raw-input input
+ input (ergoemacs-translate--event-mods input type)
+ last-command-event input
+ last-input-event input
+ ergoemacs-last-command-event last-command-event)))
+ (cond
+ ((and input (not universal)
+ (not (key-binding (ergoemacs :combine current-key raw-input)))
+ (and local-keymap
+ (memq (lookup-key local-keymap (vector raw-input))
+ ergoemacs-command-loop--universal-functions)))
+ (setq universal t
+ raw-input nil
+ input nil
+ ergoemacs-command-loop--echo-keystrokes-complete t))
+ ((and raw-input universal) ;; Handle universal arguments.
+ (setq ergoemacs-command-loop--echo-keystrokes-complete t)
+ (cond
+ ((eq raw-input 45) ;; Negative argument
+ (cond
+ ((integerp current-prefix-arg)
+ (setq current-prefix-arg (- current-prefix-arg)))
+ ((eq current-prefix-arg '-)
+ (setq current-prefix-arg nil))
+ (t
+ (setq current-prefix-arg '-)))
+ (setq raw-input nil
+ input nil))
+ ((memq raw-input (number-sequence 48 57)) ;; Number
+ (setq raw-input (- raw-input 48)) ;; Actual Number.
+ (cond
+ ((and (integerp current-prefix-arg) (< 0 current-prefix-arg))
+ (setq current-prefix-arg (+ raw-input (* current-prefix-arg 10))))
+ ((and (integerp current-prefix-arg) (> 0 current-prefix-arg))
+ (setq current-prefix-arg (+ (- raw-input) (* current-prefix-arg
10))))
+ ((and (eq current-prefix-arg '-) (> raw-input 0))
+ (setq current-prefix-arg (- raw-input)))
+ (t
+ (setq current-prefix-arg raw-input)))
+ (setq input nil
+ raw-input nil))
+ ((and local-keymap
+ (memq (lookup-key local-keymap (vector raw-input))
+ ergoemacs-command-loop--universal-functions)) ;; Toggle
to key-sequence.
+ (setq raw-input nil
+ universal nil))
+ ((or (memq (key-binding (ergoemacs :combine current-key input) t)
ergoemacs-command-loop--universal-functions)
+ (not (key-binding (ergoemacs :combine current-key raw-input) t))
+ (and local-keymap (memq (lookup-key local-keymap (vector
raw-input)) ergoemacs-command-loop--universal-functions)))
+ ;; Universal argument called.
+ (cond
+ ((not current-prefix-arg)
+ (setq current-prefix-arg '(4)
+ raw-input nil
+ input nil))
+ ((listp current-prefix-arg)
+ (setq current-prefix-arg (list (* (nth 0 current-prefix-arg) 4))
+ raw-input nil
+ input nil))
+ (t
+ (setq universal nil
+ input nil
+ raw-input nil))))
+ ((and local-keymap
+ (memq (lookup-key local-keymap (vector raw-input))
+ ergoemacs-command-loop--undo-functions))
+ ;; Allow backspace to edit universal arguments.
+ (cond
+ ((not current-prefix-arg)) ;; Exit universal argument
+ ((and (integerp current-prefix-arg)
+ (= 0 (truncate current-prefix-arg 10))
+ (< 0 current-prefix-arg))
+ (setq current-prefix-arg nil
+ input nil
+ raw-input nil))
+ ((and (integerp current-prefix-arg)
+ (= 0 (truncate current-prefix-arg 10))
+ (> 0 current-prefix-arg))
+ (setq current-prefix-arg '-
+ input nil
+ raw-input nil))
+ ((integerp current-prefix-arg)
+ (setq current-prefix-arg (truncate current-prefix-arg 10)
+ input nil
+ raw-input nil))
+ ((listp current-prefix-arg)
+ (setq current-prefix-arg
+ (list (expt 4 (- (round (log (nth 0 current-prefix-arg) 4))
1))))
+ (when (equal current-prefix-arg '(1))
+ (setq current-prefix-arg nil))
+ (setq input nil
+ raw-input nil))
+ ((eq current-prefix-arg '-)
+ (setq current-prefix-arg nil
+ input nil
+ raw-input nil))))))))
+ ;; Return list of raw key, and translated current key
+ (list (vector raw-input) (ergoemacs :combine (if reset-key-p nil
current-key) input))))
+
(defun ergoemacs-command-loop--listify-key-sequence (key &optional type)
"Return a key sequence from KEY.
@@ -517,11 +1185,132 @@ This sequence is compatible with
`listify-key-sequence'."
input))
input))
+(defun ergoemacs-command-loop-p ()
+ "Determine if `ergoemacs-mode' is running its command loop.
+This is done by looking at the current `backtrace' and making
+sure that `ergoemacs-command-loop--internal' hasn't been called."
+ (eq (symbol-function 'this-command-keys)
#'ergoemacs-command-loop--this-command-keys))
+
+(defvar ergoemacs-command-loop-start nil)
+(defun ergoemacs-command-loop (&optional key type initial-key-type universal
initial-history)
+ "Process `ergoemacs-command-loop'.
+
+KEY is the key being read, or sequence being read.
+
+TYPE is the translation being used.
+
+INITIAL-KEY-TYPE ist he key type that is used fot the initial
+translation.
+
+UNIVERSAL is if the function will be calling a universal
+argument.
+
+INITIAL-HISTORY is the initial history list.
+
+The true work is done in `ergoemacs-command-loop--internal'."
+ (interactive)
+ (cond
+ ((and (or ergoemacs-command-loop-start key) (not
(ergoemacs-command-loop-p)))
+ ;; (ergoemacs-command-loop--message "Start ergoemacs-mode command loop." )
+ (ergoemacs-command-loop--internal key type initial-key-type universal
initial-history))
+ (t
+ (setq ergoemacs-command-loop--exit :ignore-post-command-hook
+ prefix-arg current-prefix-arg
+ ergoemacs-command-loop--single-command-keys (or (and key
(read-kbd-macro key t))
+
ergoemacs-command-loop--single-command-keys)
+ unread-command-events (or (and key
(ergoemacs-command-loop--listify-key-sequence key initial-key-type))
+ unread-command-events)
+ ergoemacs-command-loop--universal (if (and
ergoemacs-command-loop--universal (not universal)) nil
+ universal)
+ ergoemacs-command-loop--current-type (or type
ergoemacs-command-loop--current-type)
+ ergoemacs-command-loop--history (or initial-history
ergoemacs-command-loop--history)))))
+
+(defvar ergoemacs-command-loop--running-pre-command-hook-p nil
+ "Variable to tell if ergoemacs-command loop is running the
`pre-command-hook'.")
+
+(defvar ergoemacs-command-loop--excluded-variables
+ '(defining-kbd-macro executing-kbd-macro)
+ "List of variables stopping the command loop.
+
+While these variables are non-nil, the `ergoemacs-command-loop'
+will stop and not be started agin.")
+
+(defvar ergoemacs-command-loop--excluded-major-modes
+ '(calc-mode calc-trail-mode calc-edit-mode)
+ "List of major modes where the command loop is incompatible.")
+
+
(defvar ergoemacs-command-loop--minibuffer-unsupported-p nil)
+(defun ergoemacs-command-loop--minibuffer-supported-p (&optional command)
+ "Determine if the current minibuffer supports the full command loop.
+When COMMAND is non-nil, set
+`ergoemacs-command-loop--minibuffer-unsupported-p' to the
+appropriate value based on the COMMAND."
+ (if (not command)
+ (or (not (minibufferp))
+ (not ergoemacs-command-loop--minibuffer-unsupported-p))
+ (when (or (and command (symbolp command) (string-match-p
"^\\(calc\\|math\\)" (symbol-name command)))
+ (and (stringp command) (string-match-p "^[^:]*:\\(calc\\|math\\)"
command)))
+ (ergoemacs-save-buffer-state
+ (set (make-local-variable
'ergoemacs-command-loop--minibuffer-unsupported-p) t)))
+ (ergoemacs-command-loop--minibuffer-supported-p)))
+
+(defun ergoemacs-command-loop-full-p (&optional type)
+ "Determines if the full command loop should be run.
+
+
+TYPE is the type of command loop to check for. By default this
+is the :full command loop."
+ (and
+ (or (eq ergoemacs-command-loop-type (or type :full)) (ergoemacs :modal-p))
+ (ergoemacs-command-loop--minibuffer-supported-p)
+ (catch 'excluded-variables
+ (dolist (var ergoemacs-command-loop--excluded-variables)
+ (when (and var (ergoemacs-sv var))
+ (throw 'excluded-variables nil)))
+ t)
+ (not (memq major-mode ergoemacs-command-loop--excluded-major-modes))))
+
+(defun ergoemacs-command-loop--start-with-pre-command-hook ()
+ "Start ergoemacs command loop.
+
+This is done by replacing `this-command' with
+`ergoemacs-command-loop-start' and then running `this-command'
+from within the ergoemacs-mode command loop."
+ (when (and (not ergoemacs-command-loop--running-pre-command-hook-p)
+ (ergoemacs-command-loop-full-p)
+ (not unread-command-events)
+ (not (ergoemacs-command-loop-p)))
+ (setq ergoemacs-command-loop-start this-command
+ ergoemacs-command-loop--single-command-keys
(this-single-command-keys)
+ this-command 'ergoemacs-command-loop-start)))
+
+(add-hook 'ergoemacs-pre-command-hook
#'ergoemacs-command-loop--start-with-pre-command-hook)
+
+
+(defvar ergoemacs-command-loop--internal-end-command-p nil)
(defvar ergoemacs-last-command-was-ergoemacs-ignore-p nil
"Last command was `ergoemacs-ignore'.")
+(defun ergoemacs-command-loop--start-with-post-command-hook ()
+ "Start ergoemacs command loop.
+
+This is done by pushing the key [ergoemacs-ignore] on the
+`unread-command-events' stack. This then forces `ergoemacs-mode'
+to start with
+`ergoemacs-command-loop--start-with-pre-command-hook'."
+ (when (and (not ergoemacs-command-loop--internal-end-command-p)
+ (ergoemacs-command-loop-full-p))
+ (if ergoemacs-last-command-was-ergoemacs-ignore-p
+ (unless (eq ergoemacs-last-command-was-ergoemacs-ignore-p :idle)
+ (run-with-idle-timer 0.05 nil (lambda()
+ (setq
ergoemacs-last-command-was-ergoemacs-ignore-p :idle)
+ (ergoemacs-command-loop-start))))
+ (push 'ergoemacs-ignore unread-command-events))))
+
+(add-hook 'ergoemacs-post-command-hook
#'ergoemacs-command-loop--start-with-post-command-hook)
+
(defvar ergoemacs-command-loop--point-motion-last-point nil
"Record the last point.")
@@ -557,6 +1346,79 @@ Fix this issue."
(ignore-errors (switch-to-buffer (window-buffer) t t))
(goto-char (window-point))))
+(defun ergoemacs-command-loop--update-primary-selection ()
+ "Update primary clipboard in X based systems."
+ (when (and mouse-drag-copy-region
+ (eventp last-command-event)
+ (consp last-command-event)
+ (memq (event-basic-type (car last-command-event))
+ '(mouse-1))
+ (region-active-p))
+ (ergoemacs :set-selection 'PRIMARY (buffer-substring-no-properties
(region-beginning) (region-end)))))
+
+(defun ergoemacs-command-loop--internal-end-command ()
+ "Simulates the end of a command."
+ ;; Simulate the end of an emacs command, since we are not
+ ;; exiting the loop.
+ (setq ergoemacs-command-loop--internal-end-command-p t)
+ (unwind-protect
+ (run-hooks 'post-command-hook)
+ (setq ergoemacs-command-loop--internal-end-command-p nil))
+
+ ;; Deactivate mark.
+ (when deactivate-mark
+ (deactivate-mark)
+ (setq deactivate-mark nil))
+
+ ;; Create undo-boundary like emacs does.
+
+ ;; The undo boundary is created every 20 characters.
+ (when (eq this-command 'self-insert-command)
+ ;; Adapted from `org-self-insert-command'
+ (if (not (eq last-command 'self-insert-command))
+ (setq ergoemacs-command-loop--self-insert-command-count 1)
+ (if (>= ergoemacs-command-loop--self-insert-command-count 20)
+ (setq ergoemacs-command-loop--self-insert-command-count 1)
+ (and (> ergoemacs-command-loop--self-insert-command-count 0)
+ buffer-undo-list (listp buffer-undo-list)
+ (not (cadr buffer-undo-list)) ; remove nil entry
+ (setcdr buffer-undo-list (cddr buffer-undo-list)))
+ (setq ergoemacs-command-loop--self-insert-command-count
+ (1+ ergoemacs-command-loop--self-insert-command-count))))
+ ;; See:
http://stackoverflow.com/questions/6590889/how-emacs-determines-a-unit-of-work-to-undo
+
+ ;; FIXME:
+ ;; Certain "hairy" insertions (as determined by
+ ;; internal_self_insert) cause an an undo boundary to be added
+ ;; immediately, and the character count to be reset. Reading the
+ ;; code, it looks as though these are: (1) in overwrite-mode, if you
+ ;; overwrote a character with one that has a different width,
+ ;; e.g. typing over a tab; (2) if the character you inserted caused
+ ;; an abbreviation to be expanded; (3) if the character you typed
+ ;; caused auto-fill-mode to insert indentation.
+ )
+
+ ;; After executing, the emacs loop should copy `this-command' into
+ ;; `last-command'.
+ ;; It should also change `last-prefix-arg'
+ (setq last-command this-command
+ real-last-command this-command ;; Hopefully doesn't throw an error.
+ last-prefix-arg prefix-arg
+ current-prefix-arg prefix-arg
+ prefix-arg nil
+ this-command nil
+ deactivate-mark nil
+ ergoemacs-command-loop--echo-keystrokes-complete nil)
+
+ (undo-boundary)
+ ;; This (sort of) fixes `this-command-keys'
+ ;; But it doesn't fix it for keyboard macros.
+ (clear-this-command-keys t)
+ (setq ergoemacs-command-loop--decode-event-timeout-p nil)
+ (ergoemacs-command-loop--sync-point)
+ (ergoemacs-command-loop--point-motion-hooks)
+ (ergoemacs-command-loop--update-primary-selection))
+
(defun ergoemacs-command-loop--mouse-command-drop-first (args &optional
fn-arg-p)
"Internal function for processing mouse commands.
@@ -609,6 +1471,68 @@ FN-ARG-P can be nil, :drop-rest or :rest"
(push a ret)))
(reverse ret))))))
+(defun ergoemacs-command-loop--modify-mouse-command (command)
+ "Modify mouse COMMAND to work with ergoemacs command loop."
+ (let* ((iform (interactive-form command))
+ (form (and iform (consp iform) (= 2 (length iform)) (stringp (nth 1
iform)) (nth 1 iform)))
+ (args (help-function-arglist command t))
+ (fn-args (ergoemacs-command-loop--mouse-command-drop-first args t))
+ (strip-args (ergoemacs-command-loop--mouse-command-drop-first args))
+ (rest-p (ergoemacs-command-loop--mouse-command-drop-first args :rest))
+ (drop-rest (ergoemacs-command-loop--mouse-command-drop-first args
:drop-rest))
+ (select-window-p (and (stringp form) (string-match-p "^[*^]*[@]"
form)))
+ (event-p (and (stringp form) (string-match-p "^[*@^]*e" form)))
+ (new-form (and form
+ (or (and (not event-p) form)
+ (and event-p (replace-regexp-in-string
"^\\([*@^]*\\)e\n*\\(.*\\)" "\\1\\2" form))))))
+ (when (and new-form (string= new-form ""))
+ (setq new-form nil))
+ (cond
+ ((not event-p)
+ command)
+ (rest-p
+ `(lambda ,fn-args
+ ,(if new-form
+ `(interactive ,new-form)
+ `(interactive))
+ ,(when select-window-p
+ '(select-window (posn-window (event-start last-command-event))))
+ (ergoemacs-command-loop--execute-modify-command-list ',command)
+ (if ,rest-p
+ (apply ',command last-command-event ,@strip-args)
+ (,command last-command-event ,@drop-rest))))
+
+ ((not rest-p)
+ `(lambda ,fn-args
+ ,(if new-form
+ `(interactive ,new-form)
+ `(interactive))
+ ,(when select-window-p
+ '(select-window (posn-window (event-start last-command-event))))
+ (ergoemacs-command-loop--execute-modify-command-list ',command)
+ (,command last-command-event ,@strip-args))))))
+
+(defun ergoemacs-command-loop--call-mouse-command (command &optional
record-flag keys)
+ "Call a possible mouse COMMAND.
+
+The COMMAND is modified to take out any event information and
+replace it with `last-event-command' information. This
+modifciation isd one by
+`ergoemacs-command-loop--modify-mouse-command'.
+
+Mouse commands are also wrapped in `ignore-errors'. This takes
+care of `window-live-p' errors that occur when running the
+Emacs detects keys when outside of Emacs.
+
+The RECORD-FLAG and KEYS arguments are passed to
+`ergoemacs-command-loop--grow-interactive' for the mouse command."
+ (cond
+ ((ergoemacs-keymapp command)
+ (popup-menu command nil current-prefix-arg))
+ (t
+ (ignore-errors
+ (call-interactively (ergoemacs-command-loop--modify-mouse-command
command) record-flag keys)))))
+
(defvar ergoemacs-command-loop-describe-key-functions
'(describe-key describe-function)
"Functions like `describe-key'.
@@ -616,6 +1540,124 @@ These functions will:
- Replace `key-description' with `ergoemacs-key-description'.
- Replace `read-key-sequence' with
`ergoemacs-command-loop--read-key-sequence'.")
+(defcustom ergoemacs-comand-loop-grow-max-sizes-p t
+ "Grow the max sizes if needed.
+This grows `max-specpdl-size' and `max-lisp-eval-depth' if
+`ergoemacs-command-loop--call-interactively' throws an error
+about `max-specpdl-size' or `max-lisp-eval-depth'.
+
+The overall maximum that these are set to are controlled by
+`ergoemacs-max-specpdl-size' and
+`ergoemacs-max-lisp-eval-depth.'"
+ :type 'boolean
+ :group 'ergoemacs-mode)
+
+(defvar ergoemacs-command-loop--grow-command nil)
+(defvar ergoemacs-command-loop--grow-record nil)
+(defvar ergoemacs-command-loop--grow-keys nil)
+(defvar ergoemacs-command-loop--grow-special nil)
+
+
+(defcustom ergoemacs-max-specpdl-size (* 8 max-specpdl-size)
+ "Maximum `max-specpdl-size' that `ergoemacs-mode' increases to..."
+ :type 'boolean
+ :group 'ergoemacs-mode)
+
+(defcustom ergoemacs-max-lisp-eval-depth (* 8 max-lisp-eval-depth)
+ "Maximum `max-lisp-eval-depth' that `ergoemacs-mode' increases to..."
+ :type 'boolean
+ :group 'ergoemacs-mode)
+
+(defcustom ergoemacs-command-loop-dont-grow-commands
+ '(org-agenda)
+ "List of commands where the command loop will not adjust sizes."
+ :type '(repeat (sexp :tag "Command"))
+ :group 'ergoemacs-mode)
+
+(defun ergoemacs-command-loop--grow-interactive (command &optional record-flag
keys)
+ "Call the COMMAND interactively.
+The RECORD-FLAG and KEYS are sent to `ergoemacs--real-call-interactively'.
+
+This will grow `max-lisp-eval-depth' and `max-specpdl-size' if
+needed (and resotre them to the original values)."
+ (setq ergoemacs-command-loop--grow-command nil
+ ergoemacs-command-loop--grow-record nil
+ ergoemacs-command-loop--grow-keys nil
+ ergoemacs-command-loop--grow-special nil)
+ (if (memq command ergoemacs-command-loop-dont-grow-commands)
+ (call-interactively command record-flag keys)
+ (let ((grow-max-lisp-p t)
+ (orig-max-specpdl-size max-specpdl-size)
+ (orig-max-lisp-eval-depth max-lisp-eval-depth))
+ (while grow-max-lisp-p
+ (condition-case err
+ (cond
+ (ergoemacs-command-loop--grow-command
+ (command-execute ergoemacs-command-loop--grow-command
+ ergoemacs-command-loop--grow-record
+ ergoemacs-command-loop--grow-keys
+ ergoemacs-command-loop--grow-special)
+ (setq grow-max-lisp-p nil))
+ (t
+ (call-interactively command record-flag keys)
+ (setq grow-max-lisp-p nil)))
+ (error
+ (if (and (consp err)
+ (eq (car err) 'error)
+ (stringp (nth 1 err))
+ (string-match "max-specpdl-size\\|max-lisp-eval-depth"
+ (nth 1 err))
+ ergoemacs-comand-loop-grow-max-sizes-p
+ (<= max-specpdl-size ergoemacs-max-specpdl-size)
+ (<= max-lisp-eval-depth ergoemacs-max-lisp-eval-depth))
+ (progn
+ (setq max-specpdl-size (* 2 max-specpdl-size)
+ max-lisp-eval-depth (* 2 max-lisp-eval-depth))
+ (ergoemacs-warn "Increased max-specpdl-size to %s and
max-lisp-eval-depth to %s for %s"
+ max-specpdl-size max-lisp-eval-depth command))
+ (setq grow-max-lisp-p nil
+ max-specpdl-size orig-max-specpdl-size
+ max-lisp-eval-depth orig-max-lisp-eval-depth)
+ (if (and err (consp err))
+ (signal (car err) (cdr err))
+ (signal err "Unknown error"))))))
+ (setq max-specpdl-size orig-max-specpdl-size
+ max-lisp-eval-depth orig-max-lisp-eval-depth))))
+
+
+(defun ergoemacs-command-loop--call-interactively (command &optional
record-flag keys)
+ "Call the COMMAND interactively. Also handle mouse events (if possible.)
+The RECORD-FLAG and KEYS are sent to
`ergoemacs-command-loop--grow-interactive'."
+ (ergoemacs-command-loop--sync-point)
+ (setq ergoemacs-last-command-was-ergoemacs-ignore-p nil
+ this-command-keys-shift-translated (or
ergoemacs-this-command-keys-shift-translated
this-command-keys-shift-translated))
+ (cond
+ ((and (eventp last-command-event)
+ (consp last-command-event)
+ (memq (event-basic-type (car last-command-event))
+ '(mouse-1 mouse-2 mouse-3 mouse-4 mouse-5 mouse-6 mouse-7
mouse-8 mouse-9)))
+ (ergoemacs-command-loop--call-mouse-command command record-flag keys))
+ ((and (symbolp command) (not (fboundp command)))
+ (ergoemacs-command-loop--message "Command `%s' is not found" command))
+ ((and (symbolp command) (not (commandp command)))
+ (ergoemacs-command-loop--message "Command `%s' cannot be called from a
key" command))
+ ((and (consp ergoemacs-command-loop-describe-key-functions)
+ (memq command ergoemacs-command-loop-describe-key-functions))
+ (ergoemacs-specials
+ (ergoemacs-command-loop--grow-interactive command record-flag keys)))
+ (t
+ (ergoemacs-command-loop--grow-interactive command record-flag keys)))
+ (setq ergoemacs-this-command-keys-shift-translated nil))
+
+
+(defun ergoemacs-command-loop-start ()
+ "Start `ergoemacs-command-loop'."
+ (interactive)
+ ;; Should work...
+ (unless ergoemacs-command-loop-start
+ (setq ergoemacs-command-loop-start t))
+ (ergoemacs-command-loop))
+
(defvar ergoemacs-command-loop--spinner nil)
(defvar ergoemacs-command-loop--spinner-i nil)
(defvar ergoemacs-command-loop--spinner-list nil)
@@ -676,7 +1718,7 @@ instead of `format'."
(when (eq ergoemacs-message-level
ergoemacs-command-loop--spinner-display)
(let* ((string (or (and (listp string)
(eq (car string) 'quote)
- (eval string))
+ (cadr string))
string))
(rest (or (and (listp string)
(concat " " (apply #'format (apply
#'ergoemacs-key-description--unicode-char string) args)))
@@ -686,10 +1728,12 @@ instead of `format'."
(when (not ergoemacs-command-loop--spinner-list)
(setq ergoemacs-command-loop--spinner-list (nth 1 (assoc
ergoemacs-command-loop-spinner ergoemacs-command-loop-spinners))
ergoemacs-command-loop--spinner-i 0))
- (ergoemacs-command-loop--message "%s%s" (nth (mod (setq
ergoemacs-command-loop--spinner-i (+ 1 ergoemacs-command-loop--spinner-i))
- (length
ergoemacs-command-loop--spinner-list))
-
ergoemacs-command-loop--spinner-list)
- rest))))))
+ (ergoemacs-command-loop--message
+ "%s%s" (nth (mod (setq ergoemacs-command-loop--spinner-i
+ (+ 1 ergoemacs-command-loop--spinner-i))
+ (length ergoemacs-command-loop--spinner-list))
+ ergoemacs-command-loop--spinner-list)
+ rest))))))
(defun ergoemacs-command-loop--spinner-end ()
"Cancel the `ergoemacs-command-loop--spinner' timer."
@@ -714,6 +1758,28 @@ They don't exactly behave like their Emacs equivalents."
(or (and ergoemacs-mode ergoemacs-command-loop--single-command-keys)
(funcall ergoemacs-command-loop--this-command-keys)))
+(defvar ergoemacs-command-loop--timer nil
+ "Timer to startup `ergoemacs-mode' command loop.")
+(defun ergoemacs-command-loop--timer ()
+ "Start `ergoemacs-command-loop--internal' if not currently running."
+ (unless (and (ergoemacs-command-loop-full-p)
+ (ergoemacs-command-loop-p))
+ (ergoemacs-command-loop--internal)))
+
+(defun ergoemacs-command-loop--install-timer ()
+ "Install the `ergoemacs-command-loop--timer'."
+ (setq ergoemacs-command-loop--timer
+ (run-with-idle-timer 0.05 nil #'ergoemacs-command-loop--timer)))
+
+(defun ergoemacs-command-loop--remove-timer ()
+ "Remove `ergoemacs-command-loop--timer'."
+ (when ergoemacs-command-loop--timer
+ (cancel-timer ergoemacs-command-loop--timer)
+ (setq ergoemacs-command-loop--timer nil)))
+
+(add-hook 'ergoemacs-mode-startup-hook #'ergoemacs-command-loop--install-timer)
+(add-hook 'ergoemacs-mode-shutdown-hook #'ergoemacs-command-loop--remove-timer)
+
(defun ergoemacs-command-loop--ignore (&rest _ignore)
"Do nothing and return nil.
@@ -727,6 +1793,227 @@ run, by changing `this-command' to `last-command'"
;; FIXME: Somehow change the output of `this-single-command-raw-keys'
nil)
+(defun ergoemacs-command-loop--read-key-sequence (prompt &rest _ignore)
+ "Read key sequence in ergoemacs-mode with PROMPT.
+
+Ignore all the other options."
+ (let ((old ergoemacs-command-loop-type)
+ (old-prompt ergoemacs-command-loop--read-key-prompt)
+ ret)
+ (setq ergoemacs-command-loop-type :read-key-sequence
+ ergoemacs-command-loop--read-key-prompt prompt)
+ (unwind-protect
+ (setq ret (ergoemacs-command-loop--internal))
+ (setq ergoemacs-command-loop-type old
+ ergoemacs-command-loop--read-key-prompt old-prompt))
+ ret))
+
+(defun ergoemacs-command-loop--internal (&optional key type initial-key-type
universal initial-history)
+ "Read keyboard input and execute command.
+The KEY is the keyboard input where the reading begins. If nil,
+read the whole keymap.
+
+TYPE is the keyboard translation type, defined by `ergoemacs-translate'
+Ergoemacs-mode sets up: :ctl-to-alt :unchorded :normal.
+
+INITIAL-KEY-TYPE represents the translation type for the initial KEY.
+
+UNIVERSAL allows ergoemacs-read-key to start with universal
+argument prompt.
+
+INITIAL-HISTORY is the initial history list to use.
+
+While in the loop, every command resets the keys typed every time
+a command is completed (by `clear-this-command-keys')
+
+Also in the loop, `universal-argument-num-events' is set to
+0. (Allows commands like `isearch' to work correctly in older
+Emacs versions)."
+ (interactive)
+ (when ergoemacs-mode
+ (ergoemacs-command-loop--execute-rm-keyfreq 'ergoemacs-command-loop)
+ ;; Call the startup command
+ (when (commandp ergoemacs-command-loop-start)
+ (ergoemacs-command-loop--call-interactively ergoemacs-command-loop-start)
+ (ergoemacs-command-loop--internal-end-command))
+ ;; Replace functions temporarily
+ (cl-letf (((symbol-function 'this-command-keys)
#'ergoemacs-command-loop--this-command-keys)
+ ((symbol-function 'this-single-command-keys)
#'ergoemacs-command-loop--this-command-keys)
+ ((symbol-function 'this-command-keys-vector)
#'ergoemacs-command-loop--this-command-keys)
+ ((symbol-function 'this-single-command-raw-keys)
#'ergoemacs-command-loop--this-command-keys)
+ ;; ((symbol-function 'read-key-sequence)
#'ergoemacs-command-loop--read-key-sequence)
+ )
+ (let* ((type (or type :normal))
+ (from-start-p ergoemacs-command-loop-start)
+ (continue-read t)
+ (first-type type)
+ raw-key current-key last-current-key
+ (translation (ergoemacs-translate--get type))
+ (local-keymap (ergoemacs-translate--keymap translation))
+ modal-p
+ tmp command)
+ (unwind-protect
+ (progn
+ ;; Set these to nil when entering the command loop;
+ ;;
+ ;; For some reason `inhibit-point-motion-hooks' on emacs
+ ;; 25.1 is t when the command loop is entered.
+ ;;
+ ;; To allow the point motion hooks to work as
+ ;; advertised, set these on starting the command loop.
+ (setq inhibit-point-motion-hooks nil
+ disable-point-adjustment nil
+ global-disable-point-adjustment nil)
+ ;; Setup initial unread command events, first type and history
+ (setq tmp (ergoemacs-command-loop--listify-key-sequence key
initial-key-type)
+ unread-command-events (or (and unread-command-events tmp
(append tmp unread-command-events)) tmp)
+ ergoemacs-command-loop--first-type first-type
+ ergoemacs-command-loop--history initial-history
+ ergoemacs-command-loop-start nil)
+ (while continue-read
+ (setq ergoemacs-last-command-was-ergoemacs-ignore-p nil)
+ (unless (eq ergoemacs-command-loop-type :read-key-sequence)
+ (setq inhibit-quit t))
+ (while continue-read
+ (setq ergoemacs-last-command-was-ergoemacs-ignore-p nil)
+ ;; Read key
+ (setq ergoemacs-command-loop--single-command-keys current-key
+ ergoemacs-command-loop--current-type type
+ ergoemacs-command-loop--universal universal
+ raw-key (ergoemacs-command-loop--read-key
+ current-key
+ (or (and unread-command-events :normal) type)
+ (and (not unread-command-events) universal))
+ ergoemacs-command-loop--single-command-keys nil
+ universal-argument-num-events 0
+ last-current-key current-key
+ current-key (nth 1 raw-key)
+ raw-key (nth 0 raw-key)
+ continue-read nil)
+ (when (setq modal-p (ergoemacs :modal-p))
+ (setq local-keymap
(ergoemacs-translation-struct-keymap-modal modal-p)))
+ (cond
+ ;; Handle quit commands
+ ((and last-current-key
+ (or (lookup-key ergoemacs-map--quit-map raw-key)
+ (and (equal raw-key [27])
+ (lookup-key ergoemacs-map--quit-map
[escape]))))
+ (ergoemacs-command-loop--message
+ "Key sequence %s aborted by %s"
+ (ergoemacs-key-description last-current-key)
+ (ergoemacs-key-description raw-key))
+ (setq quit-flag t
+ ergoemacs-this-command-keys-shift-translated nil))
+ ;; Handle local commands.
+ ((and (or modal-p
+ (not (equal current-key raw-key)))
+ (setq command (lookup-key local-keymap raw-key))
+ (not (ergoemacs-keymapp command)) ;; Ignore locally
+ ;; Already handled by
`ergoemacs-command-loop--read-key'
+ (not (ergoemacs-gethash command
ergoemacs-command-loop--next-key-hash))
+ ;; If a command has :ergoemacs-local property of
:force, don't
+ ;; worry about looking up a key, just run the
function.
+ (or modal-p
+ (and (symbolp command) (eq (get command
:ergoemacs-local) :force))
+ (not (key-binding current-key t))))
+ (pop ergoemacs-command-loop--history) ;; Don't recored
local events
+ (setq ergoemacs-command-loop--single-command-keys
last-current-key
+ universal-argument-num-events 0
+ ergoemacs-command-loop--current-type type
+ ergoemacs-command-loop--universal universal
+ ergoemacs-command-loop--exit nil)
+
+ (unless (eq ergoemacs-command-loop-type :test)
+ (setq tmp this-command
+ this-command command)
+ (ergoemacs-command-loop--call-interactively this-command)
+ (setq command this-command
+ this-command tmp))
+ ;; If the command changed anything, fix it here.
+ (unless (equal type ergoemacs-command-loop--current-type)
+ (setq type ergoemacs-command-loop--current-type
+ translation (ergoemacs-translate--get type)
+ local-keymap (ergoemacs-translate--keymap
translation)))
+
+ (setq current-key
ergoemacs-command-loop--single-command-keys
+ universal ergoemacs-command-loop--universal
+ ergoemacs-command-loop--single-command-keys nil
+ continue-read (not ergoemacs-command-loop--exit)))
+ ;; Handle any keys that are bound in some translatable way.
+ ((setq command (ergoemacs-command-loop--key-lookup
current-key))
+ ;; Setup external indicators of how the loop currently
behaves.
+ (setq ergoemacs-command-loop--single-command-keys
current-key
+ universal-argument-num-events 0
+ ergoemacs-command-loop--current-type type
+ ergoemacs-command-loop--universal nil
+ ergoemacs-command-loop--exit t)
+ (if (setq continue-read (and (not (and (consp (aref
current-key 0))
+ (memq
(event-basic-type (car (aref current-key 0)))
+ '(mouse-1
mouse-2 mouse-3 mouse-4 mouse-5 mouse-6 mouse-7 mouse-8 mouse-9))))
+ (ergoemacs-keymapp command)))
+ (setq universal nil)
+ (unless (memq ergoemacs-command-loop-type '(:test
:read-key-sequence))
+ (with-local-quit
+ (ergoemacs-command-loop--execute command)))
+
+ (when quit-flag
+ (ergoemacs-command-loop--message "Quit!"))
+
+ ;; Change any information (if needed)
+ (unless (equal type ergoemacs-command-loop--current-type)
+ (setq type ergoemacs-command-loop--current-type
+ translation (ergoemacs-translate--get type)
+ local-keymap (ergoemacs-translate--keymap
translation)))
+
+ (when (eq ergoemacs-command-loop-type :read-key-sequence)
+ (setq ergoemacs-command-loop--exit t
+ continue-read nil
+ command current-key))
+
+ (setq current-key
ergoemacs-command-loop--single-command-keys
+ universal ergoemacs-command-loop--universal
+ ergoemacs-command-loop--single-command-keys nil
+ continue-read (not ergoemacs-command-loop--exit)
+ current-prefix-arg (if
ergoemacs-command-loop--universal current-prefix-arg prefix-arg))
+
+ (when (and (not continue-read)
+ (eq ergoemacs-command-loop--exit
:ignore-post-command-hook))
+ (setq continue-read t)))
+
+ (when (or (not ergoemacs-command-loop--exit)
+ (and (not continue-read) (setq continue-read
unread-command-events)))
+ (ergoemacs-command-loop--internal-end-command)))
+ (quit-flag
+ (ergoemacs-command-loop--message "Quit!")
+ (setq quit-flag nil
+ type :normal
+ first-type :normal
+ raw-key nil
+ current-key nil
+ translation (ergoemacs-translate--get type)
+ local-keymap (ergoemacs-translate--keymap
translation)
+ ergoemacs-command-loop--first-type first-type
+ ergoemacs-command-loop--history nil))
+ ((consp (aref current-key 0))) ;; don't complain about mouse
keys
+ (t ;; Command not found exit.
+ (ergoemacs-command-loop--message "Key %s doesn't do
anything." (ergoemacs-key-description current-key)))))
+ (unless quit-flag
+ (ergoemacs-command-loop--internal-end-command))
+ (setq quit-flag nil
+ type :normal
+ continue-read (or unread-command-events (and
from-start-p (ergoemacs-command-loop-full-p)))
+ first-type :normal
+ raw-key nil
+ current-key nil
+ translation (ergoemacs-translate--get type)
+ local-keymap (ergoemacs-translate--keymap translation)
+ ergoemacs-command-loop--first-type first-type
+ ergoemacs-command-loop--history nil)
+ (when (or (not ergoemacs-mode) (eq :read-key-sequence
ergoemacs-command-loop-type))
+ (setq continue-read nil)))
+ (setq inhibit-quit nil)))
+ command))))
+
(defcustom ergoemacs-message-in-mode-line t
"Display ergoemacs information in mode-line."
:type 'boolean
@@ -791,6 +2078,333 @@ to the `format' like: (format str args)."
(let ((message-log-max ergoemacs-command-loop--message-log-max))
(apply #'message (append (list str) args))))))
+(defvar ergoemacs-command-loop--temp-message-timer-secs 0.5
+ "Timer to ensure minibuffer isn't active.")
+
+(defvar ergoemacs-command-loop--temp-message-timer nil
+ "Timer to ensure minibuffer isn't active.")
+
+(defvar ergoemacs-command-loop--temp-message-timer-str nil
+ "Message string.")
+
+(defun ergoemacs-command-loop--temp-message-timer-echo ()
+ "Echos `ergoemacs-command-loop--temp-message-timer-str' if minibuffer isn't
active."
+ (if (or (minibufferp) isearch-mode)
+ (setq ergoemacs-command-loop--temp-message-timer
+ (run-with-idle-timer ergoemacs-command-loop--temp-message-timer-secs
+ nil
#'ergoemacs-command-loop--temp-message-timer-echo))
+ (cancel-timer ergoemacs-command-loop--temp-message-timer)
+ (let (message-log-max)
+ (with-temp-message ergoemacs-command-loop--temp-message-timer-str
+ (sit-for (or (and (numberp ergoemacs-command-loop-message-sit-for)
ergoemacs-command-loop-message-sit-for) 2))))))
+
+(defun ergoemacs-command-loop--temp-message (str &rest args)
+ "Message facility for `ergoemacs-mode' command loop.
+
+STR is the format string
+ARGS is the format arguments
+These are passed to `format' as (format str args)."
+ (setq ergoemacs-command-loop--last-event-time (float-time))
+ (cond
+ ((string= str ""))
+ ((or (minibufferp) isearch-mode)
+ (apply #'ergoemacs-command-loop--mode-line-message
+ (append (list str) args)))
+ (t
+ (setq ergoemacs-command-loop--temp-message-timer-str (apply #'format
(append (list str) args))
+ ergoemacs-command-loop--temp-message-timer
+ (run-with-idle-timer ergoemacs-command-loop--temp-message-timer-secs
+ nil
#'ergoemacs-command-loop--temp-message-timer-echo)))))
+
+;; (2) Key sequence translated to command
+(defun ergoemacs-command-loop--message-binding (key &optional lookup
translated-key)
+ "Optionally messages information about the translation.
+
+KEY is the original key.
+
+LOOKUP is what will be run.
+
+TRANSLATED-KEY is what the assumed key is actually bound."
+ (cond
+ ((and lookup (ergoemacs-keymapp lookup)))
+ ((consp (elt key 0))) ;; Don't message mouse translations
+ ((and (or (eq ergoemacs-echo-function :multi-key)
+ (not (and translated-key (eq ergoemacs-echo-function
:on-translation)))
+ (not (eq ergoemacs-echo-function t)))
+ (vectorp key) (or (= (length key) 1) ;; Don't message single keys
+ (and (eq 27 (elt key 0)) (= (length key) 2)))))
+ ((and lookup
+ (or (eq ergoemacs-echo-function t)
+ (and translated-key (eq ergoemacs-echo-function :on-translation))
+ (eq ergoemacs-echo-function :multi-key)))
+ (ergoemacs-command-loop--temp-message "%s%s%s%s"
+ (ergoemacs-key-description key)
+ (ergoemacs :unicode-or-alt "→" "->")
+ lookup
+ (or (and translated-key
+ (format " (from %s)"
(ergoemacs-key-description translated-key)))
+ "")))
+ ((not lookup)
+ (ergoemacs-command-loop--temp-message "%s is undefined!"
+ (ergoemacs-key-description key)))
+ ((and ergoemacs-echo-function
+ (not (or (= (length key) 1) ;; Clear command completing message
+ (and (eq 27 (elt key 0)) (= (length key) 2)))))
+ (ergoemacs-command-loop--message ""))))
+
+(defun ergoemacs-command-loop--key-lookup (key)
+ "Find the KEY's function based on current bindings.
+
+If `ergoemacs-mode' has translated this, make Emacs think you
+pressed the translated key by changing
+`ergoemacs-command-loop--single-command-keys'."
+ (if (and (vectorp key)
+ (consp (aref key 0))
+ (memq (event-basic-type (car (aref key 0)))
+ '(mouse-1 mouse-2 mouse-3 mouse-4 mouse-5 mouse-6 mouse-7
mouse-8 mouse-9)))
+ (let* ((event (aref key 0))
+ (posn (car (cdr last-command-event)))
+ (area (and posn (ergoemacs-posnp posn) (posn-area posn)))
+ (obj (and posn (ergoemacs-posnp posn) (posn-object posn)))
+ (original-command (key-binding key t))
+ command tmp)
+ ;; From `read-key-sequence':
+ ;; /* Clicks in non-text areas get prefixed by the symbol
+ ;; in their CHAR-ADDRESS field. For example, a click on
+ ;; the mode line is prefixed by the symbol `mode-line'.
+ ;; Furthermore, key sequences beginning with mouse clicks
+ ;; are read using the keymaps of the buffer clicked on, not
+ ;; the current buffer. So we may have to switch the buffer
+ ;; here.
+ ;; When we turn one event into two events, we must make sure
+ ;; that neither of the two looks like the original--so that,
+ ;; if we replay the events, they won't be expanded again.
+ ;; If not for this, such reexpansion could happen either here
+ ;; or when user programs play with this-command-keys. */
+
+ ;;
+ ;; /* Arrange to go back to the original buffer once we're
+ ;; done reading the key sequence. Note that we can't
+ ;; use save_excursion_{save,ore} here, because they
+ ;; save point as well as the current buffer; we don't
+ ;; want to save point, because redisplay may change it,
+ ;; to accommodate a Fset_window_start or something. We
+ ;; don't want to do this at the top of the function,
+ ;; because we may get input from a subprocess which
+ ;; wants to change the selected window and stuff (say,
+ ;; emacsclient). */
+ (when area
+ (setq command (key-binding (vconcat (list area event)) t))
+ (when (and obj (consp obj)
+ (setq tmp (ignore-errors (get-text-property (cdr obj)
'local-map (car obj))))
+ (setq tmp (or (and (symbolp tmp) (ergoemacs-sv tmp)) tmp))
+ (ergoemacs-keymapp tmp)
+ (setq tmp (lookup-key tmp (vconcat (list area event)))))
+ (setq command tmp)))
+ (unless command
+ (setq command original-command))
+ ;; (ergoemacs-command-loop--call-mouse-command command record-flag keys)
+
+ command)
+ ;; Make sure to lookup the keys in the selected buffer
+ (ergoemacs-command-loop--sync-point)
+ (let ((trials (ergoemacs-translate--trials key))
+ tmp tmp2 ret)
+ (setq this-command-keys-shift-translated nil)
+ (catch 'found-command
+ (dolist (cur-key trials)
+ (when cur-key
+ (let* ((orig-key cur-key)
+ (bind (key-binding orig-key t))
+ (meta-key (ergoemacs-translate--meta-to-escape cur-key))
+ (esc-key (ergoemacs-translate--escape-to-meta cur-key))
+ (new-key (or meta-key esc-key))
+ (new-binding (and new-key (key-binding new-key)))
+ (global (and new-key
+ (list (lookup-key ergoemacs-keymap orig-key t)
+ (lookup-key ergoemacs-keymap new-key t)))))
+ ;; Prefer non-global keys.
+ (when (eq bind 'undefined)
+ (setq bind nil))
+ (when (eq new-binding 'undefined)
+ (setq new-binding nil))
+ (cond
+ ((not new-key)
+ (setq new-key orig-key))
+ ((not (memq bind global))
+ (setq new-key orig-key))
+ ((and new-binding (not (memq new-binding global)))
+ (setq bind new-binding)))
+ (unless bind
+ (cond
+ ((or (ergoemacs-keymapp (setq tmp (lookup-key input-decode-map
orig-key)))
+ (and (not (integerp tmp)) (commandp tmp)))
+ (setq bind tmp))
+ ((or (ergoemacs-keymapp (setq tmp (lookup-key
local-function-key-map orig-key)))
+ (and (not (integerp tmp)) (commandp tmp)))
+ (setq bind tmp))
+ ((or (ergoemacs-keymapp (setq tmp (lookup-key
key-translation-map orig-key)))
+ (and (not (integerp tmp)) (commandp tmp)))
+ (setq bind tmp))))
+ (when (and orig-key
+ (setq ret bind
+ ret (if (and (eq ret 'ergoemacs-map-undefined)
+ (equal orig-key (nth 0 trials))
+ (nth 1 trials)) nil ret)))
+ (cond
+ ((equal orig-key (nth 0 trials))
+ (setq ergoemacs-command-loop--single-command-keys new-key)
+ ;; (message "History %s" (length
ergoemacs-command-loop--history))
+ (when (and (not (eq ergoemacs-handle-ctl-c-or-ctl-x
'only-C-c-and-C-x))
+ (ergoemacs-keymapp ret)
+ (setq tmp (lookup-key ret [ergoemacs-timeout])))
+ (cond
+ ((eq ergoemacs-handle-ctl-c-or-ctl-x 'only-copy-cut)
+ (setq ret tmp))
+ ((< 1 (length ergoemacs-command-loop--history)))
+ ((not (region-active-p))) ;; its a key sequence.
+
+ ((and (or ergoemacs-this-command-keys-shift-translated
this-command-keys-shift-translated)
+ (eq ergoemacs-handle-ctl-c-or-ctl-x 'both)))
+
+ ;; Immediate
+ ((and (not ergoemacs-ctl-c-or-ctl-x-delay)
+ (eq ergoemacs-handle-ctl-c-or-ctl-x 'both))
+ (setq ret tmp))
+
+ (t ;; with delay
+ (if ergoemacs-command-loop--decode-event-timeout-p
+ (setq tmp2 nil
+ ergoemacs-command-loop--decode-event-timeout-p
nil))
+ (setq tmp2 (with-timeout (ergoemacs-ctl-c-or-ctl-x-delay
nil)
+ (ergoemacs-command-loop--read-event nil key)))
+ (if (not tmp2)
+ (setq ret tmp) ;; timeout, use copy/cut
+ ;; Actual key
+ (setq ret (ergoemacs-command-loop--key-lookup (vconcat
key (vector tmp2))))))))
+ (ergoemacs-command-loop--message-binding new-key ret))
+ ((equal orig-key (nth 1 trials)) ;; `ergoemacs-mode' shift
translation
+ (setq this-command-keys-shift-translated t
+ ergoemacs-command-loop--single-command-keys (nth 0
trials))
+
+ ;; Shift+Control+c
+ (when (and (ergoemacs-keymapp ret)
+ (setq tmp (lookup-key ret [ergoemacs-timeout]))
+ (eq ergoemacs-handle-ctl-c-or-ctl-x 'both))
+ (setq ret tmp))
+ (ergoemacs-command-loop--message-binding new-key ret key))
+ (t
+ (ergoemacs-command-loop--message-binding new-key ret key)
+ (setq ergoemacs-command-loop--single-command-keys new-key)))
+ (throw 'found-command ret))))))
+ ret)))
+
+(defun ergoemacs-command-loop--execute-handle-shift-selection (function)
+ "Allow `ergoemacs-mode' command loop to handle shift selection.
+
+This will apply `handle-shift-selection' when FUNCTION is
+considered a shift-selection compatible function.
+
+This allows shift-selection of non-letter keys.
+For instance in QWERTY M-> is shift translated to M-."
+ (when (ergoemacs :movement-p function)
+ (handle-shift-selection)))
+
+(defun ergoemacs-command-loop--execute-rm-keyfreq (command)
+ "Remove COMMAND from `keyfreq-mode' counts."
+ (when (featurep 'keyfreq)
+ (when keyfreq-mode
+ (let (count)
+ (setq count (ergoemacs-gethash (cons major-mode command)
keyfreq-table))
+ (cond
+ ((not count))
+ ((= count 1)
+ (remhash (cons major-mode command) keyfreq-table))
+ (count
+ (puthash (cons major-mode command) (- count 1)
+ keyfreq-table)))
+ ;; Add local-fn to counter.
+ (setq count (ergoemacs-gethash (cons major-mode command)
keyfreq-table))
+ (puthash (cons major-mode command) (if count (+ count 1) 1)
+ keyfreq-table)))))
+
+;; (3) execute command
+(defun ergoemacs-command-loop--execute (command &optional keys)
+ "Execute COMMAND pretending that KEYS were pressed."
+ (unwind-protect
+ (let ((keys (or keys ergoemacs-command-loop--single-command-keys)))
+ ;; (ergoemacs-command-loop--spinner)
+ (cond
+ ((or (stringp command) (vectorp command))
+ ;; If the command is a keyboard macro (string/vector) then execute
+ ;; it by adding it to `unread-command-events'
+ (let ((tmp (prefix-numeric-value current-prefix-arg)))
+ (cond
+ ((<= tmp 0) ;; Unsure what to do here.
+ (ergoemacs-command-loop--message "The %s keyboard macro was not
run %s times" (ergoemacs-key-description (vconcat command)) tmp))
+ (t
+ (dotimes (_i tmp unread-command-events)
+ (setq unread-command-events
+ (append (listify-key-sequence command)
+ unread-command-events))))))
+ (setq ergoemacs-command-loop--single-command-keys nil))
+ (t
+ ;; This should be a regular command.
+
+ ;; Remove counting of `this-command' in `keyfreq-mode'
+ ;; Shouldn't be needed any more...
+ ;; (ergoemacs-command-loop--execute-rm-keyfreq this-command)
+
+ ;; This command execute should modify the following variables:
+ ;; - `last-repeatable-command'
+ ;; - `this-command'
+ ;; - `this-original-command'
+
+ ;; In addition, other minor modes may store the command, so these
+ ;; should be modified as well.
+
+ ;; These are stored in
`ergoemacs-command-loop--execute-modify-command-list'
+
+ (ergoemacs-command-loop--execute-modify-command-list command)
+
+ ;; Handle Shift Selection
+ (ergoemacs-command-loop--execute-handle-shift-selection this-command)
+ (when keys
+ (setq ergoemacs-command-loop--single-command-keys keys)
+
+ ;; Modify the output for these functions when `keys' is not nil.
+
+ ;; Assume this is a nonmenu event if it isn't a mouse event
+ (unless (consp last-command-event)
+ (setq last-nonmenu-event last-command-event)))
+ (unwind-protect
+ (progn
+ (setq ergoemacs-command-loop--running-pre-command-hook-p t)
+ (run-hooks 'pre-command-hook))
+ (setq ergoemacs-command-loop--running-pre-command-hook-p nil))
+ (unwind-protect
+ (ergoemacs-command-loop--call-interactively this-command t)
+ (setq ergoemacs-command-loop--single-command-keys nil)))))
+ ;; (ergoemacs-command-loop--spinner-end)
+ ))
+(defun ergoemacs-command-loop--shift-timeout ()
+ "This is the shift-timeout function for a key."
+ (interactive)
+ (let ((shift-trans (ergoemacs-translate--emacs-shift
(this-single-command-keys))))
+ (if (eq ergoemacs-handle-ctl-c-or-ctl-x 'only-copy-cut)
+ (setq unread-command-events (append (ergoemacs-translate--emacs-shift
shift-trans) '(ergoemacs-timeout)))
+ (setq ergoemacs-this-command-keys-shift-translated t)
+ (ergoemacs-command-loop--internal shift-trans))))
+
+(defun ergoemacs-command-loop--shift-translate ()
+ "Shift translation."
+ (interactive)
+ (let ((shift-trans (ergoemacs-translate--emacs-shift
(this-single-command-keys) 'ergoemacs-shift)))
+ (message "%s->%s" (key-description (this-single-command-keys))
+ (key-description shift-trans))
+ (setq ergoemacs-this-command-keys-shift-translated t
+ this-command-keys-shift-translated t)
+ (ergoemacs-command-loop--call-interactively (key-binding shift-trans))))
(provide 'ergoemacs-command-loop)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; ergoemacs-command-loop.el ends here
diff --git a/ergoemacs-macros.el b/ergoemacs-macros.el
index 5cec912..69c8cea 100644
--- a/ergoemacs-macros.el
+++ b/ergoemacs-macros.el
@@ -316,6 +316,40 @@ When arg1 can be a property. The following properties are
supported:
((fboundp #'buffer-narrowed-p) `(buffer-narrowed-p))
(t `(/= (- (point-max) (point-min)) (buffer-size)))))
+;;;###autoload
+(defmacro ergoemacs-translation (&rest body-and-plist)
+ "Defines an `ergoemacs-mode' translation.
+:text -- Text to display while completing this translation
+:keymap -- Local Keymap for translation
+:keymap-modal -- Modal keymap for overrides.
+:modal-always -- If the modal state is always on, regardless of
+ the values of `ergoemacs-modal-ignored-buffers',
+ `ergoemacs-modal-emacs-state-modes' `minibufferp'
+The following arguments allow the keyboard presses to be translated:
+ - :meta
+ - :control
+ - :shift
+ - :meta-control
+ - :meta-shift
+ - :control-shift
+ - :meta-control-shift
+ - :unchorded (no modifiers)
+This also creates functions:
+- ergoemacs-translate--NAME-universal-argument
+- ergoemacs-translate--NAME-digit-argument
+- ergoemacs-translate--NAME-negative-argument
+- ergoemacs-translate--NAME-modal"
+ (declare (doc-string 2)
+ (indent 2))
+ (let ((kb (make-symbol "kb")))
+ (setq kb (ergoemacs-theme-component--parse-keys-and-body body-and-plist))
+
+ `(progn (puthash ,(intern (concat ":" (plist-get (nth 0 kb) ':name)))
+ (lambda() ,(plist-get (nth 0 kb) ':description)
+ (ergoemacs-translate--create :key ,(intern (concat ":"
(plist-get (nth 0 kb) ':name)))
+ ,@(nth 0 kb)))
ergoemacs-translation-hash))))
+
+
(provide 'ergoemacs-macros)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; ergoemacs-macros.el ends here
diff --git a/ergoemacs-mode.el b/ergoemacs-mode.el
index aa65846..d736b17 100644
--- a/ergoemacs-mode.el
+++ b/ergoemacs-mode.el
@@ -299,6 +299,12 @@ The `execute-extended-command' is now
\\[execute-extended-command].
(ergoemacs-setup-override-keymap))
(t (ergoemacs-setup-override-keymap)))
(setq ergoemacs-require--ini-p t)
+ (define-key key-translation-map (kbd "<apps>") (kbd "<menu>"))
+ (global-unset-key (kbd "<apps>"))
+ (global-unset-key (kbd "<menu>"))
+ (define-key ergoemacs-translate--parent-map (if (eq system-type
'windows-nt) [apps] [menu])
+ 'ergoemacs-command-loop--swap-translation)
+
(if refresh-p
(message "Ergoemacs-mode keys refreshed (%s)"
ergoemacs-keyboard-layout)
diff --git a/ergoemacs-themes.el b/ergoemacs-themes.el
index 635fd6e..1431ad3 100644
--- a/ergoemacs-themes.el
+++ b/ergoemacs-themes.el
@@ -1301,6 +1301,34 @@ keys (e.g. M-O A == <up>) or regular M-O keybinding."
(ergoemacs-set-menu-bar-search)
(ergoemacs-set-menu-bar-edit)
(ergoemacs-set-menu-bar-file)
+ (ergoemacs-define-key ergoemacs-override-keymap
+ (kbd "<menu> f")
+ (lambda ()
+ (interactive)
+ (ergoemacs-command-loop "C-x" :ctl-to-alt)))
+
+ (ergoemacs-define-key ergoemacs-override-keymap
+ (kbd "<menu> d")
+ (lambda ()
+ (interactive)
+ (ergoemacs-command-loop "C-c" :unchorded-ctl)))
+
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n a")
'org-agenda)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n A")
'org-capture)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n C-a")
'org-capture)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n c")
'calc)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n d")
'dired-jump)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n e")
'eshell)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n p")
'powershell)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n f")
'ergoemacs-open-in-desktop)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n g")
'grep)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n m")
'magit-status)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n o")
'ergoemacs-open-in-external-app)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n r") 'R)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n s")
'shell)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n t")
'org-capture)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n C-t")
'org-agenda)
+ (ergoemacs-define-key ergoemacs-override-keymap (kbd "<menu> n T")
'org-agenda)
)
(defun ergoemacs-install-standard-theme ()
@@ -1385,4 +1413,82 @@ keys (e.g. M-O A == <up>) or regular M-O keybinding."
)
(add-hook 'calc-load-hook #'ergoemacs-install-calc-bindings)
+
+(ergoemacs-translation normal ()
+ "Identify transformation"
+ :keymap (let ((map (make-sparse-keymap)))
+ (define-key map [f1] 'ergoemacs-read-key-help)
+ (define-key map (read-kbd-macro "C-h") 'ergoemacs-read-key-help)
+ map))
+
+(ergoemacs-translation ctl-to-alt ()
+ "Ctl <-> Alt translation"
+ :text (lambda() (format "<Ctl%sAlt> " (ergoemacs :unicode-or-alt "↔" " to
")))
+
+ :meta '(control)
+ :control '(meta)
+
+ :meta-shift '(control shift)
+ :control-shift '(meta shift)
+
+ :control-hyper '(meta hyper)
+ :meta-hyper '(control hyper)
+
+ :control-super '(meta super)
+ :meta-super '(control super)
+
+ :meta-shift-hyper '(control shift hyper)
+ :control-shift-hyper '(meta shift hyper)
+
+ :meta-shift-super '(control shift super)
+ :control-shift-super '(meta shift super)
+
+ :meta-super-hyper '(control super hyper)
+ :control-super-hyper '(meta super hyper)
+
+ :meta-super-hyper-shift '(control super hyper shift)
+ :control-super-hyper-shift '(meta super hyper shift)
+
+ :modal-color "blue"
+ :modal-always t
+
+ :keymap (let ((map (make-sparse-keymap)))
+ (define-key map [f1] 'ergoemacs-read-key-help)
+ (define-key map (read-kbd-macro "M-h") 'ergoemacs-read-key-help)
+ (define-key map (if (eq system-type 'windows-nt) [M-apps]
[M-menu]) 'ergoemacs-read-key-force-next-key-is-quoted)
+ (define-key map (read-kbd-macro "SPC")
'ergoemacs-read-key-force-next-key-is-ctl)
+ (define-key map (read-kbd-macro "M-SPC")
'ergoemacs-read-key-force-next-key-is-alt)
+ ;; (define-key map "G" 'ergoemacs-read-key-next-key-is-quoted)
+ ;; (define-key map "g" 'ergoemacs-read-key-next-key-is-alt)
+ map))
+
+(ergoemacs-translation unchorded-ctl ()
+ "Make the Ctl key sticky."
+ :text "<Ctl+>"
+ :unchorded '(control)
+ :shift '(control shift)
+ :meta '()
+ :control '(meta)
+ :keymap (let ((map (make-sparse-keymap)))
+ (define-key map [f1] 'ergoemacs-read-key-help)
+ (define-key map (read-kbd-macro "SPC")
'ergoemacs-read-key-force-next-key-is-quoted)
+ (define-key map (read-kbd-macro "M-SPC")
'ergoemacs-read-key-force-next-key-is-alt-ctl)
+ (define-key map "g" 'ergoemacs-read-key-force-next-key-is-alt)
+ (define-key map "G" 'ergoemacs-read-key-force-next-key-is-alt-ctl)
+ map))
+
+(ergoemacs-translation unchorded-alt ()
+ "Make the Alt key sticky."
+ :text "<Alt+>"
+ :unchorded '(meta)
+ :shift '(meta shift)
+ :meta '(meta shift)
+ :modal-color "red"
+ :keymap-modal (let ((map (make-sparse-keymap)))
+ (define-key map (read-kbd-macro "<return>")
'ergoemacs-unchorded-alt-modal)
+ (define-key map (read-kbd-macro "RET")
'ergoemacs-unchorded-alt-modal)
+ map))
+
+
+
(provide 'ergoemacs-themes)
diff --git a/ergoemacs-translate.el b/ergoemacs-translate.el
index e4503a3..0770c0a 100644
--- a/ergoemacs-translate.el
+++ b/ergoemacs-translate.el
@@ -1,6 +1,6 @@
;;; ergoemacs-translate.el --- Keyboard translation functions -*-
lexical-binding: t -*-
-;; Copyright © 2013-2014 Free Software Foundation, Inc.
+;; Copyright © 2013-2021 Free Software Foundation, Inc.
;; Filename: ergoemacs-translate.el
;; Description:
@@ -62,10 +62,12 @@
(defvar ergoemacs-translate--hash)
(defvar ergoemacs-translate--event-hash)
(defvar ergoemacs-dir)
+(defvar ergoemacs-theme)
(defvar ergoemacs-inkscape)
(defvar ergoemacs-command-loop--universal-functions)
(declare-function ergoemacs-layouts--list "ergoemacs-layouts")
+(declare-function ergoemacs-theme--list "ergoemacs-theme-engine")
(declare-function ergoemacs-mode-reset "ergoemacs-mode")
(declare-function ergoemacs-layouts--custom-documentation "ergoemacs-layouts")
(declare-function ergoemacs-theme--custom-documentation
"ergoemacs-theme-engine")
@@ -83,6 +85,10 @@
(declare-function ergoemacs-map-properties--put "ergoemacs-map-properties")
+(declare-function ergoemacs-map-- "ergoemacs-map")
+
+(declare-function ergoemacs-command-loop--modal-p "ergoemacs-command-loop")
+
(declare-function ergoemacs-translate--key-description "ergoemacs-translate")
(fset #'ergoemacs-translate--key-description (symbol-function
#'key-description))
@@ -191,6 +197,30 @@ KEY-SEQ must be a vector or string. If there is no need
to change the sequence,
(push event seq))))
(and found (vconcat seq)))))
+(defun ergoemacs-translate--swap-apps (key &optional what with)
+ "In KEY, swap apps key with menu key.
+Optionally specify WHAT you want to replace WITH.
+
+If no changes have been done, return nil."
+ (let ((seq (reverse (append key ())))
+ (what (or what 'apps))
+ (with (or with 'menu))
+ found-p
+ ret)
+ (dolist (e seq)
+ (cond
+ ((eq e what)
+ (push with ret)
+ (setq found-p t))
+ (t (push e ret))))
+ (if found-p
+ (vconcat ret)
+ nil)))
+
+(defun ergoemacs-translate--swap-menu (key)
+ "In KEY swap menu key with apps key."
+ (ergoemacs-translate--swap-apps key 'menu 'apps))
+
(defun ergoemacs-translate--to-vector (key)
"Translates KEY to vector format.
@@ -202,6 +232,43 @@ If no changes are performed, return nil."
(setq ret new-key))
ret)))
+(defun ergoemacs-translate--ergoemacs-shift-select (key)
+ "Translate KEY to allow `ergoemacs-mode' shift translation.
+
+This will shift translate Alt+# to Alt+3."
+ (let (modifiers basic)
+ (when (and (vectorp key)
+ ;; only makes sense for single key combinations.
+ (= (length key) 1)
+ ;; Doesn't make sense if shifted...
+ (not (or (memq 'shift (setq modifiers
(ergoemacs-translate--event-modifiers (aref key 0))))
+ (memq 'ergoemacs-shift modifiers)))
+ ;; Only define if emacs doesn't handle shift selection.
+ (not (eq (event-convert-list (list 'shift (setq basic
(event-basic-type (aref key 0)))))
+ (ergoemacs-translate--event-convert-list (list
'ergoemacs-shift basic)))))
+ (setq ergoemacs-translate--define-key-if-defined-p nil
+ ergoemacs-translate--define-key-replacement-function
'ergoemacs-command-loop--shift-translate)
+ (vector (ergoemacs-translate--event-convert-list (append modifiers (list
'ergoemacs-shift basic)))))))
+
+(defun ergoemacs-translate--ergoemacs-timeout (key)
+ "Translates KEY to allow Shift translation to default to key sequence.
+
+This is done for key sequences like Ctrl+Shift+c which should
+allow the Ctrl+c key sequence to be called when text is
+seleceted (instead of copying the text)."
+ (let (modifiers basic)
+ (when (and (vectorp key)
+ ;; only makes sense for single key combinations.
+ (= (length key) 2)
+ (eq 'ergoemacs-timeout (aref key 1))
+ ;; Doesn't make sense if shifted...
+ (not (or (memq 'shift (setq modifiers
(ergoemacs-translate--event-modifiers (aref key 0))))
+ (memq 'ergoemacs-shift modifiers))))
+ (setq basic (ergoemacs-translate--event-basic-type (aref key 0))
+ ergoemacs-translate--define-key-if-defined-p nil
+ ergoemacs-translate--define-key-replacement-function
'ergoemacs-command-loop--shift-timeout)
+ (vector (ergoemacs-translate--event-convert-list (append modifiers (list
'shift basic)))))))
+
(defun ergoemacs-translate--to-string (key)
"Translates KEY to string format.
@@ -217,9 +284,12 @@ If no chanegs are performed, return nil."
(defvar ergoemacs-translate--apply-funs
'(ergoemacs-translate--escape-to-meta
ergoemacs-translate--meta-to-escape
+ ergoemacs-translate--swap-apps
+ ergoemacs-translate--swap-menu
ergoemacs-translate--to-string
ergoemacs-translate--to-vector
- )
+ ergoemacs-translate--ergoemacs-timeout
+ ergoemacs-translate--ergoemacs-shift-select)
"Functions to apply to key.
These functions take a key as an argument and translate it in
@@ -343,6 +413,11 @@ MODIFIERS is the precalculated modifiers from
new-modifiers
new-event
(translation-hash (ergoemacs-translate--get-hash layout-to
layout-from)))
+ (cond
+ ((and (eq system-type 'windows-nt) (eq basic 'menu))
+ (setq basic 'apps))
+ ((and (not (eq system-type 'windows-nt)) (eq basic 'apps))
+ (setq basic 'menu)))
(if (memq 'ergoemacs-control modifiers)
(setq new-event basic
new-modifiers modifiers)
@@ -489,6 +564,10 @@ make the translation."
(not just-first-p))
(setq translated-event
(ergoemacs-translate--event-layout event layout-to layout-from
basic modifiers)))
+ ((and (eq system-type 'windows-nt) (eq basic 'menu))
+ (setq translated-event (ergoemacs-translate--event-convert-list
(append modifiers '(apps)))))
+ ((and (not (eq system-type 'windows-nt)) (eq basic 'apps))
+ (setq translated-event (ergoemacs-translate--event-convert-list
(append modifiers '(menu)))))
(t (setq translated-event event)))
(setq untranslated (vconcat untranslated (list event))
ret (vconcat ret (list translated-event))))
@@ -626,6 +705,7 @@ For keys, the list consists of:
(universal-argument nil)
(negative-argument nil)
(digit-argument nil)
+ (modal nil)
(text "")
(keymap (make-sparse-keymap))
(keymap-modal (make-sparse-keymap))
@@ -634,6 +714,62 @@ For keys, the list consists of:
(key nil)
(unchorded nil))
+(defvar ergoemacs-translate--setup-command-loop-regexp
+
"^\\(?:ergoemacs\\(?:-translate-\\)?\\)-\\(.*?\\)-\\(universal-argument\\|negative-argument\\|digit-argument\\|modal\\)$"
+ "Command loop command match/setup regular expression.")
+
+(defun ergoemacs-translate--setup-command-loop ()
+ "Setup command loop.
+To do anything, `this-command' must match
+`ergoemacs-translate--setup-command-loop-regexp'. The first
+match is the NAME of the translation, the second match is the
+TYPE of command. This command will then
+call (ergoemacs-command-loop-TYPE :NAME)."
+ (interactive)
+ (let ((command-str (symbol-name this-command))
+ name type)
+ (save-match-data
+ (when (string-match ergoemacs-translate--setup-command-loop-regexp
command-str)
+ (setq name (match-string 1 command-str)
+ type (match-string 2 command-str))
+ (funcall (intern (concat "ergoemacs-command-loop--" type)) (intern
(concat ":" name)))))))
+
+(defun ergoemacs-translate--setup-translation (&optional name)
+ "Setup translation functions and keymaps.
+If NAME is nil, setup all translations.
+When NAME is a symbol, setup the translation function for the symbol."
+ (if (not name)
+ (maphash
+ (lambda(name _item)
+ (ergoemacs-translate--setup-translation name))
+ ergoemacs-translation-hash)
+ (let ((name-str (and (symbolp name) (substring (symbol-name name) 1))))
+ (eval
+ (macroexpand ; Fixme why?
+ `(progn
+ (defvar ,(intern (concat "ergoemacs-translate--" name-str "-map"))
(make-sparse-keymap)
+ ,(concat "Ergoemacs local map for translation :"
+ name-str
+ " while completing a key sequence."))
+ (define-obsolete-variable-alias ',(intern (concat "ergoemacs-"
name-str "-translation-local-map"))
+ ',(intern (concat "ergoemacs-translate--" name-str "-map"))
+ "Ergoemacs-v5.16")))
+ t)
+ (ergoemacs-map-properties--label-map (intern (concat
"ergoemacs-translate--" name-str "-map")) t)
+ (ergoemacs (symbol-value (intern (concat "ergoemacs-translate--"
name-str "-map"))) :only-local-modifications-p t)
+ ;;
+ (dolist (type '("-universal-argument" "-negative-argument"
+ "-digit-argument" "-modal"))
+ (fset (intern (concat "ergoemacs-translate--" name-str type))
+ 'ergoemacs-translate--setup-command-loop)
+ (fset (intern (concat "ergoemacs-" name-str type))
+ 'ergoemacs-translate--setup-command-loop)
+ (when (string= type "-universal-argument")
+ (cl-pushnew (intern (concat "ergoemacs-" name-str type))
ergoemacs-command-loop--universal-functions)
+ (cl-pushnew (intern (concat "ergoemacs-translate--" name-str type))
ergoemacs-command-loop--universal-functions))))))
+
+(add-hook 'ergoemacs-mode-intialize-hook
#'ergoemacs-translate--setup-translation)
+
(defun ergoemacs-translate--create (&rest plist)
"Create a translation from PLIST and return translation object."
(let ((plist plist)
@@ -641,6 +777,7 @@ For keys, the list consists of:
-universal-argument
-negative-argument
-digit-argument
+ -modal
translation
(local-keymap (or (plist-get plist :keymap) (make-sparse-keymap)))
(trans-keymap (intern (concat "ergoemacs-translate--" (plist-get plist
:name) "-map"))))
@@ -686,6 +823,7 @@ For keys, the list consists of:
:universal-argument -universal-argument
:negative-argument -negative-argument
:digit-argument -digit-argument
+ :modal -modal
:text (plist-get plist :text)
:keymap local-keymap
:keymap-modal (or (plist-get plist :keymap-modal)
(make-sparse-keymap))
@@ -720,7 +858,8 @@ If TYPE is unspecified, assume :normal translation"
((eq 'ergoemacs-shift e) 'shift)
((eq 'ergoemacs-control e) 'control)
(t e)))
- e-mod) #'string<))
+ e-mod)
+ #'string<))
(special-p (memq basic (list ?m ?i ?\[)))
(ambiguous-p (and special-p (memq 'control e-mod)))
tmp
@@ -746,7 +885,8 @@ If TYPE is unspecified, assume :normal translation"
((and special-p (display-graphic-p)
(memq 'control modifiers))
(push 'ergoemacs-gui modifiers)))
- (throw 'found-mod t))) nil)
+ (throw 'found-mod t)))
+ nil)
(if ambiguous-p
(setq ret (ergoemacs-translate--event-convert-list `(control
,@modifiers ,basic)))
(setq ret (ergoemacs-translate--event-convert-list `(,@modifiers
,basic)))))
@@ -754,23 +894,18 @@ If TYPE is unspecified, assume :normal translation"
(defun ergoemacs-translate--no-gui (event)
"Remove any gui elements to the EVENT.
-If there are no gui elements, retun nil."
+If there are no gui elements, return nil."
(if (vectorp event)
- (eval `(vector ,@(mapcar (lambda(x) (let ((ret (or
(ergoemacs-translate--no-gui x) x)))
- (if (symbolp ret)
- `(quote ,ret)
- ret))) event)))
+ (apply #'vector (mapcar (lambda(x) (or (ergoemacs-translate--no-gui x)
x)) event))
(let* ((last-event event)
(last-mod (ergoemacs-translate--event-modifiers last-event))
(last-basic-event (ergoemacs-translate--event-basic-type last-event))
- new-mod
- new-event)
+ new-mod)
(when (memq 'ergoemacs-gui last-mod)
(dolist (elt last-mod)
(unless (eq elt 'ergoemacs-gui)
(push elt new-mod)))
- (setq new-event (ergoemacs-translate--event-convert-list `(,@new-mod
,last-basic-event))))
- new-event)))
+ (ergoemacs-translate--event-convert-list `(,@new-mod
,last-basic-event))))))
(defvar ergoemacs-translate--parent-map nil
"Parent map for keymaps when completing a key sequence.")
@@ -810,16 +945,25 @@ If there are no gui elements, retun nil."
;; (add-hook 'ergoemacs-mode-intialize-hook
#'ergoemacs-translate--keymap-reset)
(defun ergoemacs-translate--keymap (&optional translation)
- "Get the keymap for TRANSLATION."
- (let* ((translation (or (and (ergoemacs-translation-struct-p translation)
+ "Get the keymap for TRANSLATION.
+This takes into consideration the modal state of `ergoemacs-mode'."
+ (let* ((modal (ergoemacs :modal-p))
+ (translation (or (and (ergoemacs-translation-struct-p translation)
+ (or (not modal) ;; prefer modal when :normal
+ (not (eq :normal
(ergoemacs-translation-struct-key translation))))
translation)
+ modal
(ergoemacs-translate--get (or translation :normal))))
- (key (ergoemacs-translation-struct-key translation))
+ (key (or (and modal (intern (concat ":"
(ergoemacs-translation-struct-name translation) "-modal")))
+ (ergoemacs-translation-struct-key translation)))
(ret (ergoemacs-gethash key ergoemacs-translate--keymap-hash))
keymap)
(unless ret
- (setq keymap (ergoemacs-translation-struct-keymap translation)
- ret (make-composed-keymap (ergoemacs keymap) (ergoemacs
ergoemacs-translate--parent-map)))
+ (if modal
+ (setq keymap (ergoemacs-translation-struct-keymap-modal translation)
+ ret keymap)
+ (setq keymap (ergoemacs-translation-struct-keymap translation)
+ ret (make-composed-keymap (ergoemacs keymap) (ergoemacs
ergoemacs-translate--parent-map))))
(puthash key ret ergoemacs-translate--keymap-hash))
ret))
@@ -984,13 +1128,15 @@ If there are no gui elements, retun nil."
(setq ret (format "%s\n%s=%s" ret f (ergoemacs-translate--ahk-code
key))))))
ret))
-(defun ergoemacs-translate--ahk-ini (&optional all-layouts)
+(defun ergoemacs-translate--ahk-ini (&optional all-layouts all-themes)
"Creates the ini file used with the autohotkey script."
(let ((layouts (or (and all-layouts (sort (ergoemacs-layouts--list)
'string<))
(and (eq (ergoemacs :layout) 'ergoemacs-layout-us) (list
"us"))
(list "us" ergoemacs-keyboard-layout)))
- (themes (list "standard"))
+ (themes (or (and all-themes (sort (ergoemacs-theme--list) 'string<))
+ (list ergoemacs-theme)))
(original-layout ergoemacs-keyboard-layout)
+ (original-theme ergoemacs-theme)
ret)
(unwind-protect
(setq ret (with-temp-buffer
@@ -1004,13 +1150,15 @@ If there are no gui elements, retun nil."
(dolist (lay layouts)
(dolist (theme themes)
(message "Getting information from %s-%s" lay theme)
- (setq ergoemacs-keyboard-layout lay)
+ (setq ergoemacs-keyboard-layout lay
+ ergoemacs-theme theme)
(ergoemacs-mode-reset)
(insert "[" lay "-" theme "]"
(ergoemacs-translate--ahk-functions-ini)
"\n")))
(buffer-string)))
- (setq ergoemacs-keyboard-layout original-layout)
+ (setq ergoemacs-keyboard-layout original-layout
+ ergoemacs-theme original-theme)
(ergoemacs-mode-reset))
ret))
@@ -1067,14 +1215,23 @@ If :type is :quail use the 180 length string that
((string-match "[a-zA-Z0-9]" char)
char)
(t
- ;; Insert fancy characters as is and hope that the font
- ;; will work.
(setq ret (format "&#x%04X;"
(encode-char
(with-temp-buffer
(insert char)
(char-before)) 'unicode))
- )
+ font (ergoemacs-key-description--display-char-p char))
+ (when font
+ (setq font (or (font-get font :name)
+ (font-get font :family)))
+ (when (and font (symbolp font))
+ (setq font (symbol-name font)))
+ (setq default-font (or (font-get default-font :name)
+ (font-get default-font :family)))
+ (when (and default-font (symbolp default-font))
+ (setq default-font (symbol-name default-font)))
+ (unless (string= font default-font)
+ (setq ret (format "<text style=\"font-family:
'%s'\">%s</text>" font ret))))
ret)))
(while (< i (length char))
(setq ret (concat ret (ergoemacs-translate--svg-quote (substring char
i (+ i 1))))
- [elpa] externals/ergoemacs-mode 47924dc 203/325: Fix wording, (continued)
- [elpa] externals/ergoemacs-mode 47924dc 203/325: Fix wording, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode 728f2d7 209/325: Remove unused ergoemacs-map--modify-active, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode 3d61040 220/325: Remove ergoemacs-layouts--no-aliases, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode 581be06 212/325: Remove lots of timing code, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode 1cf6041 225/325: Remove :current-version, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode fe1d378 226/325: Remove :current-theme, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode 78bd8cf 231/325: Remove component stuff, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode d10087f 238/325: Remove ergoemacs macro :reset and :set-selection, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode 2caaef6 239/325: Remove unused functions, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode 4461083 242/325: Add reduction theme again, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode 97a2107 243/325: Add back the command loop. Part of it seems broken,
Stefan Monnier <=
- [elpa] externals/ergoemacs-mode 33cc2d6 244/325: Fix command loop key decriptions, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode ef2c71a 245/325: Add back the advices to have the ctrl/alt keys, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode d9b09be 246/325: Make command loop play with unicode only, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode efc8751 249/325: Some fixes based on emacs elpa requirements, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode 69abf8d 250/325: Fix ergoemacs-calculate-bindings, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode bed9aa1 253/325: Fix ergoemacs-mode and ergoemacs-themes; turn on cua mode, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode 57e8e17 257/325: remove undo-tree and mark-active, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode edc154f 272/325: Add theme for the ergoemacs keys hash. Also reduce tests, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode 09bc371 278/325: Restore menu items after turning off ergoemacs, Stefan Monnier, 2021/10/23
- [elpa] externals/ergoemacs-mode f14b71e 281/325: Remove ergoemacs-mode support for term-mode, Stefan Monnier, 2021/10/23