# # lentic-dev.el --- Tools for developers -*- lexical-binding: t -*-

* Header

This file is not part of Emacs

Author: Phillip Lord <phillip.lord@russet.org.uk>
Maintainer: Phillip Lord <phillip.lord@russet.org.uk>
The contents of this file are subject to the GPL License, Version 3.0.

Copyright (C) 2014-2024  Free Software Foundation, Inc.

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 version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

* Commentary

Developing support for new forms of lentic buffers is not trivial. This
file provides some support functions for doing so.

* Code

#+begin_src emacs-lisp
(require 'lentic)

#+end_src

** Manual Updates

Usually, lentic uses Emacs hooks to percolate changes in one buffer to
another. Unfortunately, all the hooks that do this not only silently discard
errors, but they delete the offending function from the hook. So, post-mortem
debugging is hard. Step-through is also hard since it happens in the command
loop.

Lentic has a function for disabling its functionality (due to breakage
rather than just normal switching it off), called `linked-buffer-emergency'
(and the inverse `linked-buffer-unemergency'). In this emergency state, we
can still run the hooks manually, which is by far the best way to debug them.

For the `lentic-test-after-change-function' to work `lentic-emergency-debug'
must be set. It is also critical that only a single change has happened before
this function is called -- otherwise the result of the previous change are
deleted, and the lentic buffers will update in an inconsistent and haphazard
way.


#+begin_src emacs-lisp
;;;###autoload
(defun lentic-dev-after-change-function ()
  "Run the change functions out of the command loop.
Using this function is the easiest way to test an new
`lentic-clone' method, as doing so in the command loop is
painful for debugging. Set variable `lentic-emergency' to
true to disable command loop functionality."
  (interactive)
  (message "Running after change with args: %s"
           lentic-emergency-last-change)
  (apply #'lentic-after-change-function-1
         lentic-emergency-last-change))

;;;###autoload
(defun lentic-dev-post-command-hook ()
  "Run the post-command functions out of the command loop.
Using this function is the easiest way to test an new
`lentic-convert' method, as doing so in the command loop is
painful for debugging. Set variable `lentic-emergency' to
true to disable command loop functionality."
  (interactive)
  (lentic-post-command-hook-1 (current-buffer) '()))

;;;###autoload
(defun lentic-dev-after-save-hook ()
  (interactive)
  (let ((lentic-emergency nil))
    (lentic-mode-after-save-hook)))

;;;###autoload
(defun lentic-dev-mode-buffer-list-update-hook ()
  (interactive)
  (let ((lentic-emergency nil))
    (lentic-mode-buffer-list-update-hook)))

;;;###autoload
(defun lentic-dev-kill-buffer-hook ()
  (interactive)
  (let ((lentic-emergency nil))
    (lentic-kill-buffer-hook)))

;;;###autoload
(defun lentic-dev-kill-emacs-hook ()
  (interactive)
  (let ((lentic-emergency nil))
    (lentic-kill-emacs-hook)))

;;;###autoload
(defun lentic-dev-reinit ()
  "Recall the init function regardless of current status.
This can help if you have change the config object and need
to make sure there is a new one."
  (interactive)
  (setq lentic-config nil)
  (lentic-ensure-init))

#+end_src

** Font-Lock changes

These commands enable or disable fontification of changes that lentic has
percolated. This is very useful for incremental changes; it's the only
practical way of seeing what has been copied.

The exact behaviour of this depends on the mode of the buffer displaying the
lentic buffer. Sometimes, the natural buffer fontification functions just
change the font back to whatever the syntax suggests. In this case, try
switching off `font-lock-mode'.

#+begin_src emacs-lisp

(defvar lentic-dev-insert-face 'font-lock-keyword-face
  "Start face to use for inserted text.")

;;;###autoload
(defun lentic-dev-random-face ()
  "Change the insertion face to a random one."
  (interactive)
  (setq lentic-dev-insert-face
        (nth (random (length (face-list)))
             (face-list)))
  (message "Insert face is now %s"
           (propertize
            "this"
            'face
            lentic-dev-insert-face)))

(defun lentic-dev--face-transform (string)
  (propertize
   string
   'font-lock-face
   lentic-dev-insert-face
   'face
   lentic-dev-insert-face))

;;;###autoload
(define-minor-mode lentic-dev-enable-insertion-marking
  "Enable font locking properties for inserted text."
  :global t
  :group 'lentic-dev
  (if lentic-dev-enable-insertion-marking
      (advice-add 'lentic-insertion-string-transform :override
                    #'lentic-dev--face-transform)
    (advice-remove 'lentic-insertion-string-transform
                     #'lentic-dev--face-transform)))


(defun lentic-dev--pulse-transform (buffer start stop &rest _)
  (with-current-buffer
      buffer
    (pulse-momentary-highlight-region
     (or start (point-min))
     (or stop (point-max)))))

;;;###autoload
(define-minor-mode lentic-dev-enable-insertion-pulse
  "Enable momentary pulsing for inserted text."
  :global t
  :group 'lentic-dev
  (if lentic-dev-enable-insertion-pulse
      (advice-add 'lentic-after-change-transform :after
                  #'lentic-dev--pulse-transform)
    (advice-remove 'lentic-after-change-transform
                   #'lentic-dev--pulse-transform)))


(defun lentic-dev-edebug-trace-mode ()
  (setq edebug-initial-mode 'continue)
  (setq edebug-trace t))


(defun lentic-dev-highlight-markers ()
  (interactive)
  (m-buffer-overlay-font-lock-face-match
   (lentic-blk-marker-boundaries
    (car lentic-config)
    (current-buffer))
   'highlight))

(provide 'lentic-dev)
;;; lentic-dev.el ends here

#+end_src
