source: trunk/source/cocoa-ide/hemlock/src/charprops.lisp @ 12484

Last change on this file since 12484 was 12484, checked in by gb, 10 years ago

A few attributes not implemented in Cocotron.

File size: 26.8 KB
Line 
1(in-package "HI")
2
3(defun make-empty-charprops-changes (&optional (size 2))
4  (make-array size :adjustable t :fill-pointer 0))
5
6(defun insert-charprops-change (changes index new)
7  "Insert a new change into the charprops changes vector at index.  Objects
8   at and beyond INDEX are shifted right to make room."
9  (vector-push-extend nil changes)
10  (replace changes changes :start1 (1+ index) :start2 index)
11  (setf (aref changes index) new))
12
13(defun delete-charprops-change (changes index)
14  "Delete the change at index from the charprops changes vector.  Objects
15   beyond INDEX are shifted left to fill the empty spot."
16  (unless (= (fill-pointer changes) index)
17    (replace changes changes :start1 index :start2 (1+ index)))
18  (decf (fill-pointer changes)))
19
20(defun push-charprops-change (change changes)
21  (vector-push-extend change changes))
22
23;;; Return the index of the charprops change that applies to
24;;; charpos, or else NIL if the charpos has (implicit)
25;;; default properties.
26(defun charprops-change-index-for-position (changes charpos)
27  (do ((i 0 (1+ i))
28       (i-1 nil i)
29       (change nil))
30      ((= i (length changes)) i-1)
31    (setq change (aref changes i))
32    (when (< charpos (charprops-change-index change))
33      (return i-1))))
34
35;;; Real programmers can write assembly in any language.
36(defun line-charprops-for-position (line charpos)
37  "Return, as multiple values, the plist, and start position and end
38   position over which the plist applies."
39  (unless (and (>= charpos 0)
40               (<= charpos (line-length line)))
41    (error "index ~d out of range" charpos))
42  (let* ((changes (line-charprops-changes line))
43         (change nil)
44         (prior-change nil)
45         (start-pos 0)
46         (end-pos 0))
47    (dotimes (i (length changes) (values (and change
48                                              (charprops-change-plist change))
49                                         start-pos (line-length line)))
50      (setq prior-change change)
51      (setq change (aref changes i))
52      (setq end-pos (charprops-change-index change))
53      (when (< charpos (charprops-change-index change))
54        (return (values (and prior-change (charprops-change-plist prior-change))
55                        start-pos end-pos)))
56      (setq start-pos (charprops-change-index change)))))
57
58(defun squeeze-out-superseded-changes (changes idx)
59  (let* ((base-change (aref changes idx)))
60    (do* ((i (1+ idx) (1+ i))
61          (change nil)
62          (n 0))
63         ((= i (length changes))
64          ;;(format t "~&start1 = ~d start2 = ~d" (1+ idx) (+ n 1 idx))
65          (replace changes changes :start1 (1+ idx) :start2 (+ n 1 idx))
66          (decf (fill-pointer changes) n)
67          changes)
68      (setq change (aref changes i))
69      (when (<= (charprops-change-index change)
70                (charprops-change-index base-change))
71        (setf (charprops-change-plist base-change) (charprops-change-plist change))
72        (incf n)
73        (setf (aref changes i) nil)))))
74
75;;; Set the charprops of the specified LINE between positions START and
76;;; END.  If END is NIL, that means the end of the line.  Note that this
77;;; doesn't merge in properties: it replaces whatever is there.
78(defun set-line-charprops (line charprops &key (start 0) end &aux plist)
79  (setq plist (charprops-as-plist charprops))
80  (when (and end (= end (line-length line)))
81    (setq end nil))
82  (when (and (null plist) (= start 0) (null end))
83    (setf (line-charprops-changes line) nil)
84    (return-from set-line-charprops))
85  (let* ((changes (line-charprops-changes line))
86         (new-change (make-charprops-change start plist)))
87    (if (null changes)
88      (let ((new-changes (make-array 2 :adjustable t :fill-pointer 0)))
89        (vector-push new-change new-changes)
90        (when end
91          (vector-push (make-charprops-change end nil) new-changes))
92        (setf (line-charprops-changes line) new-changes)
93        (line-charprops-changes line))
94      ;; Put the new charprops change into the right place in the charprops
95      ;; changes vector, making note of its position.
96      (do* ((i 0 (1+ i))
97            (change nil)
98            (prior-change nil change))
99           ((= i (length changes))
100            (insert-charprops-change changes i new-change)
101            (when end
102              (let ((prior-plist (and prior-change
103                                      (charprops-change-plist prior-change))))
104                (insert-charprops-change changes (1+ i)
105                                         (make-charprops-change end prior-plist)))))
106        (setq change (aref changes i))
107        (when (<= start (charprops-change-index change))
108          (insert-charprops-change changes i new-change)
109          (incf i)
110          (if (null end)
111            (setf (fill-pointer changes) i)
112            (let ((prior-plist (and prior-change
113                                    (charprops-change-plist prior-change))))
114              (insert-charprops-change changes i (make-charprops-change end prior-plist))
115              (squeeze-out-superseded-changes changes i)))
116          (return))))))
117
118;;; Returns two values: fresh charprops change vectors for the line's characters
119;;; before and after charpos.
120(defun split-line-charprops (line charpos)
121  (let ((changes (line-charprops-changes line)))
122    (when changes
123      (let ((left (make-array 2 :adjustable t :fill-pointer 0))
124            (right (make-array 2 :adjustable t :fill-pointer 0))
125            (pivot nil)
126            (prior-change nil))
127        (do* ((i 0 (1+ i))
128              (change nil))
129             ((or pivot
130                  (= i (length changes)))
131              (if (null pivot)
132                ;; The last change extends to the end of line, so that will be the
133                ;; charprops in effect at the beginning of the new line.
134                (if (null (charprops-change-plist change))
135                  (setq right nil)
136                  (let* ((c (copy-charprops-change change)))
137                    (setf (charprops-change-index c) 0)
138                    (push-charprops-change c right)))
139                ;; Some charprops changes remain.  First, split the prior change
140                ;; if necessary, and then pick up the rest of the shifts.
141                (progn
142                  (when (and prior-change
143                             (> charpos (charprops-change-index prior-change)))
144                    ;; need to split change
145                    (let* ((c (copy-charprops-change prior-change)))
146                      (setf (charprops-change-index c) 0)
147                      (push-charprops-change c right)))
148                  (loop for i from pivot below (length changes)
149                    as change = (aref changes i)
150                    do (decf (charprops-change-index change) charpos)
151                    (push-charprops-change (aref changes i) right))))
152              (values left right pivot))
153          (setq change (aref changes i))
154          (if (< (charprops-change-index change) charpos)
155            (progn
156              (push-charprops-change change left)
157              (setq prior-change change))
158            (setq pivot i)))))))
159
160(defun append-line-charprops (line changes)
161  (let* ((left (line-charprops-changes line))
162         (len (line-length line))
163         (right changes))
164    (cond ((and left right)
165           (loop for c across changes
166             for new-change = (copy-charprops-change c)
167             do (incf (charprops-change-index new-change) len)
168                (push-charprops-change new-change left)))
169          ((and (null left) right)
170           (setq left (copy-charprops-changes changes))
171           (adjust-charprops-change-indexes left len)
172           (setf (line-charprops-changes line) left))
173          ((and left (null right))
174           (push-charprops-change (make-charprops-change len nil) left)))
175    left))
176
177;;; Append the charprops-changes from line2 onto line1, modifying their
178;;; indexes appropriately.
179(defun join-line-charprops (line1 line2)
180  (let* ((left (line-charprops-changes line1))
181         (lidx (1- (length left)))
182         (right (line-charprops-changes line2))
183         (ridx 0)
184         (line1-len (line-length line1)))
185    (cond ((and left right)
186           ;; If the last change on line1 and the first change on line2
187           ;; represent the same properties, then omit line2's first
188           ;; change.
189           (let* ((lchange (aref left lidx))
190                  (lprops (charprops-change-plist lchange))
191                  (rchange (aref right ridx))
192                  (rprops (charprops-change-plist rchange)))
193             (if (> 0 (charprops-change-index rchange))
194               ;; There is an implicit run of default charprops at the
195               ;; start of the line.
196               (unless (null lprops)
197                 ;; The last change on line1 represents some non-default
198                 ;; set of charprops, so insert an explicit change to the
199                 ;; default set before copying over the rest.
200                 (push-charprops-change (make-charprops-change (1+ line1-len) nil)
201                                        left))
202               (when (charprops-equal lprops rprops)
203                 (incf ridx)))
204             (do* ((i ridx (1+ i))
205                   (change nil))
206                  ((= i (length right)))
207               (setq change (aref right i))
208               (incf (charprops-change-index change) (1+ line1-len))
209               (push-charprops-change change left))))
210          ((and (null left) right)
211           (adjust-charprops-change-indexes right line1-len)
212           (setf (line-charprops-changes line1) right))
213          ((and left (null right))
214           (let* ((lchange (aref left lidx)))
215             (unless (null (charprops-change-plist lchange))
216               (push-charprops-change (make-charprops-change (1+ line1-len) nil)
217                                   left))))
218          ;; otherwise both nil, so don't need to do anything.
219          )
220    left))
221
222(defun copy-line-charprops (line &key (start 0) end)
223  "Return a freshly-consed vector of charprops changes that applies to the
224   characters in the interval [start, end) on the specified line.  If the
225   charprops in between start and end are the default charprops, return
226   NIL."
227  (let ((changes (line-charprops-changes line)))
228    ;; some early-out special cases
229    (cond ((null changes)
230           (return-from copy-line-charprops))
231          ((and (= start 0) (null end))
232           (return-from copy-line-charprops (copy-charprops-changes changes))))
233    (unless end
234      (setq end (line-length line)))
235    (let* ((new-changes (make-empty-charprops-changes))
236           (start-idx (charprops-change-index-for-position changes start))
237           (end-idx (charprops-change-index-for-position changes (1- end))))
238      (if (eql start-idx end-idx)
239        (if (null start-idx)
240          (setq new-changes nil)
241          (let* ((change (aref changes start-idx))
242                 (plist (charprops-change-plist change)))
243            (if (null plist)
244              (setq new-changes nil)
245              (push-charprops-change (make-charprops-change start plist)
246                                     new-changes))))
247        (do ((i (or start-idx 0) (1+ i)))
248            ((> i end-idx))
249          (let* ((change (aref changes i))
250                 (index (charprops-change-index change))
251                 (plist (charprops-change-plist change)))
252          (push-charprops-change (make-charprops-change
253                                  (max 0 (- index start)) plist)
254                                 new-changes))))
255      new-changes)))
256
257(defun delete-line-charprops (line &key (start 0) end)
258  (let ((changes (line-charprops-changes line)))
259    ;; some early-out special cases
260    (cond ((null changes)
261           (return-from delete-line-charprops))
262          ((and (= start 0) (null end))
263           (setf (line-charprops-changes line) nil)
264           (return-from delete-line-charprops)))
265    (unless end
266      (setq end (line-length line)))
267    (assert (<= start end) (start end))
268    (let* ((start-idx (charprops-change-index-for-position changes start))
269           (end-idx (charprops-change-index-for-position changes (1- end))))
270      (cond ((null start-idx)
271             (if (null end-idx)
272               (adjust-charprops-change-indexes changes (- start end) :start 0)
273               (progn
274                 ;; delete changes before end-idx
275                 (replace changes changes :start1 0 :start2 end-idx)
276                 (decf (fill-pointer changes) end-idx)
277                 (setf (charprops-change-index (aref changes 0)) start)
278                 ;; move back start of subsequent changes, if there are any
279                 (when (> (length changes) 1)
280                   (adjust-charprops-change-indexes changes (- start end)
281                                                    :start 1)
282                   ;; if the change is now zero-length, remove it
283                   (when (= (charprops-change-index (aref changes 0))
284                            (charprops-change-index (aref changes 1)))
285                     (delete-charprops-change changes 0))))))
286            ((eql start-idx end-idx)
287             ;; The deletion takes place within the scope of a single
288             ;; charprops run.
289             ;; Move back start of subsequent changes, if there are any
290             (when (> (length changes) (1+ start-idx))
291               (adjust-charprops-change-indexes changes (- start end)
292                                                :start (1+ start-idx))
293               ;; if the change is now zero-length, remove it
294               (when (= (charprops-change-index (aref changes start-idx))
295                        (charprops-change-index (aref changes (1+ start-idx))))
296                 (delete-charprops-change changes start-idx))))
297            (t
298             ;; Remove changes between start-idx and and end-idx.
299             (replace changes changes :start1 (1+ start-idx)
300                      :start2 end-idx)
301             (decf (fill-pointer changes) (- end-idx (1+ start-idx)))
302             (setf (charprops-change-index (aref changes (1+ start-idx))) start)
303             (when (> (length changes) (1+ start-idx))
304               (adjust-charprops-change-indexes changes (- start end)
305                                                :start (+ 2 start-idx))
306               ;; if first change is now zero-length, remove it
307               (when (= (charprops-change-index (aref changes start-idx))
308                        (charprops-change-index (aref changes (1+ start-idx))))
309                 (delete-charprops-change changes start-idx))))))
310    (coalesce-line-charprops line)))
311
312;;; Coalesce adjacent changes with CHARPROP-EQUAL plists.
313;;; Maybe make this remove zero-length changes, too?
314(defun coalesce-line-charprops (line)
315  (let ((changes (line-charprops-changes line)))
316    (do* ((i 0 (1+ i))
317          (change nil))
318         ((>= i (length changes)))
319      (setq change (aref changes i))
320      (loop with j = (1+ i)
321        while (and (< j (length changes))
322                   (charprops-equal (charprops-change-plist change)
323                                    (charprops-change-plist (aref changes j))))
324        do (delete-charprops-change changes j)))
325    ;; Elide any changes with NIL plists at the start of the line.
326    (loop
327      while (and (> (length changes) 0)
328                 (null (charprops-change-plist (aref changes 0))))
329      do (delete-charprops-change changes 0))
330    (when (zerop (length changes))
331      (setf (line-charprops-changes line) nil)))
332  (line-charprops-changes line))
333     
334(defun adjust-charprops-change-indexes (changes delta &key (start 0))
335  (do* ((i start (1+ i))
336        (change nil))
337       ((>= i (length changes))
338        changes)
339    (setq change (aref changes i))
340    (incf (charprops-change-index change) delta)))
341
342;;; Add delta to the starting index of all charprops changes after the one
343;;; containing charpos.
344(defun adjust-charprops-changes (changes charpos delta)
345  (let ((start-idx (charprops-change-index-for-position changes charpos)))
346    (adjust-charprops-change-indexes changes delta :start (if start-idx
347                                                            (1+ start-idx)
348                                                            0))))
349
350#|
351;;; Both target-changes and source-changes are vectors of charprops-change
352;;; objects.  Insert charprops-changes from source-changes from start2 to end2
353;;; into target-changes at start1.
354(defun insert-charprops-changes (target-changes source-changes &key startpos1
355                                            startpos2 endpos2)
356  (let* ((target-idx (charprops-change-index-for-position startpos1))
357         (source-idx (charprops-change-index-for-position startpos2)))
358    (adjust-charprops-changes target-changes startpos1 (- endpos2 startpos2))
359    (do* ((i source-idx (1+ i))
360          (change nil))
361         ((= i
362
363
364
365         (start2 (charprops-change-index-for-position startpos2))
366         (end2 (charprops-change-index-for-position endpos1))
367         (n (- end2 start2))) ; number of changes to add to target-changes
368|#
369
370(defvar *display-properties*
371  '(:font-name
372    :font-size
373    :font-weight
374    :font-slant
375    :font-underline
376    :font-color
377    :background-color))
378
379;;; Accessing charprops
380
381(defun next-charprop-value (mark name &key view)
382  (let ((props (next-charprops mark :view view)))
383    (getf props name)))
384
385(defun previous-charprop-value (mark name &key view)
386  (let ((props (previous-charprops mark :view view)))
387    (getf props name)))
388
389(defun set-charprop-value (mark name value &key (count 1 count-supplied-p) end view)
390  (declare (ignore view count value name mark))
391  (when (and count-supplied-p end)
392    (error "Cannot specify both :COUNT and :END")))
393
394(defun find-charprop-value (mark name value &key (count nil count-supplied-p)
395                                 end view from-end)
396  (declare (ignore from-end view count value name mark))
397  (when (and count-supplied-p end)
398    (error "Cannot specify both :COUNT and :END")))
399
400(defun filter-match (filter name)
401  (cond ((functionp filter)
402         (funcall filter name))
403        ((eq filter :display)
404         (member name *display-properties* :test #'eq))
405        ((typep filter 'sequence)
406         (member name filter))
407        (t
408         name)))
409
410(defun filter-charprops (filter charprops)
411  (if (eq filter t)
412    charprops
413    (typecase charprops
414      ((satisfies ccl::plistp) (loop for (k v) on charprops by #'cddr
415                                 when (filter-match filter k)
416                                 collect k and collect v))
417      (hash-table (loop for k being the hash-keys of charprops using (hash-value v)
418                    when (filter-match filter k)
419                    collect k and collect v)))))
420
421(defun next-charprops (mark &key view (filter t))
422  "Return the properties of the character after MARK."
423  (declare (ignore view))
424  (when (next-character mark)
425    (let* ((props (line-charprops-for-position (mark-line mark) (mark-charpos mark))))
426      (filter-charprops filter props))))
427
428(defun previous-charprops (mark &key view (filter t))
429  "Return the properties of the character before MARK."
430  (with-mark ((m mark))
431    (when (mark-before m)
432      (next-charprops m :view view :filter filter))))
433
434(defun set-charprops (mark charprops &key (count 1 count-supplied-p)
435                           (end nil end-supplied-p) filter)
436  (declare (ignore filter end count charprops mark))
437  (when (and count-supplied-p end-supplied-p)
438    (error "Only one of count or end can be supplied."))
439 
440)
441
442;;; Return a list of charprops-change vectors that correspond to the lines
443;;; in the region defined by the paramaters.
444(defun charprops-in-region (region-or-mark &key (count 1 count-supplied-p)
445                                           end filter)
446  (declare (ignore filter))
447  (when (and count-supplied-p end)
448    (error "Only one of count or end can be supplied."))
449  (let (region result)
450    (etypecase region-or-mark
451      (mark (with-mark ((m region-or-mark))
452              (when end
453                (setq count (- end (mark-absolute-position m))))
454              (character-offset m count)
455              (setq region (region region-or-mark m))))
456      (region (setq region region-or-mark)))
457    (let* ((start (region-start region))
458           (first-line (mark-line start))
459           (end (region-end region))
460           (last-line (mark-line end)))
461      (do* ((line first-line (line-next line))
462            (m (copy-mark start) (line-start m line)))
463           ((eq line last-line)
464            ;; last line
465            (let* ((changes (line-charprops-changes line))
466                   (idx (charprops-change-index-for-position changes (mark-charpos end))))
467              (push (subseq (line-charprops-changes line) 0 idx) result)
468              (nreverse result)))
469        (let* ((changes (line-charprops-changes line))
470               (idx (or (charprops-change-index-for-position changes (mark-charpos m)) 0)))
471          (push (subseq changes idx) result))))))
472
473(defun apply-charprops (mark charprops-range &key filter from-end)
474  (declare (ignore from-end filter charprops-range mark)))
475
476(defun find-charprops (mark charprops &key count end view filter from-end)
477  (declare (ignore from-end filter view end count charprops mark)))
478
479(defun find-charprops-change (mark &key count end view filter from-end)
480  (declare (ignore from-end filter view end count))
481  (let* ((line (mark-line mark))
482         (charpos (mark-charpos mark))
483         (changes (line-charprops-changes line))
484         (idx (charprops-change-index-for-position changes charpos)))
485    (loop
486      (incf idx)
487      (if (= idx (length changes))
488        (setf line (line-next line)
489              charpos 0
490              changes (line-charprops-changes line)
491              idx (charprops-change-index-for-position changes charpos))
492        (return (move-mark mark (charprops-change-index (aref changes idx))))))))
493
494(defun print-line-charprops (line &key (start 0) (end (hi:line-length line)))
495  (let* ((string (hi:line-string line))
496         (charprops-changes (hi::line-charprops-changes line)))
497    (let ((index start)
498          (plist nil)
499          (x 0))
500      (loop for change across charprops-changes
501        do (let* ((next-index (charprops-change-index change))
502                  (next-plist (charprops-change-plist change))
503                  (end (min end next-index)))
504             (when (and (>= index start)
505                        (< index end))
506               (format t "~& ~d: [~d, ~d) ~s: ~s" x index end
507                       (subseq string index end) plist))
508             (setq index next-index)
509             (setq plist next-plist)
510             (incf x)))
511      ;; final part of line
512      (format t "~& ~d: [~d, ~d) ~s: ~s" x index end
513              (subseq string index end) plist))))
514
515(defun copy-charprops (charprops)
516  (copy-list charprops))
517
518
519;;; Utility functions
520
521(defun charprop-equal (value1 value2)
522  (cond ((and (stringp value1) (stringp value2))
523         (string= value1 value2))
524        ((and (numberp value1) (numberp value2))
525         (= value1 value2))
526        (t
527         (eql value1 value2))))
528
529(defun charprops-get (charprops name &key (filter t))
530  (when (and name (filter-match filter name))
531    (etypecase charprops
532      ((satisfies ccl::plistp) (getf charprops name))
533      (hash-table (gethash name charprops)))))
534
535(defun charprops-set (charprops name value)
536  (etypecase charprops
537    ((satisfies ccl::plistp) (setf (getf charprops name) value))
538    (hash-table (setf (gethash name charprops) value)))
539  charprops)
540
541(defun same-sets (s1 s2 &key (test #'eql))
542  (and (subsetp s1 s2 :test test)
543       (subsetp s2 s1 :test test)))
544
545;; This may need tuning later.
546(defun charprops-equal (charprops1 charprops2 &key (filter t))
547  (setq charprops1 (charprops-as-plist charprops1 :filter filter)
548        charprops2 (charprops-as-plist charprops2 :filter filter))
549  (let (keys1 values1 keys2 values2)
550    (loop for (k1 v1) on charprops1 by #'cddr
551      do (push k1 keys1)
552         (push v1 values1))
553    (loop for (k2 v2) on charprops2 by #'cddr
554      do (push k2 keys2)
555         (push v2 values2))
556    (and (same-sets keys1 keys2)
557         (same-sets values1 values2 :test #'charprop-equal))))
558
559(defun charprops-as-plist (charprops &key (filter t))
560  (etypecase charprops
561    ((satisfies ccl::plistp) (if (eq filter t)
562                               charprops
563                               (loop for (k v) on charprops by #'cddr
564                                 when (filter-match filter k)
565                                 collect k and collect v)))
566    (hash-table (loop for k being the hash-keys of charprops using (hash-value v)
567                  when (filter-match filter k)
568                  collect k and collect v))))
569
570(defun charprops-as-hash (charprops &key (filter t))
571  (etypecase charprops
572    ((satisfies ccl::plistp) (let ((hash (make-hash-table)))
573                               (loop for (k v) on charprops by #'cddr
574                                 when (filter-match filter k)
575                                 do (setf (gethash k hash) v))
576                               hash))
577    (hash-table (if (eq filter t)
578                  charprops
579                  (let ((hash (make-hash-table)))
580                    (maphash #'(lambda (k v)
581                                 (when (filter-match filter k)
582                                   (setf (gethash k hash) v)))
583                             charprops))))))
584
585(defun charprops-names (charprops &key (filter t))
586  (etypecase charprops
587    ((satisfies ccl::plistp) (loop for name in charprops by #'cddr
588                               when (filter-match filter name)
589                               collect name))
590    (hash-table (loop for name being the hash-keys of charprops
591                  when (filter-match filter name)
592                  collect name))))
593
594;;; From <AppKit/NSAttributedString.h>
595(defparameter *cocoa-attributes*
596  '((:ns-font . #&NSFontAttributeName)
597    (:ns-paragraph-style . #&NSParagraphStyleAttributeName)
598    (:ns-foreground-color . #&NSForegroundColorAttributeName)
599    (:ns-underline-style . #&NSUnderlineStyleAttributeName)
600    (:ns-superscript . #&NSSuperscriptAttributeName)
601    (:ns-background-color . #&NSBackgroundColorAttributeName)
602    (:ns-attachment . #&NSAttachmentAttributeName)
603    (:ns-ligature . #&NSLigatureAttributeName)
604    (:ns-baseline-offset . #&NSBaselineOffsetAttributeName)
605    (:ns-kern . #&NSKernAttributeName)
606    (:ns-link . #&NSLinkAttributeName)
607    (:ns-stroke-width . #&NSStrokeWidthAttributeName)
608    (:ns-stroke-color . #&NSStrokeColorAttributeName)
609    (:ns-underline-color . #&NSUnderlineColorAttributeName)
610    (:ns-strikethrough-style . #&NSStrikethroughStyleAttributeName)
611    (:ns-strikethrough-color . #&NSStrikethroughColorAttributeName)
612    (:ns-shadow . #&NSShadowAttributeName)
613    (:ns-obliqueness . #&NSObliquenessAttributeName)
614    (:ns-expansion . #&NSExpansionAttributeName)
615    (:ns-cursor . #&NSCursorAttributeName)
616    (:ns-tool-tip . #&NSToolTipAttributeName)
617    #-cocotron
618    (:ns-character-shap . #&NSCharacterShapeAttributeName)
619    #-cocotron
620    (:ns-glyph-info . #&NSGlyphInfoAttributeName)
621    ;;(:ns-marked-clause-segment . #&NSMarkedClauseSegmentAttributeName)
622    ;;(:ns-spelling-state . #&NSSpellingStateAttributeName)
623    ))
624
Note: See TracBrowser for help on using the repository browser.