pcs/edwin/marks.scm

84 lines
3.0 KiB
Scheme
Raw Permalink Normal View History

2023-05-20 05:57:04 -04:00
;;;; Permanent Marks
;;; The marks list is cleaned every time that a mark is added to the list,
;;; and every time that FOR-EACH-MARK! is called. This should keep the
;;; number of extraneous entries to a minimum. Note that FOR-EACH-MARK!
;;; and SET-MARK-LINE! are intended to be used together; in particular,
;;; a great deal of cleverness has been used to ensure that the changes
;;; made by SET-MARK-LINE! are noticed by FOR-EACH-MARK!. This turned out
;;; to be non-trivial to implement.
(define (mark-permanent! mark)
(let ((n (object-hash mark))
(marks (line-marks (mark-line mark))))
(if (not (memv n marks))
(let ((marks (cons n marks)))
(begin (clean-marks-tail! marks)
(set-line-marks! (mark-line mark) marks)))))
mark)
(define (clean-marks-tail! marks)
(if (not (null? (cdr marks)))
(if (object-unhash (cadr marks))
(clean-marks-tail! (cdr marks))
(begin (set-cdr! marks (cddr marks))
(clean-marks-tail! marks)))))
(define (for-each-mark! line procedure)
(define (loop-1 marks)
(if (not (null? marks))
(let ((mark (object-unhash (car marks))))
(if mark
(begin (procedure mark #!false)
(if (eq? marks (line-marks line))
(loop-2 marks (cdr marks))
(loop-1 (line-marks line))))
(begin (set-line-marks! line (cdr marks))
(loop-1 (line-marks line)))))))
(define (loop-2 previous marks)
(if (not (null? marks))
(let ((mark (object-unhash (car marks))))
(if mark
(begin (procedure mark #!false)
(if (eq? marks (cdr previous))
(loop-2 marks (cdr marks))
(loop-2 previous (cdr previous))))
(begin (set-cdr! previous (cddr previous))
(loop-2 previous (cdr previous)))))))
;;; point is treated as a special case and is no longer a permanent mark
;;; This would decrease the number of permanent marks considerably.
;;; Permannet marks are not so cheap and should be used only when
;;; really needed. Currently the point is obtained from current point
;;; but in a general setting there should be a way to get back to the
;;; buffer from group to get the point.
(let ((point (current-point)))
(if (and (eq? line (mark-line point))
(let ((n (object-hash point)))
(not (memv n (line-marks line)))))
(procedure point #!true)))
(loop-1 (line-marks line)))
(define (set-mark-line! mark new-line)
(let ((old-line (mark-line mark)))
(cond ((not (eq? old-line new-line))
(let ((marks
(let ((n (object-hash mark))
(marks (line-marks old-line)))
(define (loop previous marks)
(if (= n (car marks))
(begin (set-cdr! previous (cdr marks))
marks)
(loop marks (cdr marks))))
(if (= n (car marks))
(begin (set-line-marks! old-line (cdr marks))
marks)
(loop marks (cdr marks))))))
(%set-mark-line! mark new-line)
(set-cdr! marks (line-marks new-line))
(clean-marks-tail! marks)
(set-line-marks! new-line marks))))))