aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard M. Stallman1997-08-30 23:25:29 +0000
committerRichard M. Stallman1997-08-30 23:25:29 +0000
commit228282068d90a8ac238b5e8f4121213ab8df2b04 (patch)
treeb7bcc8dbb837764bce1635b6b3ac3f49cf645e10
parent80216a47a461ee8aa52872c551241c6a67bad78b (diff)
downloademacs-228282068d90a8ac238b5e8f4121213ab8df2b04.tar.gz
emacs-228282068d90a8ac238b5e8f4121213ab8df2b04.zip
(format-subtract-regions): New function.
(format-property-increment-region): New function. (format-deannotate-region): When multiple annotations go into a single text property, split the outer annotations (with format-subtract-regions) instead of resetting them; use lists of regions instead of a single number for the text property start. (format-deannotate-region): Don't change extents of enclosing annotations of the same kind. (format-deannotate-region): Use property-increment-region to add to numeric properties.
-rw-r--r--lisp/format.el258
1 files changed, 162 insertions, 96 deletions
diff --git a/lisp/format.el b/lisp/format.el
index 1ab15a4bb7c..5dff28edd3c 100644
--- a/lisp/format.el
+++ b/lisp/format.el
@@ -538,97 +538,113 @@ to write these unknown annotations back into the file."
538 538
539 ;; Delete the annotation 539 ;; Delete the annotation
540 (delete-region loc end) 540 (delete-region loc end)
541 (if positive 541 (cond
542 ;; Positive annotations are stacked, remembering location 542 ;; Positive annotations are stacked, remembering location
543 (setq open-ans (cons (list name loc) open-ans)) 543 (positive (setq open-ans (cons `(,name ((,loc . nil))) open-ans)))
544 ;; It is a negative annotation: 544 ;; It is a negative annotation:
545 ;; Close the top annotation & add its text property. 545 ;; Close the top annotation & add its text property.
546 ;; If the file's nesting is messed up, the close might not match 546 ;; If the file's nesting is messed up, the close might not match
547 ;; the top thing on the open-annotations stack. 547 ;; the top thing on the open-annotations stack.
548 ;; If no matching annotation is open, just ignore the close. 548 ;; If no matching annotation is open, just ignore the close.
549 (if (not (assoc name open-ans)) 549 ((not (assoc name open-ans))
550 (message "Extra closing annotation (%s) in file" name) 550 (message "Extra closing annotation (%s) in file" name))
551 ;; If one is open, but not on the top of the stack, close 551 ;; If one is open, but not on the top of the stack, close
552 ;; the things in between as well. Set `found' when the real 552 ;; the things in between as well. Set `found' when the real
553 ;; one is closed. 553 ;; one is closed.
554 (while (not found) 554 (t
555 (let* ((top (car open-ans)) ; first on stack: should match. 555 (while (not found)
556 (top-name (car top)) 556 (let* ((top (car open-ans)) ; first on stack: should match.
557 (start (car (cdr top))) ; location of start 557 (top-name (car top)) ; text property name
558 (params (cdr (cdr top))) ; parameters 558 (top-extents (nth 1 top)) ; property regions
559 (aalist translations) 559 (params (cdr (cdr top))) ; parameters
560 (matched nil)) 560 (aalist translations)
561 (if (equal name top-name) 561 (matched nil))
562 (setq found t) 562 (if (equal name top-name)
563 (message "Improper nesting in file.")) 563 (setq found t)
564 ;; Look through property names in TRANSLATIONS 564 (message "Improper nesting in file."))
565 (while aalist 565 ;; Look through property names in TRANSLATIONS
566 (let ((prop (car (car aalist))) 566 (while aalist
567 (alist (cdr (car aalist)))) 567 (let ((prop (car (car aalist)))
568 ;; And look through values for each property 568 (alist (cdr (car aalist))))
569 (while alist 569 ;; And look through values for each property
570 (let ((value (car (car alist))) 570 (while alist
571 (ans (cdr (car alist)))) 571 (let ((value (car (car alist)))
572 (if (member top-name ans) 572 (ans (cdr (car alist))))
573 ;; This annotation is listed, but still have to 573 (if (member top-name ans)
574 ;; check if multiple annotations are satisfied 574 ;; This annotation is listed, but still have to
575 (if (member 'nil (mapcar 575 ;; check if multiple annotations are satisfied
576 (lambda (r) 576 (if (member nil (mapcar (lambda (r)
577 (assoc r open-ans)) 577 (assoc r open-ans))
578 ans)) 578 ans))
579 nil ; multiple ans not satisfied 579 nil ; multiple ans not satisfied
580 ;; Yes, all set. 580 ;; If there are multiple annotations going
581 ;; If there are multiple annotations going 581 ;; into one text property, split up the other
582 ;; into one text property, adjust the 582 ;; annotations so they apply individually to
583 ;; begin points of the other annotations 583 ;; the other regions.
584 ;; so that we don't get double marking. 584 (setcdr (car top-extents) loc)
585 (let ((to-reset ans) 585 (let ((to-split ans) this-one extents)
586 this-one) 586 (while to-split
587 (while to-reset 587 (setq this-one
588 (setq this-one 588 (assoc (car to-split) open-ans)
589 (assoc (car to-reset) 589 extents (nth 1 this-one))
590 (cdr open-ans))) 590 (if (not (eq this-one top))
591 (if this-one 591 (setcar (cdr this-one)
592 (setcar (cdr this-one) loc)) 592 (format-subtract-regions
593 (setq to-reset (cdr to-reset)))) 593 extents top-extents)))
594 ;; Set loop variables to nil so loop 594 (setq to-split (cdr to-split))))
595 ;; will exit. 595 ;; Set loop variables to nil so loop
596 (setq alist nil aalist nil matched t 596 ;; will exit.
597 ;; pop annotation off stack. 597 (setq alist nil aalist nil matched t
598 open-ans (cdr open-ans)) 598 ;; pop annotation off stack.
599 (cond 599 open-ans (cdr open-ans))
600 ;; Check for pseudo-properties 600 (let ((extents top-extents)
601 ((eq prop 'PARAMETER) 601 (start (car (car top-extents)))
602 ;; This is a parameter of the top open ann: 602 (loc (cdr (car top-extents))))
603 ;; delete text and use as arg. 603 (while extents
604 (if open-ans 604 (cond
605 ;; (If nothing open, discard). 605 ;; Check for pseudo-properties
606 (setq open-ans 606 ((eq prop 'PARAMETER)
607 (cons (append (car open-ans) 607 ;; A parameter of the top open ann:
608 (list 608 ;; delete text and use as arg.
609 (buffer-substring 609 (if open-ans
610 start loc))) 610 ;; (If nothing open, discard).
611 (cdr open-ans)))) 611 (setq open-ans
612 (delete-region start loc)) 612 (cons
613 ((eq prop 'FUNCTION) 613 (append (car open-ans)
614 ;; Not a property, but a function to call. 614 (list
615 (let ((rtn (apply value start loc params))) 615 (buffer-substring
616 (if rtn (setq todo (cons rtn todo))))) 616 start loc)))
617 (t 617 (cdr open-ans))))
618 ;; Normal property/value pair 618 (delete-region start loc))
619 (setq todo 619 ((eq prop 'FUNCTION)
620 (cons (list start loc prop value) 620 ;; Not a property, but a function.
621 todo))))))) 621 (let ((rtn
622 (setq alist (cdr alist)))) 622 (apply value start loc params)))
623 (setq aalist (cdr aalist))) 623 (if rtn (setq todo (cons rtn todo)))))
624 (if matched 624 (t
625 nil 625 ;; Normal property/value pair
626 (setq todo
627 (cons (list start loc prop value)
628 todo))))
629 (setq extents (cdr extents)
630 start (car (car extents))
631 loc (cdr (car extents))))))))
632 (setq alist (cdr alist))))
633 (setq aalist (cdr aalist)))
634 (if (not matched)
626 ;; Didn't find any match for the annotation: 635 ;; Didn't find any match for the annotation:
627 ;; Store as value of text-property `unknown'. 636 ;; Store as value of text-property `unknown'.
628 (setq open-ans (cdr open-ans)) 637 (let ((extents top-extents)
629 (setq todo (cons (list start loc 'unknown top-name) 638 (start (car (car top-extents)))
630 todo)) 639 (loc (cdr (car top-extents))))
631 (setq unknown-ans (cons name unknown-ans))))))))) 640 (while extents
641 (setq open-ans (cdr open-ans)
642 todo (cons (list start loc 'unknown top-name)
643 todo)
644 unknown-ans (cons name unknown-ans)
645 extents (cdr extents)
646 start (car (car extents))
647 loc (cdr (car extents))))))))))))
632 648
633 ;; Once entire file has been scanned, add the properties. 649 ;; Once entire file has been scanned, add the properties.
634 (while todo 650 (while todo
@@ -637,21 +653,71 @@ to write these unknown annotations back into the file."
637 (to (nth 1 item)) 653 (to (nth 1 item))
638 (prop (nth 2 item)) 654 (prop (nth 2 item))
639 (val (nth 3 item))) 655 (val (nth 3 item)))
640 656
641 (put-text-property 657 (if (numberp val) ; add to ambient value if numeric
658 (format-property-increment-region from to prop val 0)
659 (put-text-property
642 from to prop 660 from to prop
643 (cond ((numberp val) ; add to ambient value if numeric 661 (cond ((get prop 'format-list-valued) ; value gets consed onto
644 (+ val (or (get-text-property from prop) 0)))
645 ((get prop 'format-list-valued) ; value gets consed onto
646 ; list-valued properties 662 ; list-valued properties
647 (let ((prev (get-text-property from prop))) 663 (let ((prev (get-text-property from prop)))
648 (cons val (if (listp prev) prev (list prev))))) 664 (cons val (if (listp prev) prev (list prev)))))
649 (t val)))) ; normally, just set to val. 665 (t val))))) ; normally, just set to val.
650 (setq todo (cdr todo))) 666 (setq todo (cdr todo)))
651 667
652 (if unknown-ans 668 (if unknown-ans
653 (message "Unknown annotations: %s" unknown-ans)))))) 669 (message "Unknown annotations: %s" unknown-ans))))))
654 670
671(defun format-subtract-regions (minu subtra)
672 "Remove the regions in SUBTRAHEND from the regions in MINUEND. A region
673is a dotted pair (from . to). Both parameters are lists of regions. Each
674list must contain nonoverlapping, noncontiguous regions, in descending
675order. The result is also nonoverlapping, noncontiguous, and in descending
676order. The first element of MINUEND can have a cdr of nil, indicating that
677the end of that region is not yet known."
678 (let* ((minuend (copy-alist minu))
679 (subtrahend (copy-alist subtra))
680 (m (car minuend))
681 (s (car subtrahend))
682 results)
683 (while (and minuend subtrahend)
684 (cond
685 ;; The minuend starts after the subtrahend ends; keep it.
686 ((> (car m) (cdr s))
687 (setq results (cons m results)
688 minuend (cdr minuend)
689 m (car minuend)))
690 ;; The minuend extends beyond the end of the subtrahend. Chop it off.
691 ((or (null (cdr m)) (> (cdr m) (cdr s)))
692 (setq results (cons (cons (1+ (cdr s)) (cdr m)) results))
693 (setcdr m (cdr s)))
694 ;; The subtrahend starts after the minuend ends; throw it away.
695 ((< (cdr m) (car s))
696 (setq subtrahend (cdr subtrahend) s (car subtrahend)))
697 ;; The subtrahend extends beyond the end of the minuend. Chop it off.
698 (t ;(<= (cdr m) (cdr s)))
699 (if (>= (car m) (car s))
700 (setq minuend (cdr minuend) m (car minuend))
701 (setcdr m (1- (car s)))
702 (setq subtrahend (cdr subtrahend) s (car subtrahend))))))
703 (nconc (nreverse results) minuend)))
704
705;; This should probably go somewhere other than format.el. Then again,
706;; indent.el has alter-text-property. NOTE: We can also use
707;; next-single-property-change instead of text-property-not-all, but then
708;; we have to see if we passed TO.
709(defun format-property-increment-region (from to prop delta default)
710 "Increment property PROP over the region between FROM and TO by the
711amount DELTA (which may be negative). If property PROP is nil anywhere
712in the region, it is treated as though it were DEFAULT."
713 (let ((cur from) val newval next)
714 (while cur
715 (setq val (get-text-property cur prop)
716 newval (+ (or val default) delta)
717 next (text-property-not-all cur to prop val))
718 (put-text-property cur (or next to) prop newval)
719 (setq cur next))))
720
655;;; 721;;;
656;;; Encoding 722;;; Encoding
657;;; 723;;;