GNU bug report logs - #20266
Emacs doesn't respond when editing the attached c header file.

Previous Next

Packages: emacs, cc-mode;

Reported by: 张海君 <netjune <at> icloud.com>

Date: Mon, 6 Apr 2015 10:11:02 UTC

Severity: normal

Done: Alan Mackenzie <acm <at> muc.de>

Bug is archived. No further changes may be made.

Full log


Message #14 received at 20266 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: 张海君 <netjune <at> icloud.com>
Cc: 20266 <at> debbugs.gnu.org
Subject: Re: bug#20266: Emacs doesn't respond when editing the attached c
 header	file.
Date: Tue, 21 Apr 2015 16:14:42 +0000
Hello, Netjune.

On Sun, Apr 12, 2015 at 10:15:15AM +0800, 张海君 wrote:

> > 在 2015年4月7日,23:16,Alan Mackenzie <acm <at> muc.de> 写道:

> > In article <mailman.71.1428315070.904.bug-gnu-emacs <at> gnu.org> you wrote:
> >> [-- text/plain, encoding 7bit, charset: us-ascii, 13 lines --]

> >> Emacs doesn't respond when editing the attached c header file.
> >> Emacs version: 24.4.

> >> ------------------------------------
> >> Run emacs with "emacs -Q test.h".
> >> M-x mark-whole-buffer
> >> M-x kill-ring-save
> >> M-x end-of-buffer
> >> M-x yank
> >> Then emacs doesn't respond for about 5 seconds.
> >> M-x scroll-down-command. 
> >> Then emacs doesn't respond for about 5 seconds too.

> > Yes.  This isn't good at all.

> >> M-x scroll-down-command.
> >> Then emacs doesn't respond for about 5 seconds too.

> > I can't actually reproduce this delay.

> Try do it more than 4 times, like: M-> M-v M-v M-v M-v M-v.
> The delay often happens at the first M-v, but not always.
> The delay is about 5 seconds on mac OSX (cpu: 1.4GHz), and is about 2 seconds on linux (cpu: 2.53Ghz).

After applying the patch below, I measured a single M-v from the end of
the buffer, and it took 0.14s.  This is on GNU/Linux on a 5 year old PC
(2.6 GHz processor).

> Or try to input some text (like newline chars) at the end of buffer.
> I input a newline at the end of buffer, and emacs didn't respond about 2 seconds on linux.

Yes.  That is a different kettle of fish altogether.

> After apply the patch, there is no delay after yank.

Thanks.  With the following patch (instead of the first one) there
shouldn't be much delay with C-x u after having done the yank.

The patch is calculated in Emacs-24.4.  Please try it out.



--- cc-mode.el.orig	2014-03-21 05:34:40.000000000 +0000
+++ cc-mode.el	2015-04-21 14:33:55.571993081 +0000
@@ -509,6 +509,14 @@
   (set (make-local-variable 'comment-line-break-function)
        'c-indent-new-comment-line)
 
+  ;; Prevent time-wasting activity on C-y.
+  (when (boundp 'yank-handled-properties)
+    (make-local-variable 'yank-handled-properties)
+    (let ((yank-cat-handler (assq 'category yank-handled-properties)))
+      (when yank-cat-handler
+	(setq yank-handled-properties (remq yank-cat-handler
+					    yank-handled-properties)))))
+
   ;; For the benefit of adaptive file, which otherwise mis-fills.
   (setq fill-paragraph-handle-comment nil)
 
@@ -831,6 +839,18 @@
 (defvar c-old-EOM 0)
 (make-variable-buffer-local 'c-old-EOM)
 
+(defun c-called-from-text-property-change-p ()
+  ;; Is the primitive which invoked `before-change-functions' or
+  ;; `after-change-functions' one which merely changes text properties?  This
+  ;; function must be called directly from a member of one of the above hooks.
+  ;;
+  ;; In the following call, frame 0 is `backtrace-frame', frame 1 is
+  ;; `c-called-from-text-property-change-p', frame 2 is
+  ;; `c-before/after-change', frame 3 is the primitive invoking the change
+  ;; hook.
+  (memq (cadr (backtrace-frame 3))
+	'(put-text-property remove-list-of-text-properties)))
+
 (defun c-extend-region-for-CPP (beg end)
   ;; Set c-old-BOM or c-old-EOM respectively to BEG, END, each extended to the
   ;; beginning/end of any preprocessor construct they may be in.
@@ -988,64 +1008,65 @@
   ;; it/them from the cache.  Don't worry about being inside a string
   ;; or a comment - "wrongly" removing a symbol from `c-found-types'
   ;; isn't critical.
-  (setq c-maybe-stale-found-type nil)
-  (save-restriction
-    (save-match-data
-      (widen)
-      (save-excursion
-	;; Are we inserting/deleting stuff in the middle of an identifier?
-	(c-unfind-enclosing-token beg)
-	(c-unfind-enclosing-token end)
-	;; Are we coalescing two tokens together, e.g. "fo o" -> "foo"?
-	(when (< beg end)
-	  (c-unfind-coalesced-tokens beg end))
-	;; Are we (potentially) disrupting the syntactic context which
-	;; makes a type a type?  E.g. by inserting stuff after "foo" in
-	;; "foo bar;", or before "foo" in "typedef foo *bar;"?
-	;;
-	;; We search for appropriate c-type properties "near" the change.
-	;; First, find an appropriate boundary for this property search.
-	(let (lim
-	      type type-pos
-	      marked-id term-pos
-	      (end1
-	       (or (and (eq (get-text-property end 'face) 'font-lock-comment-face)
-			(previous-single-property-change end 'face))
-		   end)))
-	  (when (>= end1 beg) ; Don't hassle about changes entirely in comments.
-	    ;; Find a limit for the search for a `c-type' property
-	    (while
-		(and (/= (skip-chars-backward "^;{}") 0)
-		     (> (point) (point-min))
-		     (memq (c-get-char-property (1- (point)) 'face)
-			   '(font-lock-comment-face font-lock-string-face))))
-	    (setq lim (max (point-min) (1- (point))))
-
-	    ;; Look for the latest `c-type' property before end1
-	    (when (and (> end1 (point-min))
-		       (setq type-pos
-			     (if (get-text-property (1- end1) 'c-type)
-				 end1
-			       (previous-single-property-change end1 'c-type nil lim))))
-	      (setq type (get-text-property (max (1- type-pos) lim) 'c-type))
-
-	      (when (memq type '(c-decl-id-start c-decl-type-start))
-		;; Get the identifier, if any, that the property is on.
-		(goto-char (1- type-pos))
-		(setq marked-id
-		      (when (looking-at "\\(\\sw\\|\\s_\\)")
-			(c-beginning-of-current-token)
-			(buffer-substring-no-properties (point) type-pos)))
-
-		(goto-char end1)
-		(skip-chars-forward "^;{}") ; FIXME!!!  loop for comment, maybe
-		(setq lim (point))
-		(setq term-pos
-		      (or (next-single-property-change end 'c-type nil lim) lim))
-		(setq c-maybe-stale-found-type
-		      (list type marked-id
-			    type-pos term-pos
-			    (buffer-substring-no-properties type-pos term-pos)
+  (unless (c-called-from-text-property-change-p)
+    (setq c-maybe-stale-found-type nil)
+    (save-restriction
+      (save-match-data
+	(widen)
+	(save-excursion
+	  ;; Are we inserting/deleting stuff in the middle of an identifier?
+	  (c-unfind-enclosing-token beg)
+	  (c-unfind-enclosing-token end)
+	  ;; Are we coalescing two tokens together, e.g. "fo o" -> "foo"?
+	  (when (< beg end)
+	    (c-unfind-coalesced-tokens beg end))
+	  ;; Are we (potentially) disrupting the syntactic context which
+	  ;; makes a type a type?  E.g. by inserting stuff after "foo" in
+	  ;; "foo bar;", or before "foo" in "typedef foo *bar;"?
+	  ;;
+	  ;; We search for appropriate c-type properties "near" the change.
+	  ;; First, find an appropriate boundary for this property search.
+	  (let (lim
+		type type-pos
+		marked-id term-pos
+		(end1
+		 (or (and (eq (get-text-property end 'face) 'font-lock-comment-face)
+			  (previous-single-property-change end 'face))
+		     end)))
+	    (when (>= end1 beg) ; Don't hassle about changes entirely in comments.
+	      ;; Find a limit for the search for a `c-type' property
+	      (while
+		  (and (/= (skip-chars-backward "^;{}") 0)
+		       (> (point) (point-min))
+		       (memq (c-get-char-property (1- (point)) 'face)
+			     '(font-lock-comment-face font-lock-string-face))))
+	      (setq lim (max (point-min) (1- (point))))
+
+	      ;; Look for the latest `c-type' property before end1
+	      (when (and (> end1 (point-min))
+			 (setq type-pos
+			       (if (get-text-property (1- end1) 'c-type)
+				   end1
+				 (previous-single-property-change end1 'c-type nil lim))))
+		(setq type (get-text-property (max (1- type-pos) lim) 'c-type))
+
+		(when (memq type '(c-decl-id-start c-decl-type-start))
+		  ;; Get the identifier, if any, that the property is on.
+		  (goto-char (1- type-pos))
+		  (setq marked-id
+			(when (looking-at "\\(\\sw\\|\\s_\\)")
+			  (c-beginning-of-current-token)
+			  (buffer-substring-no-properties (point) type-pos)))
+
+		  (goto-char end1)
+		  (skip-chars-forward "^;{}") ; FIXME!!!  loop for comment, maybe
+		  (setq lim (point))
+		  (setq term-pos
+			(or (next-single-property-change end 'c-type nil lim) lim))
+		  (setq c-maybe-stale-found-type
+			(list type marked-id
+			      type-pos term-pos
+			      (buffer-substring-no-properties type-pos term-pos)
 			      (buffer-substring-no-properties beg end)))))))
 
 	  (if c-get-state-before-change-functions
@@ -1056,7 +1077,7 @@
 	  )))
     ;; The following must be done here rather than in `c-after-change' because
     ;; newly inserted parens would foul up the invalidation algorithm.
-  (c-invalidate-state-cache beg))
+    (c-invalidate-state-cache beg)))
 
 (defvar c-in-after-change-fontification nil)
 (make-variable-buffer-local 'c-in-after-change-fontification)
@@ -1077,49 +1098,51 @@
   ;; This calls the language variable c-before-font-lock-functions, if non nil.
   ;; This typically sets `syntax-table' properties.
 
-  (c-save-buffer-state (case-fold-search open-paren-in-column-0-is-defun-start)
-    ;; When `combine-after-change-calls' is used we might get calls
-    ;; with regions outside the current narrowing.  This has been
-    ;; observed in Emacs 20.7.
-    (save-restriction
-      (save-match-data		  ; c-recognize-<>-arglists changes match-data
-	(widen)
-
-	(when (> end (point-max))
-	  ;; Some emacsen might return positions past the end. This has been
-	  ;; observed in Emacs 20.7 when rereading a buffer changed on disk
-	  ;; (haven't been able to minimize it, but Emacs 21.3 appears to
-	  ;; work).
-	  (setq end (point-max))
-	  (when (> beg end)
-	    (setq beg end)))
-
-	;; C-y is capable of spuriously converting category properties
-	;; c-</>-as-paren-syntax and c-cpp-delimiter into hard syntax-table
-	;; properties.  Remove these when it happens.
-	(c-clear-char-property-with-value beg end 'syntax-table
-					  c-<-as-paren-syntax)
-	(c-clear-char-property-with-value beg end 'syntax-table
-					  c->-as-paren-syntax)
-	(c-clear-char-property-with-value beg end 'syntax-table nil)
-
-	(c-trim-found-types beg end old-len) ; maybe we don't need all of these.
-	(c-invalidate-sws-region-after beg end)
-	;; (c-invalidate-state-cache beg) ; moved to `c-before-change'.
-	(c-invalidate-find-decl-cache beg)
-
-	(when c-recognize-<>-arglists
-	  (c-after-change-check-<>-operators beg end))
-
-	;; (c-new-BEG c-new-END) will be the region to fontify.  It may become
-	;; larger than (beg end).
-	(setq c-new-BEG beg
-	      c-new-END end)
-	(setq c-in-after-change-fontification t)
-	(save-excursion
-	  (mapc (lambda (fn)
-		  (funcall fn beg end old-len))
-		c-before-font-lock-functions))))))
+  ;; (c-new-BEG c-new-END) will be the region to fontify.  It may become
+  ;; larger than (beg end).
+  (setq c-new-BEG beg  c-new-END end)
+  
+  (unless (c-called-from-text-property-change-p)
+    (c-save-buffer-state (case-fold-search open-paren-in-column-0-is-defun-start)
+      ;; When `combine-after-change-calls' is used we might get calls
+      ;; with regions outside the current narrowing.  This has been
+      ;; observed in Emacs 20.7.
+      (save-restriction
+	(save-match-data  ; c-recognize-<>-arglists changes match-data
+	  (widen)
+
+	  (when (> end (point-max))
+	    ;; Some emacsen might return positions past the end. This has been
+	    ;; observed in Emacs 20.7 when rereading a buffer changed on disk
+	    ;; (haven't been able to minimize it, but Emacs 21.3 appears to
+	    ;; work).
+	    (setq end (point-max))
+	    (when (> beg end)
+	      (setq beg end)))
+
+	  ;; C-y is capable of spuriously converting category properties
+	  ;; c-</>-as-paren-syntax and c-cpp-delimiter into hard syntax-table
+	  ;; properties.  Remove these when it happens.
+	  (c-save-buffer-state ()
+	    (c-clear-char-property-with-value beg end 'syntax-table
+					      c-<-as-paren-syntax)
+	    (c-clear-char-property-with-value beg end 'syntax-table
+					      c->-as-paren-syntax)
+	    (c-clear-char-property-with-value beg end 'syntax-table nil))
+
+	  (c-trim-found-types beg end old-len) ; maybe we don't need all of these.
+	  (c-invalidate-sws-region-after beg end)
+	  ;; (c-invalidate-state-cache beg) ; moved to `c-before-change'.
+	  (c-invalidate-find-decl-cache beg)
+
+	  (when c-recognize-<>-arglists
+	    (c-after-change-check-<>-operators beg end))
+
+	  (setq c-in-after-change-fontification t)
+	  (save-excursion
+	    (mapc (lambda (fn)
+		    (funcall fn beg end old-len))
+		  c-before-font-lock-functions)))))))
 
 (defun c-set-fl-decl-start (pos)
   ;; If the beginning of the line containing POS is in the middle of a "local"



-- 
Alan Mackenzie (Nuremberg, Germany).




This bug report was last modified 10 years and 85 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.