From 161db8c3aef72ef0a35948a1927a4c4cd23b354b Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Sat, 18 Nov 2023 00:40:36 +0900 Subject: [PATCH 01/14] additional parameters This prevents the task bars from leaping into the foreground and creating tons of windows that annoy the user --- keypression.el | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/keypression.el b/keypression.el index 315f2af..b25ec88 100644 --- a/keypression.el +++ b/keypression.el @@ -477,6 +477,12 @@ See `set-face-attribute' help for details." (keep-ratio ,keep-ratio) (fullscreen . nil) (no-accept-focus . t) + (no-focus-on-map . t) + (modeline . nil) + (skip-taskbar . t) + (user-size . t) + (user-position . t) + (icon-type nil) (min-width . 0) (min-height . 0) (border-width . 0) From b366571adf11a907b59b8d207bcf410053d5d8b3 Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Fri, 17 Nov 2023 16:21:26 +0900 Subject: [PATCH 02/14] Add support to ignore commands, such as self-insert-command --- keypression.el | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/keypression.el b/keypression.el index b25ec88..5676e66 100644 --- a/keypression.el +++ b/keypression.el @@ -209,6 +209,10 @@ See `set-face-attribute' help for details." (const wheel-down)) :group 'keypression) +(defcustom keypression-ignored-commands '(self-insert-command) + "List of commands to ignore." + :type '(repeat symbol)) + ;;; Global variables (defvar keypression--nactives 0) @@ -418,7 +422,9 @@ See `set-face-attribute' help for details." (key-description keys))) (defun keypression--pre-command () - (unless (memq (event-basic-type last-command-event) keypression-ignore-mouse-events) + (unless (or (memq (event-basic-type last-command-event) + keypression-ignore-mouse-events) + (memq this-command keypression-ignored-commands)) (keypression--push-string (keypression--keys-to-string (this-command-keys))))) (cl-defun keypression--create-frame (buffer-or-name From 43321a1a542f3fa4a1bf6d073cfe8ee3be3ee6b2 Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Fri, 17 Nov 2023 16:21:53 +0900 Subject: [PATCH 03/14] More robust face setup Setting the frame attributes wasn't consistently achieving the intent. --- keypression.el | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/keypression.el b/keypression.el index 5676e66..eb0538f 100644 --- a/keypression.el +++ b/keypression.el @@ -595,7 +595,10 @@ See `set-face-attribute' help for details." (keypression--set-frame-alpha (selected-frame) 0.0) (aset keypression--frames i (selected-frame)) (aset keypression--buffers i (current-buffer)) - (apply #'set-face-attribute 'default (selected-frame) keypression-font-face-attribute) + (apply #'set-face-attribute 'default (selected-frame) + keypression-font-face-attribute) + (set-face-attribute 'default (selected-frame) :foreground fg) + (set-face-attribute 'default (selected-frame) :background bg) (set-face-attribute 'fringe (selected-frame) :background bg) ;; Workaround for invisible bugs... (when (eq system-type 'windows-nt) From 72c45767159eff5dd2ffbd02977cc964c145922d Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Sat, 18 Nov 2023 02:15:44 +0900 Subject: [PATCH 04/14] support ignore function this makes it easier for users to ignore vast swaths of commands Signed-off-by: Psionik K <73710933+psionic-k@users.noreply.github.com> --- keypression.el | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/keypression.el b/keypression.el index eb0538f..540bf6f 100644 --- a/keypression.el +++ b/keypression.el @@ -210,8 +210,13 @@ See `set-face-attribute' help for details." :group 'keypression) (defcustom keypression-ignored-commands '(self-insert-command) - "List of commands to ignore." - :type '(repeat symbol)) + "Function or list that rejects commands. +If list, members will be ignored. When a function is provided, function will be +called with single COMMAND argument, a symbol. If the function returns non-nil, +the command is ignored." + :group 'keypression + :type '(symbol (list symbol)) + :options '(symbol (repeat symbol))) ;;; Global variables @@ -424,7 +429,10 @@ See `set-face-attribute' help for details." (defun keypression--pre-command () (unless (or (memq (event-basic-type last-command-event) keypression-ignore-mouse-events) - (memq this-command keypression-ignored-commands)) + (if (functionp keypression-ignored-commands) + (funcall keypression-ignored-commands this-command) + ;; assume list if not callable. + (memq this-command keypression-ignored-commands))) (keypression--push-string (keypression--keys-to-string (this-command-keys))))) (cl-defun keypression--create-frame (buffer-or-name From dae93b1bd690524a51094be5cc37cae2ee54e93c Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Sat, 18 Nov 2023 02:26:40 +0900 Subject: [PATCH 05/14] Condense parent logic and add delete-before --- keypression.el | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/keypression.el b/keypression.el index 540bf6f..836bd1d 100644 --- a/keypression.el +++ b/keypression.el @@ -579,7 +579,7 @@ the command is ignored." (keypression--create-arrays) (keypression--create-fade-out-timer) (add-hook 'kill-emacs-hook #'keypression--finalize) - (let* ((parent-frame (when keypression-use-child-frame (window-frame (selected-window)))) + (let* ((parent-frame (window-frame (selected-window))) (fg (if (keypression--light-background-p) keypression-foreground-for-light-mode keypression-foreground-for-dark-mode)) @@ -590,12 +590,12 @@ the command is ignored." (with-current-buffer (get-buffer-create (format " *keypression-%d*" i)) (with-selected-frame (keypression--create-frame (current-buffer) - :override-parameters (if keypression-use-child-frame - `((parent-frame . ,parent-frame) - (font . ,keypression-font)) - `((parent-frame . ,parent-frame) - (z-group . above) - (font . ,keypression-font))) + :override-parameters + `((parent-frame ,(when keypression-use-child-frame + parent-frame)) + (delete-before . ,parent-frame) + (font . ,keypression-font) + (z-group . ,(unless keypression-use-child-frame 'above))) :foreground-color fg :background-color bg :left-fringe keypression-left-fringe From 6b1277731c4ed17854e9295d2627f993c4b04b33 Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:42:51 +0900 Subject: [PATCH 06/14] switch to post-command hook as the base Signed-off-by: Psionik K <73710933+psionic-k@users.noreply.github.com> --- keypression.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/keypression.el b/keypression.el index 836bd1d..bce2df9 100644 --- a/keypression.el +++ b/keypression.el @@ -426,7 +426,7 @@ the command is ignored." keypression-space-substitution-string (key-description keys))) -(defun keypression--pre-command () +(defun keypression--post-command () (unless (or (memq (event-basic-type last-command-event) keypression-ignore-mouse-events) (if (functionp keypression-ignored-commands) @@ -538,7 +538,7 @@ the command is ignored." (defun keypression--finalize () (setq frame-alpha-lower-limit keypression--prev-frame-alpha-lower-limit) - (remove-hook 'pre-command-hook 'keypression--pre-command) + (remove-hook 'post-command-hook 'keypression--post-command) (when keypression--fade-out-timer (cancel-timer keypression--fade-out-timer)) (cl-flet ((mapc-when (array func &rest args) @@ -613,7 +613,7 @@ the command is ignored." (make-frame-visible))))) (raise-frame parent-frame)) (run-at-time 0.5 nil (lambda () - (add-hook 'pre-command-hook 'keypression--pre-command)))) + (add-hook 'post-command-hook 'keypression--post-command)))) ;;;###autoload (define-minor-mode keypression-mode From 28efc322c8da20f46557726521355ac1f3fe6ae2 Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:22:14 +0900 Subject: [PATCH 07/14] Add pre-command hook (no-op) Signed-off-by: Psionik K <73710933+psionic-k@users.noreply.github.com> --- keypression.el | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/keypression.el b/keypression.el index bce2df9..257dddb 100644 --- a/keypression.el +++ b/keypression.el @@ -426,6 +426,12 @@ the command is ignored." keypression-space-substitution-string (key-description keys))) +(defun keypression--pre-command () + "Record the pre-command state. +This enables us to differentiate commands that delegate out to other commands by +reading before the command and comparing the state during the post command +hook.") + (defun keypression--post-command () (unless (or (memq (event-basic-type last-command-event) keypression-ignore-mouse-events) @@ -538,14 +544,15 @@ the command is ignored." (defun keypression--finalize () (setq frame-alpha-lower-limit keypression--prev-frame-alpha-lower-limit) + (remove-hook 'pre-command-hook 'keypression--pre-command) (remove-hook 'post-command-hook 'keypression--post-command) (when keypression--fade-out-timer (cancel-timer keypression--fade-out-timer)) (cl-flet ((mapc-when (array func &rest args) - (mapc (lambda (elem) - (when elem - (apply func elem args))) - array))) + (mapc (lambda (elem) + (when elem + (apply func elem args))) + array))) (mapc-when keypression--buffers #'kill-buffer) (mapc-when keypression--frames #'delete-frame t)) (setq keypression--fade-out-timer nil @@ -612,8 +619,10 @@ the command is ignored." (when (eq system-type 'windows-nt) (make-frame-visible))))) (raise-frame parent-frame)) + (run-at-time 0.5 nil (lambda () - (add-hook 'post-command-hook 'keypression--post-command)))) + (add-hook 'pre-command-hook #'keypression--pre-command) + (add-hook 'post-command-hook #'keypression--post-command)))) ;;;###autoload (define-minor-mode keypression-mode From 5b772e08708e0f780f0dbf3b9a13ab4e8bf79d28 Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:39:21 +0900 Subject: [PATCH 08/14] Increasing purity. Pass rather than re-read. This enables upstream logic to dictate downstream behavior Signed-off-by: Psionik K <73710933+psionic-k@users.noreply.github.com> --- keypression.el | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/keypression.el b/keypression.el index 257dddb..6c6b781 100644 --- a/keypression.el +++ b/keypression.el @@ -375,17 +375,19 @@ the command is ignored." separator) str)) -(defun keypression--push-string (keys) - (let* ((string (if (and keypression-cast-command-name - this-command) +(defun keypression--push-string (keys command) + "Push string handles rendering and collapsing repeats. +It converts `self-insert-command' and digit prefix arguments. +Command filtering logic is in the `keypression-post--command'." + (let* ((string (if (and keypression-cast-command-name command) (format keypression-cast-command-name-format - keys this-command) + keys command) keys)) (self-insert (and keypression-concat-self-insert - (eq this-command 'self-insert-command))) + (eq command 'self-insert-command))) (same-key (and keypression-combine-same-keystrokes (string= keys keypression--last-keystrokes))) - (digit-arg (keypression--digit-argument-p this-command)) + (digit-arg (keypression--digit-argument-p command)) (before-digit-arg (keypression--digit-argument-p keypression--last-command))) (cond ((and (keypression--same-command-p) @@ -418,10 +420,10 @@ the command is ignored." (keypression--set-position-active-frames))) (setq keypression--last-keystrokes keys keypression--last-command-2 keypression--last-command - keypression--last-command this-command))) + keypression--last-command command))) -(defsubst keypression--keys-to-string (keys) - (if (and (eq this-command 'self-insert-command) +(defsubst keypression--keys-to-string (keys command) + (if (and (eq command 'self-insert-command) (string= keys " ")) keypression-space-substitution-string (key-description keys))) @@ -439,7 +441,9 @@ hook.") (funcall keypression-ignored-commands this-command) ;; assume list if not callable. (memq this-command keypression-ignored-commands))) - (keypression--push-string (keypression--keys-to-string (this-command-keys))))) + (keypression--push-string + (keypression--keys-to-string (this-command-keys) this-command) + this-command))) (cl-defun keypression--create-frame (buffer-or-name &key From 2b1b707a6efb9a8c64812b037b48a2ffc55e86a0 Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:47:14 +0900 Subject: [PATCH 09/14] store this-command-keys in pre-hook Reading command keys post hook failed for C-g. It is frequently nil in the post hook. Signed-off-by: Psionik K <73710933+psionic-k@users.noreply.github.com> --- keypression.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/keypression.el b/keypression.el index 6c6b781..7cf4d26 100644 --- a/keypression.el +++ b/keypression.el @@ -235,6 +235,7 @@ the command is ignored." (defvar keypression--last-keystrokes "") (defvar keypression--last-command nil) (defvar keypression--last-command-2 nil) +(defvar keypression--pre-command-keys nil) (defvar keypression--concat-string "") (defvar keypression--prev-frame-alpha-lower-limit 20) @@ -432,7 +433,8 @@ Command filtering logic is in the `keypression-post--command'." "Record the pre-command state. This enables us to differentiate commands that delegate out to other commands by reading before the command and comparing the state during the post command -hook.") +hook." + (setq keypression--pre-command-keys (this-command-keys))) (defun keypression--post-command () (unless (or (memq (event-basic-type last-command-event) @@ -442,7 +444,7 @@ hook.") ;; assume list if not callable. (memq this-command keypression-ignored-commands))) (keypression--push-string - (keypression--keys-to-string (this-command-keys) this-command) + (keypression--keys-to-string keypression--pre-command-keys this-command) this-command))) (cl-defun keypression--create-frame (buffer-or-name From 6a8d57b43b4e18b7775db8a38d487631323ffc6a Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Tue, 21 Nov 2023 12:13:12 +0900 Subject: [PATCH 10/14] purify keypression--same-command Signed-off-by: Psionik K <73710933+psionic-k@users.noreply.github.com> --- keypression.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/keypression.el b/keypression.el index 7cf4d26..0426fc3 100644 --- a/keypression.el +++ b/keypression.el @@ -362,10 +362,10 @@ the command is ignored." (and keypression-concat-digit-argument (memq command '(digit-argument universal-argument universal-argument-more)))) -(defun keypression--same-command-p () +(defun keypression--same-command-p (command) (cond ((keypression--digit-argument-p keypression--last-command)) - ((keypression--digit-argument-p this-command) + ((keypression--digit-argument-p command) (keypression--digit-argument-p keypression--last-command)) ((and (eq this-command keypression--last-command) (not (keypression--digit-argument-p keypression--last-command-2)))))) @@ -391,7 +391,7 @@ Command filtering logic is in the `keypression-post--command'." (digit-arg (keypression--digit-argument-p command)) (before-digit-arg (keypression--digit-argument-p keypression--last-command))) (cond - ((and (keypression--same-command-p) + ((and (keypression--same-command-p command) (or self-insert same-key digit-arg before-digit-arg)) ;; Just rewrite the bottom line. (let ((str (cond From e89f7f1bb62564a7c1f2e36e125fbbd2eefa1eba Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:38:08 +0900 Subject: [PATCH 11/14] Store pre-command this-command and enable preference before render Signed-off-by: Psionik K <73710933+psionic-k@users.noreply.github.com> --- keypression.el | 49 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/keypression.el b/keypression.el index 0426fc3..d7d1f10 100644 --- a/keypression.el +++ b/keypression.el @@ -218,6 +218,30 @@ the command is ignored." :type '(symbol (list symbol)) :options '(symbol (repeat symbol))) +(defcustom keypression-pre-or-post-command 'post-command + "Show the bound command or what it delegates to? +Either the pre-command or post-command value of `this-command' +can be preferred. The actual key binding is observable during +`pre-command-hook' but sometimes it delegates to another command, +observable during the `post-commnand-hook'. When working on +bindings in the minibuffer, you should use `pre-command` and +when screencasting and showing users which `M-x` commands you used, +set to `post-command`. + +For example, when you call a command via `M-x`, the command to +pick a completion result will delegate to another command. If +you select `next-line', do you want to see `ivy-done' or +`next-line'? Selecting `pre-command` will show exactly what was +bound, even if it's boring, such as `ivy-done'. Selecting +`post-command` will show what these commands delegate to. + +Also see `keypression-post-excepting-pre-commands' for a list of +commands that revert to `pre-command` behavior because they don't +update the value of `this-command'." + :group 'keypression + :type 'symbol + :options '(pre-command post-command)) + ;;; Global variables (defvar keypression--nactives 0) @@ -235,6 +259,7 @@ the command is ignored." (defvar keypression--last-keystrokes "") (defvar keypression--last-command nil) (defvar keypression--last-command-2 nil) +(defvar keypression--pre-command-command) (defvar keypression--pre-command-keys nil) (defvar keypression--concat-string "") @@ -371,6 +396,7 @@ the command is ignored." (not (keypression--digit-argument-p keypression--last-command-2)))))) (defun keypression--push-back-self-insert-string (str &optional separator) + "Append SEPARATOR and STR to `keypression--concat-string'." (cl-callf concat keypression--concat-string (when (and separator (< 0 (length keypression--concat-string))) separator) @@ -434,18 +460,23 @@ Command filtering logic is in the `keypression-post--command'." This enables us to differentiate commands that delegate out to other commands by reading before the command and comparing the state during the post command hook." + (setq keypression--pre-command-command this-command) (setq keypression--pre-command-keys (this-command-keys))) (defun keypression--post-command () - (unless (or (memq (event-basic-type last-command-event) - keypression-ignore-mouse-events) - (if (functionp keypression-ignored-commands) - (funcall keypression-ignored-commands this-command) - ;; assume list if not callable. - (memq this-command keypression-ignored-commands))) - (keypression--push-string - (keypression--keys-to-string keypression--pre-command-keys this-command) - this-command))) + (let ((command (if (eq keypression-pre-or-post-command 'pre-command) + keypression--pre-command-command + this-command))) + (unless (or (memq (event-basic-type last-command-event) + keypression-ignore-mouse-events) + (if (functionp keypression-ignored-commands) + (funcall keypression-ignored-commands command) + ;; assume list if not callable. + (memq this-command keypression-ignored-commands))) + (keypression--push-string + (keypression--keys-to-string + keypression--pre-command-keys command) + command)))) (cl-defun keypression--create-frame (buffer-or-name &key From 39947fd97031ffd277312a6243f3694c17932b38 Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:38:36 +0900 Subject: [PATCH 12/14] pre commands that require exception of the post command The value of `this-command` is not updated by every bound command. Commands such as `counsel-M-x` and `universal-argument` do not update `this-command` and so we must use the value of `this-command` we stored during the pre-command hook. Signed-off-by: Psionik K <73710933+psionic-k@users.noreply.github.com> --- keypression.el | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/keypression.el b/keypression.el index d7d1f10..0638f55 100644 --- a/keypression.el +++ b/keypression.el @@ -242,6 +242,25 @@ update the value of `this-command'." :type 'symbol :options '(pre-command post-command)) +(defcustom keypression-post-excepting-pre-commands + `(counsel-M-x + universal-argument-more + universal-argument + digit-argument + execute-extended-command + ;; whatever the user's `M-x` remap is + ,(command-remapping 'execute-extended-command)) + "A list of commands that require some exception behavior. +When `keypression-log-preference' is set to `post-command` but +the command we observe in the `post-command-hook' is a member of +this list, the value of `this-command' has not been updated or is +invalid. In these cases, we fall back to `pre-command` behavior +and show the value of `this-command' logged in the +`pre-command-hook'. One common case is +`execute-extended-command' and it's usual re-mappings." + :group 'keypression + :type '(repeat symbol)) + ;;; Global variables (defvar keypression--nactives 0) @@ -466,7 +485,10 @@ hook." (defun keypression--post-command () (let ((command (if (eq keypression-pre-or-post-command 'pre-command) keypression--pre-command-command - this-command))) + (if (member keypression--pre-command-command + keypression-post-excepting-pre-commands) + keypression--pre-command-command + this-command)))) (unless (or (memq (event-basic-type last-command-event) keypression-ignore-mouse-events) (if (functionp keypression-ignored-commands) From 591a86a6ab008639eb24cefd54c47555fa84382a Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:41:49 +0900 Subject: [PATCH 13/14] Change internal name and add docstring This one kind of confused me Signed-off-by: Psionik K <73710933+psionic-k@users.noreply.github.com> --- keypression.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/keypression.el b/keypression.el index 0638f55..df633ab 100644 --- a/keypression.el +++ b/keypression.el @@ -406,7 +406,8 @@ and show the value of `this-command' logged in the (and keypression-concat-digit-argument (memq command '(digit-argument universal-argument universal-argument-more)))) -(defun keypression--same-command-p (command) +(defun keypression--digit-prefix-p (command) + "Should we fold digit arguments and commands for COMMAND." (cond ((keypression--digit-argument-p keypression--last-command)) ((keypression--digit-argument-p command) @@ -436,7 +437,7 @@ Command filtering logic is in the `keypression-post--command'." (digit-arg (keypression--digit-argument-p command)) (before-digit-arg (keypression--digit-argument-p keypression--last-command))) (cond - ((and (keypression--same-command-p command) + ((and (keypression--digit-prefix-p command) (or self-insert same-key digit-arg before-digit-arg)) ;; Just rewrite the bottom line. (let ((str (cond From a5911d38ea3b2e1f05565ad4855a30e09ed39bcb Mon Sep 17 00:00:00 2001 From: Psionik K <73710933+psionic-k@users.noreply.github.com> Date: Tue, 21 Nov 2023 15:36:55 +0900 Subject: [PATCH 14/14] docstrings, package lints Signed-off-by: Psionik K <73710933+psionic-k@users.noreply.github.com> --- keypression.el | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/keypression.el b/keypression.el index df633ab..4e2c89d 100644 --- a/keypression.el +++ b/keypression.el @@ -424,8 +424,9 @@ and show the value of `this-command' logged in the (defun keypression--push-string (keys command) "Push string handles rendering and collapsing repeats. -It converts `self-insert-command' and digit prefix arguments. -Command filtering logic is in the `keypression-post--command'." +It configures animation state when new commands are to be +displayed. Repeats, strings, and digit arguments may be merged. +KEYS and COMMAND are decided in `keypression--post-command'." (let* ((string (if (and keypression-cast-command-name command) (format keypression-cast-command-name-format keys command) @@ -516,7 +517,7 @@ hook." respect-header-line respect-mode-line respect-tab-line) - "Create a frame. Copied from posframe." + "Create a frame. Copied from posframe." (let ((left-fringe (or left-fringe 0)) (right-fringe (or right-fringe 0)) (internal-border-width (or internal-border-width 0))