[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Signal `quit' in a `font-lock-fontify-region-function'
From: |
Paul Pogonyshev |
Subject: |
Re: Signal `quit' in a `font-lock-fontify-region-function' |
Date: |
Sun, 30 Jun 2019 01:49:46 +0200 |
On Sat, 29 Jun 2019 at 23:26, Stefan Monnier <address@hidden> wrote:
>
> > I'm not sure if this is flexible enough. I don't like the idea of C-g
> > already invoking some code (that e.g. disables font-locking).
>
> [...] It definitely wouldn't disable font-locking right away.
>
> The disabling would only be in response to a "large" number of C-g,
> which presumably should only be needed in extreme circumstances
> (basically when currently the user ends up killing Emacs instead).
So, basically, as I understand, C-g handler in your proposal would
look like (I know it is in C code, but...), simplified:
(defun handle-C-g (...)
(when registered-many-C-g-callback ; variable set by e.g.
font-locking code
(setq num-C-g-presses (1+ num-C-g-presses))
(when (> num-C-g-presses 3)
(funcall registered-many-C-g-callback))))
and font-locking code would be roughly
(let ((registered-many-C-g-callback (lambda () (setq font-lock-mode nil))))
; call fontification function, process its result etc.
)
That's what I meant: here `handle-C-g' already invokes some callback
that higher level (in this case font-locking) registers.
I propose that instead font-locking code simply says "I will process
multiple C-g presses somehow, please count them" by let-binding
`count-C-g-presses' to t. The idea is to not invoke the "abort"
callback immediately when the 3rd C-g is pressed, but instead let the
iteration finish gracefully and _then_ let the higher-level code
(font-locking) abort or not based on all the information it has by
now. Usually this information would be just result of
`(too-many-C-g-recently)', but could be anything in the future, so we
are more flexible.
> > So, I'd like to be able to _handle_ `quit' signal in the function
> > itself and stop extending the region and return immediately, so that I
> > don't throw away work on a considerable region of text that has been
> > done already.
>
> I don't understand why you say "don't throw away work on a considerable
> region of text that has been done already": if you're in the middle of
> extending the region, presumably no "work" has been done yet.
For example, my function decides to fontify 1000 lines of text and by
the time C-g is pressed (triggering the signal) it has already
fontified 500 of them (this is already more than what font-locking
code wanted, because I extended the requested region). I'd like to be
able to notify font-locking code about the work that has been done,
even if I planned to do even more. If I raise `quit' signal or let
C-g raise it by default, all this work is thrown away.
> Could `while-no-input` be usable in this case?
This macro uses `with-local-quit', which, as I understand will rethrow
signal `quit' after the body. As a result, font-locking code will
still see my function terminate non-locally, deem the whole invocation
failed and set property `fontified' to nil. So no, to achive what I
want I need to let my function return normally somehow.
>
> > I'm not sure if it is the best solution, but I'd propose C-g to be
> > counted not when `quit' signal is caught, but when it would be
> > emitted, even if `inhibit-quit' is t. And font-locking code would
> > look something like this: [...]
>
> I think if C-g resulted in (signal 'quit ...), then presumably we exited
> this code, so the only really interesting case should be the one where
> we just have `quit-flag` set to t.
Yes, but the point is in that I want to avoid C-g resulting in the
signal by binding `inhibit-quit' inside my fontification function.
But still have C-g handler note that C-g is pressed and let
fontification code find if it is being pressed too often.
> Maybe we should change the C-g code so it sets `quit-flag` to the
> number of C-g that are pending.
This generally sounds like a good idea: I'm always in favour of having
more information. However, in my case it is not enough.
I guess it is easier to explain by pseudocode of my fontification
function:
(defun my--fontify-region (region-start region-end _loudly)
;; Very fast, so always work on large regions to avoid setup overhead.
(setq region-end (+ region-start 50000))
;; Here comes some internal setup.
...
(let ((fontified-up-to region-start)
(inhibit-quit t))
;; While `quit' is inhibitted, the below loop will still be
aborted on C-g.
(while (and (< fontified-up-to region-end) (null quit-flag))
... ; do some work on the next small chunk of text; this is
very fast,
; but as the region is quite big, the loop is iterated many times
)
;; Always exit normally. Font-locking code will find out if
we suppressed
;; a C-g through other means, i.e. using (too-many-C-g-recently).
(setq quit-flag nil)
`(jit-lock-bounds ,region-start . ,fontified-up-to)))
Note that the function doesn't suppress any other signals/errors.
Paul