557 lines
20 KiB
EmacsLisp
557 lines
20 KiB
EmacsLisp
;;; polymode-debug.el --- Interactive debugging utilities for polymode -*- lexical-binding: t -*-
|
||
;;
|
||
;; Copyright (C) 2016-2018 Vitalie Spinu
|
||
;; Author: Vitalie Spinu
|
||
;; URL: https://github.com/vspinu/polymode
|
||
;;
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;;
|
||
;; 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, or
|
||
;; (at your option) any later version.
|
||
;;
|
||
;; This program is distributed in the hope that it will be useful,
|
||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
;; General Public License for more details.
|
||
;;
|
||
;; You should have received a copy of the GNU General Public License
|
||
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||
;;
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;;
|
||
|
||
;;; Commentary:
|
||
;;
|
||
|
||
;;; Code:
|
||
|
||
(require 'polymode-core)
|
||
(require 'poly-lock)
|
||
(require 'trace)
|
||
|
||
|
||
;;; MINOR MODE
|
||
|
||
(defvar pm--underline-overlay
|
||
(let ((overlay (make-overlay (point) (point))))
|
||
(overlay-put overlay 'face '(:underline (:color "tomato" :style wave)))
|
||
overlay)
|
||
"Overlay used in function `pm-debug-mode'.")
|
||
|
||
(defvar pm--highlight-overlay
|
||
(let ((overlay (make-overlay (point) (point))))
|
||
(overlay-put overlay 'face '(:inverse-video t))
|
||
overlay)
|
||
"Overlay used by `pm-debug-map-over-spans-and-highlight'.")
|
||
|
||
(defvar pm-debug-minor-mode-map
|
||
(let ((map (make-sparse-keymap)))
|
||
(define-key map (kbd "M-n M-i") #'pm-debug-info-on-current-span)
|
||
(define-key map (kbd "M-n i") #'pm-debug-info-on-current-span)
|
||
(define-key map (kbd "M-n M-p") #'pm-debug-print-relevant-variables)
|
||
(define-key map (kbd "M-n p") #'pm-debug-print-relevant-variables)
|
||
(define-key map (kbd "M-n M-h") #'pm-debug-map-over-spans-and-highlight)
|
||
(define-key map (kbd "M-n h") #'pm-debug-map-over-spans-and-highlight)
|
||
(define-key map (kbd "M-n M-t t") #'pm-toggle-tracing)
|
||
(define-key map (kbd "M-n M-t i") #'pm-debug-toogle-info-message)
|
||
(define-key map (kbd "M-n M-t f") #'pm-debug-toggle-fontification)
|
||
(define-key map (kbd "M-n M-t p") #'pm-debug-toggle-post-command)
|
||
(define-key map (kbd "M-n M-t c") #'pm-debug-toggle-after-change)
|
||
(define-key map (kbd "M-n M-t a") #'pm-debug-toggle-all)
|
||
(define-key map (kbd "M-n M-t M-t") #'pm-toggle-tracing)
|
||
(define-key map (kbd "M-n M-t M-i") #'pm-debug-toogle-info-message)
|
||
(define-key map (kbd "M-n M-t M-f") #'pm-debug-toggle-fontification)
|
||
(define-key map (kbd "M-n M-t M-p") #'pm-debug-toggle-post-command)
|
||
(define-key map (kbd "M-n M-t M-c") #'pm-debug-toggle-after-change)
|
||
(define-key map (kbd "M-n M-t M-a") #'pm-debug-toggle-all)
|
||
(define-key map (kbd "M-n M-f s") #'pm-debug-fontify-current-span)
|
||
(define-key map (kbd "M-n M-f b") #'pm-debug-fontify-current-buffer)
|
||
(define-key map (kbd "M-n M-f M-t") #'pm-debug-toggle-fontification)
|
||
(define-key map (kbd "M-n M-f M-s") #'pm-debug-fontify-current-span)
|
||
(define-key map (kbd "M-n M-f M-b") #'pm-debug-fontify-current-buffer)
|
||
map))
|
||
|
||
;;;###autoload
|
||
(define-minor-mode pm-debug-minor-mode
|
||
"Turns on/off useful facilities for debugging polymode.
|
||
|
||
Key bindings:
|
||
\\{pm-debug-minor-mode-map}"
|
||
nil
|
||
" PMDBG"
|
||
:group 'polymode
|
||
(if pm-debug-minor-mode
|
||
(progn
|
||
;; this is global hook. No need to complicate with local hooks
|
||
(add-hook 'post-command-hook 'pm-debug-highlight-current-span))
|
||
(delete-overlay pm--underline-overlay)
|
||
(delete-overlay pm--highlight-overlay)
|
||
(remove-hook 'post-command-hook 'pm-debug-highlight-current-span)))
|
||
|
||
;;;###autoload
|
||
(defun pm-debug-minor-mode-on ()
|
||
;; activating everywhere (in case font-lock infloops in a polymode buffer )
|
||
;; this doesn't activate in fundamental mode
|
||
(unless (eq major-mode 'minibuffer-inactive-mode)
|
||
(pm-debug-minor-mode t)))
|
||
|
||
;;;###autoload
|
||
(define-globalized-minor-mode pm-debug-mode pm-debug-minor-mode pm-debug-minor-mode-on)
|
||
|
||
|
||
;;; INFO
|
||
|
||
(cl-defgeneric pm-debug-info (chunkmode))
|
||
(cl-defmethod pm-debug-info (chunkmode)
|
||
(eieio-object-name chunkmode))
|
||
(cl-defmethod pm-debug-info ((chunkmode pm-inner-chunkmode))
|
||
(format "%s head-matcher:\"%s\" tail-matcher:\"%s\""
|
||
(cl-call-next-method)
|
||
(eieio-oref chunkmode 'head-matcher)
|
||
(eieio-oref chunkmode 'tail-matcher)))
|
||
(cl-defmethod pm-debug-info ((_chunkmode pm-inner-auto-chunkmode))
|
||
(cl-call-next-method))
|
||
|
||
(defvar syntax-ppss-wide)
|
||
(defvar syntax-ppss-last)
|
||
(defun pm--debug-info (&optional span as-list)
|
||
(let* ((span (or span (and polymode-mode (pm-innermost-span))))
|
||
(message-log-max nil)
|
||
(beg (nth 1 span))
|
||
(end (nth 2 span))
|
||
(obj (nth 3 span))
|
||
(type (and span (or (car span) 'host))))
|
||
(let ((out (list (current-buffer)
|
||
(point-min) (point) (point-max)
|
||
major-mode
|
||
type beg end
|
||
(and obj (pm-debug-info obj))
|
||
(format "lppss:%s"
|
||
(if pm--emacs>26
|
||
(car syntax-ppss-wide)
|
||
syntax-ppss-last)))))
|
||
(if as-list
|
||
out
|
||
(apply #'format
|
||
"(%s) min:%d pos:%d max:%d || (%s) type:%s span:%s-%s %s %s"
|
||
out)))))
|
||
|
||
(defun pm-debug-info-on-current-span (no-cache)
|
||
"Show info on current span.
|
||
With NO-CACHE prefix, don't use cached values of the span."
|
||
(interactive "P")
|
||
(if (not polymode-mode)
|
||
(message "not in a polymode buffer")
|
||
(let ((span (pm-innermost-span nil no-cache)))
|
||
(message (pm--debug-info span))
|
||
;; (move-overlay pm--highlight-overlay (nth 1 span) (nth 2 span) (current-buffer))
|
||
(pm-debug-flick-region (nth 1 span) (nth 2 span)))))
|
||
|
||
(defun pm-debug-report-points (&optional where)
|
||
(when polymode-mode
|
||
(let* ((bufs (eieio-oref pm/polymode '-buffers))
|
||
(poses (mapcar (lambda (b)
|
||
(format "%s:%d" b (with-current-buffer b (point))))
|
||
bufs)))
|
||
(message "<%s> cb:%s %s" (or where "") (current-buffer) poses)))
|
||
nil)
|
||
|
||
|
||
;;; TOGGLING
|
||
|
||
(defvar pm-debug-display-info-message nil)
|
||
(defun pm-debug-toogle-info-message ()
|
||
"Toggle permanent info display."
|
||
(interactive)
|
||
(setq pm-debug-display-info-message (not pm-debug-display-info-message)))
|
||
|
||
(defvar poly-lock-allow-fontification)
|
||
(defun pm-debug-toggle-fontification ()
|
||
"Enable or disable fontification in polymode buffers."
|
||
(interactive)
|
||
(if poly-lock-allow-fontification
|
||
(progn
|
||
(message "fontificaiton disabled")
|
||
(dolist (b (buffer-list))
|
||
(with-current-buffer b
|
||
(when polymode-mode
|
||
(setq poly-lock-allow-fontification nil
|
||
font-lock-mode nil
|
||
fontification-functions nil)))))
|
||
(message "fontificaiton enabled")
|
||
(dolist (b (buffer-list))
|
||
(with-current-buffer b
|
||
(when polymode-mode
|
||
(setq poly-lock-allow-fontification t
|
||
font-lock-mode t
|
||
fontification-functions '(poly-lock-function)))))))
|
||
|
||
(defun pm-debug-toggle-after-change ()
|
||
"Allow or disallow polymode actions in `after-change-functions'."
|
||
(interactive)
|
||
(if pm-allow-after-change-hook
|
||
(progn
|
||
(message "after-change disabled")
|
||
(setq pm-allow-after-change-hook nil))
|
||
(message "after-change enabled")
|
||
(setq pm-allow-after-change-hook t)))
|
||
|
||
(defun pm-debug-toggle-post-command ()
|
||
"Allow or disallow polymode actions in `post-command-hook'."
|
||
(interactive)
|
||
(if pm-allow-post-command-hook
|
||
(progn
|
||
(message "post-command disabled")
|
||
(setq pm-allow-post-command-hook nil))
|
||
(message "post-command enabled")
|
||
(setq pm-allow-post-command-hook t)))
|
||
|
||
(defun pm-debug-toggle-all ()
|
||
"Toggle all polymode guards back and forth."
|
||
(interactive)
|
||
(if poly-lock-allow-fontification
|
||
(progn
|
||
(message "fontificaiton, after-chnage and command-hook disabled")
|
||
(setq poly-lock-allow-fontification nil
|
||
pm-allow-after-change-hook nil
|
||
pm-allow-post-command-hook nil))
|
||
(message "fontificaiton, after-change and command-hook enabled")
|
||
(setq poly-lock-allow-fontification t
|
||
pm-allow-after-change-hook t
|
||
pm-allow-post-command-hook t)))
|
||
|
||
|
||
;;; FONT-LOCK
|
||
|
||
(defun pm-debug-fontify-current-span ()
|
||
"Fontify current span."
|
||
(interactive)
|
||
(let ((span (pm-innermost-span))
|
||
(poly-lock-allow-fontification t))
|
||
(poly-lock-flush (nth 1 span) (nth 2 span))
|
||
(poly-lock-fontify-now (nth 1 span) (nth 2 span))))
|
||
|
||
(defun pm-debug-fontify-current-buffer ()
|
||
"Fontify current buffer."
|
||
(interactive)
|
||
(let ((poly-lock-allow-fontification t))
|
||
(font-lock-unfontify-buffer)
|
||
(poly-lock-flush (point-min) (point-max))
|
||
(poly-lock-fontify-now (point-min) (point-max))))
|
||
|
||
|
||
;;; TRACING
|
||
|
||
(defvar pm-traced-functions
|
||
'(
|
||
;; core initialization
|
||
(0 (pm-initialize
|
||
pm--common-setup
|
||
pm--mode-setup))
|
||
;; core hooks
|
||
(1 (polymode-post-command-select-buffer
|
||
polymode-after-kill-fixes
|
||
;; this one indicates the start of a sequence
|
||
poly-lock-after-change))
|
||
;; advises
|
||
(2 (pm-override-output-cons
|
||
pm-around-advice
|
||
polymode-with-current-base-buffer))
|
||
;; font-lock
|
||
(3 (font-lock-default-fontify-region
|
||
font-lock-fontify-keywords-region
|
||
font-lock-fontify-region
|
||
font-lock-fontify-syntactically-region
|
||
font-lock-unfontify-region
|
||
jit-lock--run-functions
|
||
jit-lock-fontify-now
|
||
poly-lock--after-change-internal
|
||
poly-lock--extend-region
|
||
poly-lock--extend-region-span
|
||
poly-lock-after-change
|
||
poly-lock-flush
|
||
poly-lock-fontify-now
|
||
poly-lock-function))
|
||
;; syntax
|
||
(4 (syntax-ppss
|
||
pm--call-syntax-propertize-original
|
||
polymode-syntax-propertize
|
||
polymode-restrict-syntax-propertize-extension
|
||
pm-flush-syntax-ppss-cache
|
||
pm--reset-ppss-cache))
|
||
;; core functions
|
||
(5 (pm-select-buffer
|
||
pm-map-over-spans
|
||
pm--get-intersected-span
|
||
pm--cached-span))
|
||
;; (13 . "^syntax-")
|
||
(14 . "^polymode-")
|
||
(15 . "^pm-")))
|
||
|
||
(defvar pm--do-trace nil)
|
||
;;;###autoload
|
||
(defun pm-toggle-tracing (level)
|
||
"Toggle polymode tracing.
|
||
With numeric prefix toggle tracing for that LEVEL. Currently
|
||
universal argument toggles maximum level of tracing (4). Default
|
||
level is 3."
|
||
(interactive "P")
|
||
(setq level (prefix-numeric-value (or level 3)))
|
||
(with-current-buffer (get-buffer-create "*Messages*")
|
||
(read-only-mode -1))
|
||
(setq pm--do-trace (not pm--do-trace))
|
||
(if pm--do-trace
|
||
(progn (dolist (kv pm-traced-functions)
|
||
(when (<= (car kv) level)
|
||
(if (stringp (cdr kv))
|
||
(pm-trace-functions-by-regexp (cdr kv))
|
||
(dolist (fn (cadr kv))
|
||
(pm-trace fn)))))
|
||
(message "Polymode tracing activated"))
|
||
(untrace-all)
|
||
(message "Polymode tracing deactivated")))
|
||
|
||
|
||
;;;###autoload
|
||
(defun pm-trace (fn)
|
||
"Trace function FN.
|
||
Use `untrace-function' to untrace or `untrace-all' to untrace all
|
||
currently traced functions."
|
||
(interactive (trace--read-args "Trace: "))
|
||
(let ((buff (get-buffer "*Messages*")))
|
||
(unless (advice-member-p trace-advice-name fn)
|
||
(advice-add
|
||
fn :around
|
||
(let ((advice (trace-make-advice
|
||
fn buff 'background
|
||
#'pm-trace--tracing-context)))
|
||
(lambda (body &rest args)
|
||
(when (eq fn 'polymode-flush-syntax-ppss-cache)
|
||
(with-current-buffer buff
|
||
(save-excursion
|
||
(goto-char (point-max))
|
||
(insert "\n"))))
|
||
(if polymode-mode
|
||
(apply advice body args)
|
||
(apply body args))))
|
||
`((name . ,trace-advice-name)
|
||
(depth . -100))))))
|
||
|
||
(defun pm-trace-functions-by-regexp (regexp)
|
||
"Trace all functions whose name matched REGEXP."
|
||
(interactive "sRegex: ")
|
||
(cl-loop for sym being the symbols
|
||
when (and (fboundp sym)
|
||
(not (memq sym '(pm-toggle-tracing
|
||
pm-trace--tracing-context
|
||
pm-format-span
|
||
pm-fun-matcher
|
||
pm--find-tail-from-head)))
|
||
(not (string-match "^pm-\\(trace\\|debug\\)" (symbol-name sym)))
|
||
(string-match regexp (symbol-name sym)))
|
||
do (pm-trace sym)))
|
||
|
||
(defun pm-trace--tracing-context ()
|
||
(let ((span (or *span*
|
||
(get-text-property (point) :pm-span))))
|
||
(format " [%s pos:%d(%d-%d) %s%s (%f)]"
|
||
(current-buffer) (point) (point-min) (point-max)
|
||
(or (when span
|
||
(when (not (and (= (point-min) (nth 1 span))
|
||
(= (point-max) (nth 2 span))))
|
||
"UNPR "))
|
||
"")
|
||
(when span
|
||
(pm-format-span span))
|
||
(float-time))))
|
||
|
||
;; fix object printing
|
||
(defun pm-trace--fix-1-arg-for-tracing (arg)
|
||
(cond
|
||
((eieio-object-p arg) (eieio-object-name arg))
|
||
((and (listp arg) (eieio-object-p (nth 3 arg)))
|
||
(list (nth 0 arg) (nth 1 arg) (nth 2 arg) (eieio-object-name (nth 3 arg))))
|
||
(arg)))
|
||
|
||
(defun pm-trace--fix-args-for-tracing (orig-fn fn level args context)
|
||
(let ((args (or (and (listp args)
|
||
(listp (cdr args))
|
||
(ignore-errors (mapcar #'pm-trace--fix-1-arg-for-tracing args)))
|
||
args)))
|
||
(funcall orig-fn fn level args context)))
|
||
|
||
(advice-add #'trace-entry-message :around #'pm-trace--fix-args-for-tracing)
|
||
(advice-add #'trace-exit-message :around #'pm-trace--fix-args-for-tracing)
|
||
;; (advice-remove #'trace-entry-message #'pm-trace--fix-args-for-tracing)
|
||
;; (advice-remove #'trace-exit-message #'pm-trace--fix-args-for-tracing)
|
||
|
||
|
||
;;; RELEVANT VARIABLES
|
||
|
||
(defvar pm-debug-relevant-variables
|
||
`(:change
|
||
(before-change-functions after-change-functions)
|
||
:command (pre-command-hook
|
||
post-command-hook)
|
||
:font-lock (fontification-functions
|
||
font-lock-function
|
||
font-lock-flush-function
|
||
font-lock-ensure-function
|
||
font-lock-fontify-region-function
|
||
font-lock-fontify-buffer-function
|
||
font-lock-unfontify-region-function
|
||
font-lock-unfontify-buffer-function
|
||
jit-lock-after-change-extend-region-functions
|
||
jit-lock-functions
|
||
poly-lock-defer-after-change)
|
||
;; If any of these are reset by host mode it can create issues with
|
||
;; font-lock and syntax (e.g. scala-mode in #195)
|
||
:search (parse-sexp-lookup-properties
|
||
parse-sexp-ignore-comments
|
||
;; (syntax-table)
|
||
;; font-lock-syntax-table
|
||
case-fold-search)
|
||
:indent (indent-line-function
|
||
indent-region-function
|
||
pm--indent-line-function-original)
|
||
:revert (revert-buffer-function
|
||
before-revert-hook
|
||
after-revert-hook)
|
||
:save (after-save-hook
|
||
before-save-hook
|
||
write-contents-functions
|
||
local-write-file-hooks
|
||
write-file-functions)
|
||
:syntax (syntax-propertize-function
|
||
syntax-propertize-extend-region-functions
|
||
pm--syntax-propertize-function-original)))
|
||
|
||
;;;###autoload
|
||
(defun pm-debug-relevant-variables (&optional out-type)
|
||
"Get the relevant polymode variables.
|
||
If OUT-TYPE is 'buffer, print the variables in the dedicated
|
||
buffer, if 'message issue a message, if nil just return a list of values."
|
||
(interactive (list 'buffer))
|
||
(let* ((cbuff (current-buffer))
|
||
(vars (cl-loop for v on pm-debug-relevant-variables by #'cddr
|
||
collect (cons (car v)
|
||
(mapcar (lambda (v)
|
||
(cons v (buffer-local-value v cbuff)))
|
||
(cadr v))))))
|
||
(require 'pp)
|
||
(cond
|
||
((eq out-type 'buffer)
|
||
(with-current-buffer (get-buffer-create "*polymode-vars*")
|
||
(erase-buffer)
|
||
(goto-char (point-max))
|
||
(insert (format "\n================== %s ===================\n" cbuff))
|
||
(insert (pp-to-string vars))
|
||
(toggle-truncate-lines -1)
|
||
(goto-char (point-max))
|
||
(view-mode)
|
||
(display-buffer (current-buffer))))
|
||
((eq out-type 'message)
|
||
(message "%s" (pp-to-string vars)))
|
||
(t vars))))
|
||
|
||
(defun pm-debug-diff-local-vars (&optional buffer1 buffer2)
|
||
"Print differences between local variables in BUFFER1 and BUFFER2."
|
||
(interactive)
|
||
(let* ((buffer1 (or buffer1 (read-buffer "Buffer1: " (buffer-name (current-buffer)))))
|
||
(buffer2 (or buffer2 (read-buffer "Buffer2: " (buffer-name (nth 2 (buffer-list))))))
|
||
(vars1 (buffer-local-variables (get-buffer buffer1)))
|
||
(vars2 (buffer-local-variables (get-buffer buffer2)))
|
||
(all-keys (delete-dups (append (mapcar #'car vars1)
|
||
(mapcar #'car vars2))))
|
||
(out-buf (get-buffer-create "*pm-debug-output")))
|
||
(with-current-buffer out-buf
|
||
(erase-buffer)
|
||
(pp (delq nil
|
||
(mapcar (lambda (k)
|
||
(let ((val1 (cdr (assoc k vars1)))
|
||
(val2 (cdr (assoc k vars2))))
|
||
(unless (equal val1 val2)
|
||
(list k val1 val2))))
|
||
all-keys))
|
||
out-buf))
|
||
(pop-to-buffer out-buf)))
|
||
|
||
|
||
;;; HIGHLIGHT
|
||
|
||
(defun pm-debug-highlight-current-span ()
|
||
(when polymode-mode
|
||
(with-silent-modifications
|
||
(unless (memq this-command '(pm-debug-info-on-current-span
|
||
pm-debug-highlight-last-font-lock-error-region))
|
||
(delete-overlay pm--highlight-overlay))
|
||
(condition-case-unless-debug err
|
||
(let ((span (pm-innermost-span)))
|
||
(when pm-debug-display-info-message
|
||
(message (pm--debug-info span)))
|
||
(move-overlay pm--underline-overlay (nth 1 span) (nth 2 span) (current-buffer)))
|
||
(error (message "%s" (error-message-string err)))))))
|
||
|
||
(defun pm-debug-flick-region (start end &optional delay)
|
||
(move-overlay pm--highlight-overlay start end (current-buffer))
|
||
(run-with-timer (or delay 0.4) nil (lambda () (delete-overlay pm--highlight-overlay))))
|
||
|
||
(defun pm-debug-map-over-spans-and-highlight ()
|
||
"Map over all spans in the buffer and highlight briefly."
|
||
(interactive)
|
||
(pm-map-over-spans (lambda (span)
|
||
(let ((start (nth 1 span))
|
||
(end (nth 2 span)))
|
||
(pm-debug-flick-region start end)
|
||
(sit-for 1)))
|
||
(point-min) (point-max) nil nil t))
|
||
|
||
(defun pm-debug-map-over-modes-and-highlight (&optional beg end)
|
||
"Map over all spans between BEG and END and highlight modes."
|
||
(interactive)
|
||
(let ((cbuf (current-buffer)))
|
||
(pm-fast-map-over-modes
|
||
(lambda (beg end)
|
||
(goto-char beg)
|
||
;; (dbg beg end (pm-format-span))
|
||
(with-current-buffer cbuf
|
||
(recenter-top-bottom)
|
||
(pm-debug-flick-region (max beg (point-min))
|
||
(min end (point-max))))
|
||
(sit-for 1))
|
||
(or beg (point-min))
|
||
(or end (point-max)))))
|
||
|
||
(defun pm-debug-run-over-check (no-cache)
|
||
"Map over all spans and report the time taken.
|
||
Switch to buffer is performed on every position in the buffer.
|
||
On prefix NO-CACHE don't use cached spans."
|
||
(interactive)
|
||
(goto-char (point-min))
|
||
(let ((start (current-time))
|
||
(count 1)
|
||
(pm-initialization-in-progress no-cache))
|
||
(pm-switch-to-buffer)
|
||
(while (< (point) (point-max))
|
||
(setq count (1+ count))
|
||
(forward-char)
|
||
(pm-switch-to-buffer))
|
||
(let ((elapsed (float-time (time-subtract (current-time) start))))
|
||
(message "Elapsed: %s per-char: %s" elapsed (/ elapsed count)))))
|
||
|
||
(defun pm-dbg (msg &rest args)
|
||
(let ((cbuf (current-buffer))
|
||
(cpos (point)))
|
||
(with-current-buffer (get-buffer-create "*pm-dbg*")
|
||
(save-excursion
|
||
(goto-char (point-max))
|
||
(insert "\n")
|
||
(insert (apply 'format (concat "%f [%s at %d]: " msg)
|
||
(float-time) cbuf cpos args))))))
|
||
|
||
(provide 'polymode-debug)
|
||
;;; polymode-debug.el ends here
|