unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Re: Signal `quit' in a `font-lock-fontify-region-function'
@ 2019-06-29 17:50 Paul Pogonyshev
  2019-06-29 21:26 ` Stefan Monnier
  0 siblings, 1 reply; 11+ messages in thread
From: Paul Pogonyshev @ 2019-06-29 17:50 UTC (permalink / raw)
  To: Stefan Monnier, Emacs developers

Found this answer to my question in the list archives. I'm not
subscribed, please CC to me.

> Right, here's how I could imagine a "desirable" behavior:
>
> - everytime some operation may block Emacs, it should "register"
>   somewhere (probably some let-binding of a global var is all it takes).
> - After hitting C-g, a timer is started.
> - If this timer is reached before the C-g has had to chance to be
>   processed, emit a message in the echo area explaining what Emacs is
>   currently doing (based on the "registered" information above).
> - when we reach the Nth C-g in a row within the same "registered"
>   operation, we abort the operation (e.g. by calling an ad-hoc
>   function provided while "registering").

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).  Please
read on to see a usecase that I feel would be impossible to support
with your proposal.

My fontification function often extends the fontification region
considerably and then returns `(jit-lock-bounds START . END)', as
required in the documentation.  In my case this makes fontification
much faster, because the function itself is very fast and most of the
time is spent in various setups (both in fontlocking code and the
function itself), not in traversing through the region to be
fontified.

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.  However, fontlocking code shouldn't discard the results
(as otherwise this is pointless).  So, I cannot resignal `quit', I
have to return normally.  But I also don't want to "eat" this signal
and hide C-g press from Emacs' monitoring code.  So basically, I want
font-locking still continue to work for a while, even if C-g has been
pressed too many times, but if so, abort soon.

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:

    (let ((count-C-g-presses t))  ; Instead of "registering" as you
proposed, I think we just
                                  ; need to tell C-g handler to count
presses while inside
                                  ; certain blocks of code.
      (condition-case error
          (let ((fontified-region (funcall actual-handler ...)))
            ;; Process the fontified region
            ...)
        (error ;; This logs any errors inside the handler, including uncaught
               ;; `quit' signals.  Just as now.
               ...))
      (when (too-many-C-g-recently)  ; This would count both C-g that
resulted in (signal 'quit ...)
                                     ; and those that resulted in
`(setq quit-flag t)'.
        ;; The below forms are roughly what would be "registered" in your
        ;; proposal.  I feel leaving it up to the caller gives more
        ;; flexibility in actually permorming "abort everything" tasks.
        (setq font-lock-mode nil)
        (message "Too many C-g, font-locking disabled")))

I think I could try to implement this myself, but on the other hand
I'm certainly not familiar with Emacs internals.  So I would gladly
give up this task to someone else who would like to do it.

Paul



^ permalink raw reply	[flat|nested] 11+ messages in thread
* Re: Signal `quit' in a `font-lock-fontify-region-function'
@ 2019-05-28 16:24 Paul Pogonyshev
  2019-05-28 17:50 ` Stefan Monnier
  0 siblings, 1 reply; 11+ messages in thread
From: Paul Pogonyshev @ 2019-05-28 16:24 UTC (permalink / raw)
  To: Stefan Monnier, Emacs developers

Found this answer to my question in the list archives. I'm not
subscribed, please CC to me.

> > Error during redisplay: (jit-lock-function ##) signaled (quit)
>
> This is indeed the behavior I expect (tho I don't really like it, but
I never dared to change jit-lock to set inhibit-quit).
>
> > sometimes it doesn't.

Is there a difference in behavior in this respect when you try it in the
GUI vs in a tty?  How 'bout in another OS?

After recompiling with your patch I cannot reproduce it. Maybe it was
fixed by some other change, but more likely that I made a mistake and
the problem was never there. I could have been confused by my own
`message' replacement since it didn't insert at the buffer end, but
rather at the point.

Anyway, why I needed this. It is not impossible that during
development you write a fontification function that is broken and e.g.
falls into infinite loop. You can sort of abort it with C-g, but then
fontification code marks the whole region as unfontified (since the
function never finished), calls the function again, it gets stuck...
And the only way you can end this is by killing Emacs process. Or at
least I don't know any better way.

It is also possible to accidentally stumble into a finite, but
extremely long fontification. For example, if you open a
megabyte-large minified JavaScript file. I believe also one of the
many Python modes was susceptible at some point.

I was trying to write some workaround for my own mode, because it
targets log files, which can be hundreds of megabytes in size.
Additionally, the mode puts filtering into fontification process,
meaning that in fontification callback it can hide everything (if the
filter is too strict). And then the callback gets called again and
again, chewing through all the megabytes with no apparent way to stop
it until it finally finishes minutes later.

But would it make sense to adjust fontification code to disable
fontification in the current buffer if fontification function is
killed with C-g several times? I.e. instead of some custom workaround
for my mode only, add something generic to Emacs core. This would give
the user a chance to kill offending buffer rather than the whole
Emacs.

Paul



^ permalink raw reply	[flat|nested] 11+ messages in thread
* Signal `quit' in a `font-lock-fontify-region-function'
@ 2019-05-16 22:20 Paul Pogonyshev
  2019-05-16 23:20 ` Stefan Monnier
  0 siblings, 1 reply; 11+ messages in thread
From: Paul Pogonyshev @ 2019-05-16 22:20 UTC (permalink / raw)
  To: Emacs developers

[-- Attachment #1: Type: text/plain, Size: 1803 bytes --]

Hi,

I'm having the following, unfortunately unreproducible problem: inside a
custom font-locking function condition `quit' _sometimes_ cannot be
triggered with C-g. I'm sure it has nothing to do with `inhibit-quit'. For
the same function in one Emacs instance it is triggerable, in another ---
not. If in a certain instance it "breaks" (i.e. C-g no longer triggers
`quit'), it seems to stay broken forever.

This is notoriously difficult to investigate. I came up with the following
pseudo-mode (usage: M-x pretend-fontification-mode RET in a large buffer):

(define-derived-mode pretend-fontification-mode nil "PRETEND-FONTIFICATION"
  "..."
  (setq font-lock-defaults '(nil))
  (set (make-local-variable 'font-lock-fontify-region-function)
       (lambda (from to _verbose)
         ;; (message ...) doesn't seem to do anything
         (with-current-buffer "*Messages*" (with-silent-modifications
(insert (format "\nPRETEND-FONTIFYING %s-%s\n" from to))))
         (let (x)
           (dotimes (k 10000000)  ; long delay in pure Lisp, i.e. not
`sleep-for'
             (setq x k))))))

but as I said it is not reproducible: sometimes mashing C-g results in the
following in *Messages* buffer:

Error during redisplay: (jit-lock-function ##) signaled (quit)

sometimes it doesn't. I also tried `(condition-case ... (quit ...))' inside
font-locking function, but result is the same: sometimes the handler is
triggered, sometimes it is not and I cannot work out any pattern. I also
tried printing out values that could be relevant (inhibit-quit, quit-flag,
(input-pending-p), unread-command-events), but they appear to be the same
regardless of whether `quit' is still triggerable or not.

Does anyone has any idea what's going on?

Paul

P.S.: I'm not subscribed to the list, please CC answers to me.

[-- Attachment #2: Type: text/html, Size: 2330 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2019-06-30 10:51 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-06-29 17:50 Signal `quit' in a `font-lock-fontify-region-function' Paul Pogonyshev
2019-06-29 21:26 ` Stefan Monnier
2019-06-29 23:49   ` Paul Pogonyshev
2019-06-30  0:18     ` Stefan Monnier
2019-06-30 10:51       ` Paul Pogonyshev
  -- strict thread matches above, loose matches on Subject: below --
2019-05-28 16:24 Paul Pogonyshev
2019-05-28 17:50 ` Stefan Monnier
2019-05-28 18:14   ` Paul Pogonyshev
2019-05-28 18:24     ` Stefan Monnier
2019-05-16 22:20 Paul Pogonyshev
2019-05-16 23:20 ` Stefan Monnier

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).