From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Alan Mackenzie Newsgroups: gmane.emacs.devel Subject: [PATCH] Re: cc-mode fontification feels random Date: Mon, 30 Aug 2021 18:50:34 +0000 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="19792"; mail-complaints-to="usenet@ciao.gmane.io" Cc: emacs-devel@gnu.org To: Daniel Colascione Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Mon Aug 30 20:52:05 2021 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mKmO4-0004y1-C7 for ged-emacs-devel@m.gmane-mx.org; Mon, 30 Aug 2021 20:52:04 +0200 Original-Received: from localhost ([::1]:51286 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mKmO2-0000sZ-QA for ged-emacs-devel@m.gmane-mx.org; Mon, 30 Aug 2021 14:52:02 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:45498) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mKmMj-0008FB-LI for emacs-devel@gnu.org; Mon, 30 Aug 2021 14:50:41 -0400 Original-Received: from colin.muc.de ([193.149.48.1]:59561 helo=mail.muc.de) by eggs.gnu.org with smtp (Exim 4.90_1) (envelope-from ) id 1mKmMg-0004nH-9v for emacs-devel@gnu.org; Mon, 30 Aug 2021 14:50:41 -0400 Original-Received: (qmail 57141 invoked by uid 3782); 30 Aug 2021 18:50:34 -0000 Original-Received: from acm.muc.de (p4fe15b65.dip0.t-ipconnect.de [79.225.91.101]) (using STARTTLS) by colin.muc.de (tmda-ofmipd) with ESMTP; Mon, 30 Aug 2021 20:50:34 +0200 Original-Received: (qmail 7771 invoked by uid 1000); 30 Aug 2021 18:50:34 -0000 Content-Disposition: inline In-Reply-To: X-Submission-Agent: TMDA/1.3.x (Ph3nix) X-Primary-Address: acm@muc.de Received-SPF: pass client-ip=193.149.48.1; envelope-from=acm@muc.de; helo=mail.muc.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:273532 Archived-At: Hello, Daniel. On Thu, Jun 03, 2021 at 20:16:53 -0700, Daniel Colascione wrote: > As long as I can remember, cc-mode fontification has felt totally > random, with actual faces depending on happenstance of previously-parsed > types, luck of the draw in jit-lock chunking, and so on. Is there any > *general* way that we can make fontification more robust and consistent? > For years and years now, I've been thinking we just need more > deterministic parser-and-based mode support, and I still think that, but > on a realistic level, that doesn't seem to be coming any time soon. > In the meantime, is there any general approach we might be able to use > to get stuff like the attached to stop happening? Here, "stuff like the attached" was having some types correctly fontified, others not. This was due to the order, somewhat random, in which a type is recognised as such and entered into a CC Mode table, and its use being scanned in a jit-lock chunk. The following patch is an attempt to improve this situation. It is best used with jit-stealth-lock enabled. I have tried it out with the following settings: jit-lock-stealth-load: 200 ; i.e. inactive. jit-lock-stealth-nice: 0.1 ; 100 ms between fontifying stealth chunks. jit-lock-stealth-time: 1 ; 1 second idle time before stealth kicks in. Whenever a new found type is entered into the CC Mode table, it marks all occurrences of the type in the buffer for fontification (by setting the 'fontified text property to nil on it), and causes an immediate redisplay when there are occurrences of the new type in a window. I think stealth lock could be enhanced by having it fontify several 500-byte chunks together, say until 0.05s time has been taken up. This could speed up stealth fontification while still leaving the keyboard responsive to the user. Anyhow, could you try the patch please, in particular on the source code which you posted a picture of back in June, and see how well it, together with stealth fontification, helps with the random fontification. (The patch is still a fairly rough sketch, not a finished patch.) Thanks! diff -r a811a06c82c2 cc-engine.el --- a/cc-engine.el Sat Aug 21 10:14:48 2021 +0000 +++ b/cc-engine.el Mon Aug 30 18:23:44 2021 +0000 @@ -173,6 +173,9 @@ (cc-bytecomp-defvar c-doc-line-join-end-ch) (defvar c-syntactic-context) (defvar c-syntactic-element) +(defvar c-new-id-start) +(defvar c-new-id-end) +(defvar c-new-id-is-type) (cc-bytecomp-defvar c-min-syn-tab-mkr) (cc-bytecomp-defvar c-max-syn-tab-mkr) (cc-bytecomp-defun c-clear-syn-tab) @@ -6839,21 +6842,47 @@ (setq c-found-types (make-hash-table :test #'equal :weakness nil))) +;;;; OLD STOUGH, 2021-08-23 +;; (defun c-add-type (from to) +;; ;; Add the given region as a type in `c-found-types'. If the region +;; ;; doesn't match an existing type but there is a type which is equal +;; ;; to the given one except that the last character is missing, then +;; ;; the shorter type is removed. That's done to avoid adding all +;; ;; prefixes of a type as it's being entered and font locked. This +;; ;; doesn't cover cases like when characters are removed from a type +;; ;; or added in the middle. We'd need the position of point when the +;; ;; font locking is invoked to solve this well. +;; ;; +;; ;; This function might do hidden buffer changes. +;; (let ((type (c-syntactic-content from to c-recognize-<>-arglists))) +;; (unless (gethash type c-found-types) +;; (remhash (substring type 0 -1) c-found-types) +;; (puthash type t c-found-types)))) +;;;; NEW STOUGH, 2021-08-29 +(defun c-add-type-1 (from to) + ;; FIXME!!! + (let ((type (c-syntactic-content from to c-recognize-<>-arglists))) + (unless (gethash type c-found-types) + (puthash type t c-found-types) + (when (and (eq (string-match c-symbol-key type) 0) + (eq (match-end 0) (length type))) + (c-fontify-new-found-type type))))) + (defun c-add-type (from to) - ;; Add the given region as a type in `c-found-types'. If the region - ;; doesn't match an existing type but there is a type which is equal - ;; to the given one except that the last character is missing, then - ;; the shorter type is removed. That's done to avoid adding all - ;; prefixes of a type as it's being entered and font locked. This - ;; doesn't cover cases like when characters are removed from a type - ;; or added in the middle. We'd need the position of point when the - ;; font locking is invoked to solve this well. + ;; Add the given region as a type in `c-found-types'. If the region is or + ;; overlaps an identifier which might be being typed in, don't record it. + ;; This is tested by checking `c-new-id-start' and `c-new-id-end'. That's + ;; done to avoid adding all prefixes of a type as it's being entered and + ;; font locked. This is a bit rough and ready, but now covers adding + ;; characters into the middle of an identifer. ;; ;; This function might do hidden buffer changes. - (let ((type (c-syntactic-content from to c-recognize-<>-arglists))) - (unless (gethash type c-found-types) - (remhash (substring type 0 -1) c-found-types) - (puthash type t c-found-types)))) + (if (and c-new-id-start c-new-id-end + (<= from c-new-id-end) (>= to c-new-id-start)) + (setq c-new-id-is-type t) + (c-add-type-1 from to))) +;;;; END OF NEW STOUGH +;;;; END OF NEW STOUGH (defun c-unfind-type (name) ;; Remove the "NAME" from c-found-types, if present. diff -r a811a06c82c2 cc-fonts.el --- a/cc-fonts.el Sat Aug 21 10:14:48 2021 +0000 +++ b/cc-fonts.el Mon Aug 30 18:23:44 2021 +0000 @@ -2253,6 +2253,48 @@ ;; defvar will install its default value later on. (makunbound def-var))) +;;;; NEW STOUGH, 2021-08-29 +;; `c-re-redisplay-timer' is a timer which, when triggered, causes a +;; redisplay. +(defvar c-re-redisplay-timer nil) + +(defun c-force-redisplay (start end) + ;; Force redisplay immediately. This assumes `font-lock-support-mode' is + ;; 'jit-lock-mode. Set the variable `c-re-redisplay-timer' to nil. + (jit-lock-force-redisplay (copy-marker start) (copy-marker end)) + (setq c-re-redisplay-timer nil)) + +(defun c-fontify-new-found-type (type) + ;; Cause the fontification of TYPE, a string, wherever it occurs in the + ;; buffer. If TYPE is currently displayed in a window, cause redisplay to + ;; happen "instantaneously". These actions are done only when jit-lock-mode + ;; is active. + (when (and (boundp 'font-lock-support-mode) + (eq font-lock-support-mode 'jit-lock-mode)) + (c-save-buffer-state + ((window-boundaries + (mapcar (lambda (win) + (cons (window-start win) + (window-end win))) + (get-buffer-window-list (current-buffer) 'no-mini t))) + (target-re (concat "\\_<" type "\\_>"))) + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (while (re-search-forward target-re nil t) + (put-text-property (match-beginning 0) (match-end 0) + 'fontified nil) + (dolist (win-boundary window-boundaries) + (when (and (< (match-beginning 0) (cdr win-boundary)) + (> (match-end 0) (car win-boundary)) + (c-get-char-property (match-beginning 0) 'fontified) + (not c-re-redisplay-timer)) + (setq c-re-redisplay-timer + (run-with-timer 0 nil #'c-force-redisplay + (match-beginning 0) (match-end 0))))))))))) + +;;;; END OF NEW STOUGH, 2021-08-29 ;;; C. diff -r a811a06c82c2 cc-mode.el --- a/cc-mode.el Sat Aug 21 10:14:48 2021 +0000 +++ b/cc-mode.el Mon Aug 30 18:23:44 2021 +0000 @@ -173,6 +173,16 @@ (when c-buffer-is-cc-mode (save-restriction (widen) +;;;; NEW STOUGH, 2021-08-23 + (let ((lst (buffer-list))) + (catch 'found + (dolist (b lst) + (if (and (not (eq b (current-buffer))) + (with-current-buffer b + c-buffer-is-cc-mode)) + (throw 'found nil))) + (remove-hook 'post-command-hook 'c-post-command))) +;;;; END OF NEW STOUGH (c-save-buffer-state () (c-clear-char-properties (point-min) (point-max) 'category) (c-clear-char-properties (point-min) (point-max) 'syntax-table) @@ -728,6 +738,9 @@ (or (memq 'add-hook-local c-emacs-features) (make-local-hook 'after-change-functions)) (add-hook 'after-change-functions 'c-after-change nil t) +;;;; NEW STOUGH, 2021-08-23 + (add-hook 'post-command-hook 'c-post-command) +;;;; END OF NEW STOUGH (when (boundp 'font-lock-extend-after-change-region-function) (set (make-local-variable 'font-lock-extend-after-change-region-function) 'c-extend-after-change-region))) ; Currently (2009-05) used by all @@ -1936,6 +1949,45 @@ ;; confused by already processed single quotes. (narrow-to-region (point) (point-max)))))) +;;;; NEW STOUGH, 2021-08-22 +;; The next two variables record the bounds of an identifier currently being +;; typed in. These are used to prevent such a partial identifier being +;; recorded as a found type by c-add-type. +(defvar c-new-id-start nil) +(make-variable-buffer-local 'c-new-id-start) +(defvar c-new-id-end nil) +(make-variable-buffer-local 'c-new-id-end) +;;;; NEW STOUGH, 2021-08-29 +;; The next variable, when non-nil, records that the previous two variables +;; define a type. +(defvar c-new-id-is-type nil) +(make-variable-buffer-local 'c-new-id-is-type) +;;;; END OF NEW STOUGH + +(defun c-update-new-id (end) + ;; Fill this in. FIXME!!! + (save-excursion + (goto-char end) + (let ((id-beg (c-on-identifier))) + (setq c-new-id-start id-beg + c-new-id-end (and id-beg + (progn (c-end-of-current-token) (point))))))) + + +(defun c-post-command () + ;; If point was inside of a new identifier and no longer is, record that + ;; fact. + (when (and c-buffer-is-cc-mode + c-new-id-start c-new-id-end + (or (> (point) c-new-id-end) + (< (point) c-new-id-start))) + (when c-new-id-is-type + (c-add-type-1 c-new-id-start c-new-id-end)) + (setq c-new-id-start nil + c-new-id-end nil + c-new-id-is-type nil))) +;;;; END OF NEW STOUGH + (defun c-before-change (beg end) ;; Function to be put in `before-change-functions'. Primarily, this calls ;; the language dependent `c-get-state-before-change-functions'. It is @@ -2133,6 +2185,9 @@ c->-as-paren-syntax) (c-clear-char-property-with-value beg end 'syntax-table nil))) +;;;; NEW STOUGH, 2021-08-22 + (c-update-new-id end) +;;;; END OF NEW STOUGH (c-trim-found-types beg end old-len) ; maybe we don't ; need all of these. (c-invalidate-sws-region-after beg end old-len) -- Alan Mackenzie (Nuremberg, Germany).