diff --git a/.github/flake.lock b/.github/flake.lock
index a033b73..0c87c29 100644
--- a/.github/flake.lock
+++ b/.github/flake.lock
@@ -7,14 +7,15 @@
],
"nixpkgs": [
"nixpkgs"
- ]
+ ],
+ "nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
- "lastModified": 1670637348,
- "narHash": "sha256-4FLOEi02WS+St6i1MSUxGfA32FL1SFIpwWCDsABAZkk=",
+ "lastModified": 1700039860,
+ "narHash": "sha256-khtUI3bCyjaXTviQBhd0m991Tj/GWDB6c535LdCin1I=",
"owner": "nix-community",
"repo": "emacs-overlay",
- "rev": "3a0b5dd7756173e63c2bbbe70dd5484a7463257d",
+ "rev": "accc684eb6fceac1b504fc6bec7298263dae3f86",
"type": "github"
},
"original": {
@@ -40,11 +41,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1670482022,
- "narHash": "sha256-xzzjWulnNMCSTEGosGaAg7sLsAtF7stA3sQljZ410/w=",
+ "lastModified": 1688392541,
+ "narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "c50e5b63e9d65ff0e70cc06b7042a72c6a6583bc",
+ "rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b",
"type": "github"
},
"original": {
@@ -54,6 +55,22 @@
"type": "github"
}
},
+ "nixpkgs-stable": {
+ "locked": {
+ "lastModified": 1699596684,
+ "narHash": "sha256-XSXP8zjBZJBVvpNb2WmY0eW8O2ce+sVyj1T0/iBRIvg=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "da4024d0ead5d7820f6bd15147d3fe2a0c0cec73",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-23.05",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
"root": {
"inputs": {
"emacs-overlay": "emacs-overlay",
diff --git a/.github/flake.nix b/.github/flake.nix
index 121ba0e..bd51f18 100644
--- a/.github/flake.nix
+++ b/.github/flake.nix
@@ -21,7 +21,7 @@
description = "This flake provides CI & local development dependencies";
inputs = {
- nixpkgs.url = "github:nixos/nixpkgs?ref=release-22.11";
+ nixpkgs.url = "github:nixos/nixpkgs?ref=release-23.05";
flake-utils.url = "github:numtide/flake-utils";
emacs-overlay = {
url = "github:nix-community/emacs-overlay";
@@ -42,7 +42,7 @@
emacsPackages = [
"emacs"
- "emacsGit" # to see changes in upstreams
+ "emacs29" # to see changes in upstreams
];
devShells = pkgs.lib.genAttrs emacsPackages (emacsPkg:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 913bb9b..97e981d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -36,7 +36,7 @@ jobs:
strategy:
matrix:
os: [ ubuntu-latest ]
- emacsPkg: [ emacs, emacsGit ]
+ emacsPkg: [ emacs, emacs29 ]
runs-on: ${{ matrix.os }}
steps:
@@ -58,10 +58,10 @@ jobs:
# Linting the package is less useful on multiple version. Modify the
# logic if you wish to expand lint coverage.
- name: lint package
- if: matrix.emacsPkg == 'emacs'
+ if: matrix.emacsPkg == 'emacs29'
run: |
eval "$(nix print-dev-env \
- --override-input nixpkgs github:nixos/nixpkgs/release-22.11 \
+ --override-input nixpkgs github:nixos/nixpkgs/release-23.05 \
--update-input emacs-overlay \
.github#${{ matrix.emacsPkg }})"
@@ -71,7 +71,7 @@ jobs:
- name: load package
run: |
eval "$(nix print-dev-env \
- --override-input nixpkgs github:nixos/nixpkgs/release-22.11 \
+ --override-input nixpkgs github:nixos/nixpkgs/release-23.05 \
--update-input emacs-overlay \
.github#${{ matrix.emacsPkg }})"
diff --git a/README.org b/README.org
index 8bcaadf..7c70c2e 100644
--- a/README.org
+++ b/README.org
@@ -4,10 +4,10 @@
#+HTML:
#+HTML:
-Please see the [[https://github.com/tarsius/keycast/tree/master][keycast]] package, which has options to display in a posframe,
-headline, or modeline. It's a pretty well written package. This package was
-started to clean up the [[https://github.com/lewang/command-log-mode][command-log-mode]] package that is still ranking highly in
-a lot of search results.
+Please see the [[https://github.com/tarsius/keycast/tree/master][keycast]] and [[https://github.com/chuntaro/emacs-keypression][keypression]] package, which has options to display in
+a posframe, headline, or modeline. It's a pretty well written package. This
+package was forked to clean up the [[https://github.com/lewang/command-log-mode][command-log-mode]] package that is still
+ranking highly in a lot of search results.
** What it do?
@@ -28,17 +28,16 @@ a lot of search results.
should support pointing at specific repositories) to use this repo.
#+begin_src elisp
+ ;; using elpaca (recommended to add a hash for reproducibility)
+ (use-package
+ :elpaca (command-log
+ :host github
+ :repo "positron-solutions/command-log"))
;; using straight use-package with custom recipe
(use-package command-log
:straight '(command-log
:type git :host github :repo "positron-solutions/command-log"))
-
- ;; using elpaca (recommended to add a hash for reproducibility)
- (elpaca-use-package
- (command-log :host github
- :repo "positron-solutions/command-log"))
-
#+end_src
** How do I use it?
@@ -49,21 +48,27 @@ a lot of search results.
Customize the =command-log= group for more options.
#+begin_src elisp
-
(use-package command-log
- :custom
- (command-log-window-text-scale 2 "Command log two steps higher text scale")
- (command-log-logging-shows-buffer t "Toggling will show the buffer.")
- (command-log-hiding-disables-logging t "Toggling visible buffer turns off logging.")
- (command-log-disabling-logging-kills-buffer t "The buffer will be new when displayed again.")
- (command-log-log-globally t "Auto-enable with global minor mode (including minibuffer)")
- (command-log-filter-commands '(self-insert-command) "Be chatty.
- Show everything besides self-insert-command"))
-
+ :config
+ (setopt command-log-filter-commands '(self-insert-command) ; commands you don't care about
+ (setopt command-log-mouse t)
+ (setopt command-log-text t) ; print strings rather than streams of `self-insert-command'.
+
+ (setopt command-log-merge-repeats t) ; show repeat counts without making new entries
+ ;; This following option and some related options can be powerful for
+ ;; revealing how commands are delegating out to other commands, such as M-x
+ ;; and ivy. Read the docs ;-)
+ (setopt command-log-merge-repeat-targets 'post-command)
#+end_src
- You can reveal all commands by running [M-x]
- =command-log-toggle-show-all-commands=.
+*** Unveiling More Details
+
+ You can reveal all commands temporarily by running [M-x]
+ ~command-log-toggle-show-all~. It overrides several behaviors to try to reveal
+ more.
+
+ There is also ~command-log-tail-dribble~ if you need to see your inputs for
+ debugging. Don't forget about simple ~view-lossage~ and refreshing with =g=.
Commands to toggle buffer showing and to turn everything off without doing it
on every toggle are sorely needed. PR's welcome!
@@ -71,7 +76,7 @@ a lot of search results.
** License
All post-fork work is GPL licensed. This increasingly covers most of the
- package. The CI is MIT licensed for ease of use. See [[./CONTRIBUTING.org][CONTRIBUTING.org]] for
+ package. The CI is MIT licensed for convenience. See [[./CONTRIBUTING.org][CONTRIBUTING.org]] for
information about submitting changes correctly.
This package is a fork of [[http://www.foldr.org/~michaelw/emacs/mwe-log-commands.el][mwe-log-commands.el]] by Michael Weber
diff --git a/command-log.el b/command-log.el
index 6974645..de82e6d 100644
--- a/command-log.el
+++ b/command-log.el
@@ -1,19 +1,21 @@
;;; command-log.el --- Log user inputs & commands -*- lexical-binding: t -*-
-;; homepage: https://github.com/positron-solutons/command-log
-
-;; Copyright (C) 2022 Positron Solutions
+;; Copyright (C) 2022-2023 Positron Solutions
;; Copyright (C) 2013 Nic Ferrier
;; Copyright (C) 2012 Le Wang
;; Copyright (C) 2004 Free Software Foundation, Inc.
-;; Author: Michael Weber
-;; Keywords: help docs
-;; Version: 0.1.0
+;; Author: Michael Weber
+;; Maintainer: Positron Solutions
+;; Keywords: help, docs
+;; Version: 0.2.0
;; Package-Requires: ((emacs "28.0"))
+;; homepage: https://github.com/positron-solutons/command-log
;; Initial-version: <2004-10-07 11:41:28 michaelw>
;; Time-stamp: <2004-11-06 17:08:11 michaelw>
+;; This file is not part of GNU Emacs.
+
;; This program is free software: you can redistribute it and/or modify it under
;; the terms of the GNU General Public License as published by the Free Software
;; Foundation, either version 3 of the License, or (at your option) any later
@@ -30,7 +32,7 @@
;;; Commentary:
;; This package is an updated fork of `command-log-mode'. Also see the
-;; `keycast' package.
+;; `keycast' and `keypression' packages.
;; This add-on can be used to demo Emacs to an audience. When activated,
;; keystrokes get logged into a designated buffer, along with the command bound
@@ -48,6 +50,7 @@
;;; Code:
+(require 'autorevert)
(require 'cl-lib)
(require 'comint)
(require 'button)
@@ -61,97 +64,272 @@
:prefix 'command-log
:group 'convenience)
-(defcustom command-log-window-size 40
- "The size of the command-log window."
- :group 'command-log
- :type 'integer)
-
(defcustom command-log-default-side 'right
"Which side for use in `display-buffer-in-side-window'."
:group 'command-log
:type 'symbol
:options '(right left top bottom))
-(defcustom command-log-window-text-scale 0
- "The text scale of the command-log window.
+(define-obsolete-variable-alias 'command-log-window-text-scale
+ 'command-log-text-scale "0.2.0")
+
+(define-obsolete-variable-alias 'command-log-mode-window-font-size
+ 'command-log-text-scale "0.2.0")
+
+(defcustom command-log-text-scale 0
+ "The text scale of the command-log output.
+1,+2,... increase and -1,-2,... decrease the font size."
:group 'command-log
:type 'integer)
-(defcustom command-log-log-command-indentation 11
- "Indentation of commands in command log buffer."
+(defcustom command-log-repeat-format " #%s"
+ "How to display repeats."
+ :group 'command-log
+ :type 'string)
+
+(defcustom command-log-keys-min-width 8
+ "How wide to make keys.
+One way to help indentation. Default will align up to two chords
+with a trailing space."
:group 'command-log
:type 'integer)
+(defcustom command-log-text-format "\"%s\""
+ "How to display text.
+Only applies when `command-log-text' is non-nil."
+ :group 'command-log
+ :type 'string)
+
+(defcustom command-log-text-space "␣"
+ "How to draw spaces in text."
+ :group 'command-log
+ :type 'string)
+
(defface command-log-key-face
'((t :inherit 'font-lock-keyword-face))
"Face for keys in command log."
:group 'command-log)
(defface command-log-command-face
- '((t :inherit font-lock-doc-markup-face))
+ '((t :inherit font-lock-function-name-face))
"Face for commands in command log."
:group 'command-log)
(defface command-log-repeat-face
- '((t :inherit 'font-lock-doc-face))
+ '((t :inherit 'shadow))
"Face for commands in command log."
:group 'command-log)
+(defface command-log-text-face
+ '((t :inherit 'font-lock-string-face))
+ "Face for text echo'ing in the command log."
+ :group 'command-log)
+
+(define-obsolete-variable-alias 'clm/time-string
+ 'command-log-time-string "0.2.0")
+
(defcustom command-log-time-string "%Y-%m-%dT%H:%M:%S"
- "The string sent to `format-time-string' when command time is logged."
+ "Sent to `format-time-string' if time logging enabled."
+ :group 'command-log
+ :type 'string)
+
+(defcustom command-log-max-log-lines 256
+ "Set higher if you need to save long sessions."
:group 'command-log
:type 'string)
-(defcustom command-log-logging-shows-buffer t
+(define-obsolete-variable-alias 'command-log-mode-auto-show
+ 'command-log-enable-shows "0.2.0")
+
+(defcustom command-log-enable-shows t
"Turning on logging shows the buffer if it's not visible."
:group 'command-log
:type 'boolean)
-(defcustom command-log-hiding-disables-logging t
+(define-obsolete-variable-alias 'command-log-hiding-disables-logging
+ 'command-log-hide-disables "0.2.0")
+
+(defcustom command-log-hide-disables t
"Hiding the buffer deactivates logging modes."
:group 'command-log
:type 'boolean)
-(defcustom command-log-disabling-logging-kills-buffer t
+(define-obsolete-variable-alias 'command-log-disabling-logging-kills-buffer
+ 'command-log-disable-kills "0.2.0")
+
+(defcustom command-log-disable-kills t
"Turning off all logging kills the buffer."
:group 'command-log
:type 'boolean)
-(defcustom command-log-log-globally t
- "Does turning on `command-log-mode' happen globally?"
+(define-obsolete-variable-alias 'command-log-log-globally
+ 'command-log-prefer-global "0.2.0")
+
+(defcustom command-log-prefer-global t
+ "When logging is enabled automatically, is it global?"
:group 'command-log
:type 'boolean)
-(defcustom command-log-filter-commands
+
+(define-obsolete-variable-alias 'clm/log-command-exceptions*
+ 'command-log-ignored "0.2.0")
+
+(define-obsolete-variable-alias 'command-log-filter-commands
+ 'command-log-ignored "0.2.0")
+
+(defcustom command-log-ignored
'(self-insert-command
handle-switch-frame)
- "A list commands which should not be logged, despite logging being enabled.
-Frequently used non-interesting commands (like cursor movements)
-should be put here."
+ "A list commands which should be ignored.
+For `self-insert-command', logging text overrides this."
:group 'command-log
:type '(repeat (symbol :tag "command function name")))
-(defcustom command-log-log-text nil
+
+(define-obsolete-variable-alias 'command-log-log-text 'command-log-text "0.2.0")
+
+(define-obsolete-variable-alias 'clm/log-text 'command-log-text "0.2.0")
+
+(defcustom command-log-text nil
"Log text as strings instead of `self-insert-commands'.
You may want to just except `self-insert-command' by adding it to
`command-log-filter-commands'."
:group 'command-log
:type 'boolean)
-(defcustom command-log-log-mouse nil
+(define-obsolete-variable-alias 'command-log-log-mouse 'command-log-muose
+ "0.2.0")
+
+(defcustom command-log-mouse nil
"Log mouse events.
Toggling this is more conveneint than setting `command-log-ignored-commands'."
:group 'command-log
:type 'boolean)
+(define-obsolete-variable-alias 'clm/log-repeat 'command-log-merge-repeats
+ "0.2.0")
+
(defcustom command-log-merge-repeats t
"Merge repetitions of the same command."
:group 'command-log
:type 'boolean)
-(defcustom command-log-logging-dir (locate-user-emacs-file
- "var/command-log-mode/")
+(defcustom command-log-pre-command-target 'this-command
+ "Symbol to report during the pre-command.
+When non-nil, the symbol will be read during the
+`pre-command-hook'. Normally we are interested in
+`this-command', but special debugging circumstances may be
+interested in `last-repeatable-command' or `this-real-command'
+etc. Any Lisp variable that is always bound will work, but could
+break features such as text logging, which watch for
+`self-insert-command' in the post-command.
+
+Experience shows that many commands which delegate out to other
+commands, such `ivy-done' or lispy commands, will have the effect
+of resetting `this-command' and `this-real-command' both between
+the pre & post command hook. In the pre-command hook we see the
+command that was called, but for commands such as \`M-x', it' is
+potentially not interesting to see the pre-command `this-command'
+value, such as `ivy-done', the result of pressing \`RET' in an
+\`M-x' menu.
+
+The following is a log output of all likely events you will want
+to log during the pre and post command:
+
+;; pre-command-hook:
+;; this-command: ivy-done
+;; real-this-command: ivy-done
+;; real-last-command: self-insert-command
+;; last-repeatable-command: self-insert-command
+;;
+;; post-command-hook:
+;; this-command: next-line
+;; real-this-command: next-line
+;; real-last-command: self-insert-command
+;; last-repeatable-command: self-insert-command
+
+Note: `self-insert-command' was the actual command that preceded
+pressing \`RET' to cause an `ivy-done' command.
+`real-last-command' is not terribly interesting. It does not
+change between the pre & post command hooks in any observed
+cases.
+
+However, also note that `real-this-command' was modified between
+pre & post-command hooks. This contradicts the semantic meaning
+and docstring of `real-this-command'. Practically, we don't care
+because we caught the change via the `pre-command-hook' rather
+than blindly trusting the words of the `real-last-command'
+docstring author. We obtain a useful result, and that is what
+matters.
+
+\`M-x' is known to not update `this-command' in the case of
+counsel's \`M-x' command.
+
+When developing a package, you may be very interested in
+different values pre and post command. It is very easy to modify
+the point that values are recorded to fit your use case. See the
+body of `command-log--log-pre-command' and
+`command-log--log-post-command' and submit a patch if you find a
+use case for making these support function calls for example.
+
+See `command-log-merge-targets' information about output
+formatting."
+ :group 'command-log
+ :type 'symbol)
+
+(defcustom command-log-post-command-target 'this-command
+ "Symbol to report during the post-command.
+When non-nil, the symbol will be read during the
+`post-command-hook'. Normally we are interested in
+`this-command', but special debugging circumstances may be
+interested in `last-repeatable-command' or `this-real-command'
+etc. Any Lisp variable that is always bound will work.
+
+See `command-log-pre-command-target' for more information."
+ :group 'command-log
+ :type 'symbol)
+
+(defcustom command-log-merge-repeat-targets 'post-command
+ "Controls merging behavior when targets match or not.
+We can prefer the `'pre-command' or the `'post-command'. Setting
+to `'nil' or `'both' will not merge the values at all. The
+pre-command will be first in the output.
+
+When `command-log-pre-command-target' and
+`command-log--log-post-command' target are the same or different,
+how should we behave? Since the user did not press additional
+keys, there are no inputs, we will only display keys once. The
+same is true for repeats, but the repeat counter will only count
+a repeat if everything matches. Since the pre-command comes
+before the post-command, we always show the pre-command before
+the post command when both are shown.
+
+See `command-log-post-excepting-pre-commands' for information
+about commands that will override the setting of `'post-command'."
+ :group 'command-log
+ :type 'symbol
+ :options '(pre-command post-command both))
+
+(defcustom command-log-post-excepting-pre-commands
+ `(counsel-M-x
+ execute-extended-command
+ ,(command-remapping 'execute-extended-command)) ; whatever the user's remap is
+ "A list of commands that do not update `this-command'.
+We decline to print the post-command value when the pre-command
+value of `this-command' is a member of this list. It's tricky.
+There isn't a great way to detect this. The only known use is
+however terribly common, `execute-extended-command' and it's
+re-mappings."
+ :group 'command-log
+ :type '(repeat symbol))
+
+(define-obsolete-variable-alias 'command-log-logging-dir
+ 'command-log-save-dir "0.2.0")
+
+(define-obsolete-variable-alias 'clm/logging-dir 'command-log-save-dir "0.2.0")
+
+(defcustom command-log-save-dir (locate-user-emacs-file
+ "var/command-log-mode/")
"Directory in which to store files containing logged commands."
:group 'command-log
:type 'directory)
@@ -164,18 +342,42 @@ Toggling this is more conveneint than setting `command-log-ignored-commands'."
(defvar command-log--command-repetitions 0
"Count of how often the last keyboard commands has been repeated.")
-(defvar command-log--last-keyboard-command nil
- "Last logged keyboard command.")
+(defvar command-log--pre-command nil
+ "Command after remapping.")
+
+(defvar command-log--pre-command-keys nil
+ "Command keys after remapping.")
+
+(defvar command-log--last-pre-command nil
+ "Last logged pre command.")
+
+(defvar command-log--last-post-command nil
+ "Last logged post command.")
(defvar command-log--last-command-keys nil
"Last key description for `this-command-keys'.")
-(defvar command-log--recent-history-string ""
+(defvar command-log--repeat-start-marker nil
+ "Marker for updating the repeat counter.")
+
+(defvar command-log--repeat-end-marker nil
+ "Marker for updating the repeat counter.")
+
+(defvar command-log--self-insert-start nil
+ "Marker for updating sequences of `self-insert-command'.")
+
+(defvar command-log--self-insert-end nil
+ "Marker for updating sequences of `self-insert-command'.")
+
+(defvar command-log--self-insert-string ""
"This string will hold recently typed text.")
(defvar command-log--show-all-commands nil
"Override `command-log-filter-commands' and show all commands instead.")
+(defvar command-log--last-log-marker nil
+ "Saving our location so we can update repeat commands.")
+
(declare-function helpful-at-point "helpful" ())
(defun command-log--push-button ()
"Open help for command at point.
@@ -204,10 +406,14 @@ Use `helpful' package if loaded."
:init-value nil
:lighter " command-log"
:keymap nil
- (if command-log-mode
- (add-hook 'pre-command-hook
- #'command-log--log-command 'default-depth)
- (remove-hook 'pre-command-hook #'command-log--log-command)))
+ (cond (command-log-mode
+ (add-hook 'pre-command-hook
+ #'command-log--log-pre-command 'default-depth)
+ (add-hook 'post-command-hook
+ #'command-log--log-post-command 'default-depth))
+ (t
+ (remove-hook 'pre-command-hook #'command-log--log-pre-command)
+ (remove-hook 'post-command-hook #'command-log--log-post-command))))
;;;###autoload
(define-globalized-minor-mode global-command-log-mode command-log-mode command-log-mode
@@ -220,7 +426,7 @@ Use `helpful' package if loaded."
The following variables are used to configure this toggle:
-`command-log-log-globally' controls the preference for
+`command-log-prefer-global' controls the preference for
`command-log-mode` minor mode or `global-command-log-mode.
`command-log-open-log-turns-on-mode' will activate modes if
showing the log buffer. `command-log-close-log-turns-off-mode'
@@ -232,27 +438,40 @@ Passing a prefix CLEAR will clear the buffer before display."
(progn
(command-log--hide-buffer)
(when command-log-hiding-disables-logging
- (if command-log-log-globally
+ (if command-log-prefer-global
(global-command-log-mode nil)
(command-log-mode nil))
(when command-log-disabling-logging-kills-buffer
(command-log--hide-buffer t))))
(progn
- (if command-log-log-globally
+ (if command-log-prefer-global
(global-command-log-mode t)
(command-log-mode t))
- (when command-log-logging-shows-buffer
+ (when command-log-enable-shows
(command-log--show-buffer clear)))))
+(declare-function 'clm/toggle-command-log-buffer "command-log-mode" ())
+(declare-function 'clm/open-command-log-buffer "command-log-mode" ())
+(define-obsolete-function-alias
+ 'clm/toggle-command-log-buffer #'command-log-toggle "0.2.0")
+(define-obsolete-function-alias
+ 'clm/open-command-log-buffer #'command-log-toggle "0.2.0")
+
;;;###autoload
-(defun command-log-close-command-log-buffer (&optional kill)
+(defun command-log-close-buffer (&optional kill)
"Close the command log window.
Prefix argument will KILL buffer."
(interactive "P")
(command-log--hide-buffer kill))
+(declare-function 'clm/close-command-log-buffer "command-log-mode" ())
+(define-obsolete-function-alias
+ 'clm/close-command-log-buffer #'command-log-close-buffer "0.2.0")
+(define-obsolete-function-alias
+ 'command-log-close-command-log-buffer #'command-log-close-buffer "0.2.0")
+
;;;###autoload
-(defun command-log-command-log-clear ()
+(defun command-log-clear ()
"Clear the command log buffer."
(interactive)
(let ((buffer (command-log--get-buffer)))
@@ -261,7 +480,7 @@ Prefix argument will KILL buffer."
(erase-buffer)))))
;;;###autoload
-(defun command-log-toggle-show-all-commands (&optional arg)
+(defun command-log-toggle-show-all (&optional arg)
"Override `command-log-filter-commands' and show everything.
ARG can be passed for direct setting."
(interactive)
@@ -274,15 +493,18 @@ ARG can be passed for direct setting."
(format "Show all commands: %s" command-log--show-all-commands)
'face 'success)))))
+(define-obsolete-function-alias
+ 'command-log-toggle-show-all-commands #'command-log-toggle-show-all "0.2.0")
+
;;;###autoload
-(defun command-log-save-command-log ()
+(defun command-log-save ()
"Save commands to today's log.
Clears the command log buffer after saving."
(interactive)
(let ((buffer (command-log--get-buffer)))
(when buffer
(with-current-buffer buffer
- (make-directory command-log-logging-dir :parents)
+ (make-directory command-log-save-dir :parents)
(goto-char (point-min))
(let ((now (format-time-string "%Y-%02m-%02d %02H:%02M:%02S"))
(write-region-annotate-functions '(command-log--line-time)))
@@ -290,7 +512,7 @@ Clears the command log buffer after saving."
(not (eobp)))
(append-to-file (line-beginning-position)
(1+ (line-end-position))
- (concat command-log-logging-dir now))))
+ (concat command-log-save-dir now))))
(when (y-or-n-p "Erase buffer?")
(erase-buffer))))))
@@ -360,12 +582,6 @@ KILL will kill the buffer after deleting its window."
(when kill
(kill-buffer buffer)))))
-(defun command-log--push-history ()
- "Push the character entered into the buffer into the recent history."
- (setq command-log--recent-history-string
- (concat command-log--recent-history-string
- (key-description (this-command-keys)))))
-
(defun command-log--mouse-event-p (event)
"Return t if EVENT is mouse event.
Emacs `mouse-event-p' reports nil for movement."
@@ -384,11 +600,11 @@ EVENT is the last input event that triggered the command."
(buffer-local-value 'major-mode (current-buffer)))))
(or command-log--show-all-commands
(and (not in-log-buffer)
- (or (if command-log-log-mouse
+ (or (if command-log-mouse
(not filtered)
(and (not mouse)
(not filtered)))
- (and command-log-log-text text))))))
+ (and command-log-text text))))))
(defun command-log--scroll-buffer-windows ()
"Move `point' to end of windows containing log buffer."
@@ -404,74 +620,167 @@ EVENT is the last input event that triggered the command."
(when (or command-log--show-all-commands
(not (member cmd command-log-filter-commands))
(not (eq cmd #'self-insert-command)))
- (setq command-log--recent-history-string "")))
-
-(defun command-log--log-command (&optional cmd)
- "Log CMD to the command-log--buffer."
+ (setq command-log--self-insert-string "")))
+
+(defun command-log--format-command (cmd)
+ "Make CMD human pretty and clickable."
+ (if (byte-code-function-p cmd)
+ (propertize "" 'face 'command-log-command-face)
+ (propertize (symbol-name cmd)
+ 'face 'command-log-command-face
+ 'button '(t)
+ 'category 'default-button)))
+
+(defun command-log--log-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."
+ (setq command-log--pre-command-keys (key-description (this-command-keys)))
+ (setq command-log--pre-command (symbol-value command-log-pre-command-target)))
+
+(defun command-log--log-post-command ()
+ "Write the command information to the output."
(let ((deactivate-mark nil) ; do not deactivate mark in transient mark mode
- ;; Don't let random commands change `this-command' Emacs global
- ;; variables by creating local lexical variables with their values.
- (this-command this-command)
(buffer (command-log--get-buffer))
- (cmd (or cmd this-command))
+ (pre-cmd command-log--pre-command)
+ (post-cmd (symbol-value command-log-post-command-target))
(event last-command-event)
- (keys (key-description (this-command-keys))))
- (when (and buffer (command-log--should-log-command-p cmd event))
+ (keys command-log--pre-command-keys))
+ ;; During updates, use `real-this-command' for logic in case the user
+ ;; has selected some random value for the targets.
+ (when (and buffer (command-log--should-log-command-p real-this-command event))
(with-current-buffer buffer
(goto-char (point-max))
(cond ((and command-log-merge-repeats
- (not (and command-log-log-text
- (eq cmd #'self-insert-command)
+ (not (and command-log-text
+ (eq post-cmd #'self-insert-command)
(not command-log--show-all-commands)))
- (and (eq cmd command-log--last-keyboard-command)
+ ;; must completely match
+ (and (eq pre-cmd command-log--last-pre-command)
+ (eq post-cmd command-log--last-post-command)
(string= keys command-log--last-command-keys)))
+ ;; Either set up repeat or delete marked region of old repeat and
+ ;; re-insert between markers.
(cl-incf command-log--command-repetitions)
- (save-match-data
- (when (and (> command-log--command-repetitions 1)
- (search-backward "[" (line-beginning-position -1) t))
- (delete-region (point) (line-end-position))))
- (backward-char) ; skip over either ?\newline or ?\space before ?\[
- (insert (propertize (concat " ["
- (number-to-string (1+ command-log--command-repetitions))
- " times]")
+ (if (> command-log--command-repetitions 1)
+ (progn (delete-region command-log--repeat-start-marker
+ command-log--repeat-end-marker)
+ (goto-char command-log--repeat-start-marker))
+ (backward-char)
+ (setq command-log--repeat-start-marker (point-marker)
+ command-log--repeat-end-marker (point-marker))
+ (set-marker-insertion-type command-log--repeat-end-marker t))
+ (insert (propertize (format command-log-repeat-format
+ (1+ command-log--command-repetitions))
'face 'command-log-repeat-face)))
- ((and (and command-log-log-text (not command-log--show-all-commands))
- (eq cmd #'self-insert-command))
- (when (eq command-log--last-keyboard-command #'self-insert-command)
- (delete-char -1)
- (delete-region (line-beginning-position) (line-end-position)))
- (setq command-log--recent-history-string
- (concat command-log--recent-history-string (kbd keys)))
- (setq command-log--last-keyboard-command cmd)
- (setq command-log--last-command-keys keys)
- (insert (propertize
- (concat "[text: " command-log--recent-history-string "]\n")
- 'face 'command-log-repeat-face)))
+
+ ((and (and command-log-text (not command-log--show-all-commands))
+ (eq post-cmd #'self-insert-command))
+ ;; TODO the only reason we can't log text and all commands
+ ;; simultaneously is because of this condition statement.
+
+ ;; Either set up string or delete marked region of old string and
+ ;; re-insert between markers.
+ (if (eq command-log--last-post-command #'self-insert-command)
+ (progn (delete-region command-log--self-insert-start
+ command-log--self-insert-end)
+ (goto-char command-log--self-insert-start))
+ (setq command-log--self-insert-start (point-marker)
+ command-log--self-insert-end (point-marker))
+ (set-marker-insertion-type command-log--self-insert-end t))
+ (setq command-log--self-insert-string
+ (concat command-log--self-insert-string (kbd keys)))
+ (insert
+ (propertize
+ (format
+ command-log-text-format
+ ;; 32 is space and I always wish I could write it more
+ ;; explicitly lol
+ (subst-char-in-string 32
+ (string-to-char command-log-text-space)
+ command-log--self-insert-string)
+ 'face 'command-log-text-face)))
+ (newline))
(t
- (setq command-log--command-repetitions 0)
(insert
(propertize
keys
:time (format-time-string command-log-time-string (current-time))
'face 'command-log-key-face))
- (when (>= (current-column) command-log-log-command-indentation)
- (newline))
- (move-to-column command-log-log-command-indentation t)
- (insert
- (if (byte-code-function-p cmd)
- (propertize "" 'face 'command-log-command-face)
- (propertize (symbol-name cmd)
- 'face 'command-log-command-face
- 'button '(t)
- 'category 'default-button)))
+
+ (when (< (length keys) command-log-keys-min-width)
+ (insert (make-string (- command-log-keys-min-width
+ (length keys))
+ 32)))
+ (when (>= (length keys) command-log-keys-min-width)
+ (insert 32))
+
+ (if (and (not (eq pre-cmd post-cmd))
+ (not (member
+ pre-cmd
+ command-log-post-excepting-pre-commands))
+ (eq command-log-merge-repeat-targets 'post-command))
+ (insert (command-log--format-command post-cmd))
+ (insert (command-log--format-command pre-cmd)))
(newline)
- (setq command-log--last-command-keys keys)
- (setq command-log--last-keyboard-command cmd)))
- (when (> (count-lines (point-min) (point-max)) comint-max-line-length)
- (goto-char (point-min))
- (delete-line))
- (command-log--zap-recent-history cmd) ; could be inside condition expression
+ (when (and (not (eq pre-cmd post-cmd))
+ (not (member
+ pre-cmd
+ command-log-post-excepting-pre-commands))
+ (not (member command-log-merge-repeat-targets
+ '(pre-command post-command))))
+ (insert (make-string command-log-keys-min-width 32))
+ (insert (command-log--format-command post-cmd))
+ (newline))
+
+ ;; non-string command. unset string tracking.
+ (setq command-log--self-insert-end nil
+ command-log--self-insert-start nil
+ command-log--self-insert-string nil)
+ ;; non-repeat command. unset repetition tracking.
+ (setq command-log--command-repetitions 0
+ command-log--repeat-start-marker nil
+ command-log--repeat-end-marker nil)))
+
+ ;; every non-skipped command updates the last command
+ (setq command-log--last-post-command post-cmd
+ command-log--last-pre-command pre-cmd
+ command-log--last-command-keys keys)
+
+ (when (> (count-lines (point-min) (point-max))
+ command-log-max-log-lines)
+ (delete-region (goto-char (point-min))
+ (progn (forward-line) (point))))
(command-log--scroll-buffer-windows)))))
+(defvar-local command-log--dribble-file nil
+ "Clean up this dribble file.")
+
+(defun command-log--dribble-cleanup ()
+ "Delete `command-log--dribble-file'."
+ (when (file-exists-p command-log--dribble-file)
+ (delete-file command-log--dribble-file )))
+
+;;;###autoload
+(defun command-log-tail-dribble ()
+ "Open a dribble file and tail the contents."
+ (interactive)
+ (let* ((dribble-buffer "*Dribble*")
+ (buffer (get-buffer dribble-buffer)))
+ (if buffer
+ (kill-buffer buffer)
+ (with-current-buffer (get-buffer-create dribble-buffer)
+ (setq-local command-log--dribble-file
+ (make-temp-file "dribble"))
+ (open-dribble-file command-log--dribble-file)
+ (insert-file-contents command-log--dribble-file 'visit)
+ (add-hook 'kill-buffer-hook #'command-log--dribble-cleanup
+ nil 'local)
+ (auto-revert-tail-mode)
+ (setq-local auto-revert-verbose nil
+ buffer-read-only t))
+ (switch-to-buffer-other-window dribble-buffer))))
+
(provide 'command-log)
;;; command-log.el ends here