Changeset 568


Ignore:
Timestamp:
Feb 24, 2004, 12:31:29 PM (21 years ago)
Author:
Gary Byers
Message:

Start to use Hemlock for documents.

Location:
trunk/ccl/examples
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/ccl/examples/cocoa-editor.lisp

    r563 r568  
    2323           
    2424   
    25 (defparameter *default-font-name* "Courier")
    26 (defparameter *default-font-size* 12.0e0)
    27 
    28    
    29 ;;; Try to find the specified font.  If it doesn't exist (or isn't
    30 ;;; fixed-pitch), try to find a fixed-pitch font of the indicated size.
    31 (defun default-font (&key (name *default-font-name*)
    32                           (size *default-font-size*))
    33   (setq size (float size 0.0f0))
    34   (with-cstrs ((name name))
    35     (with-autorelease-pool
    36         (rletz ((matrix (:array :float 6)))
    37           (setf (%get-single-float matrix 0) size
    38                 (%get-single-float matrix 12) size)
    39           (let* ((fontname (send (@class ns-string) :string-with-c-string name))
    40                  (font (send (@class ns-font)
    41                                   :font-with-name fontname :matrix matrix)))
    42             (if (or (%null-ptr-p font)
    43                     (and
    44                      (not (send font 'is-fixed-pitch))
    45                      (not (eql #$YES (objc-message-send font "_isFakeFixedPitch" :<BOOL>)))))
    46               (setq font (send (@class ns-font)
    47                                :user-fixed-pitch-font-of-size size)))
    48             font)))))
    4925
    5026(defun size-of-char-in-font (f)
     
    9672
    9773
    98 (defparameter *tab-width* 8)
    9974
    100 ;;; Create a paragraph style, mostly so that we can set tabs reasonably.
    101 (defun create-paragraph-style (font line-break-mode)
    102   (let* ((p (make-objc-instance 'ns-mutable-paragraph-style))
    103          (charwidth (send (send font 'screen-font)
    104                           :width-of-string #@" ")))
    105     (send p
    106           :set-line-break-mode
    107           (ecase line-break-mode
    108             (:char #$NSLineBreakByCharWrapping)
    109             (:word #$NSLineBreakByWordWrapping)
    110             ;; This doesn't seem to work too well.
    111             ((nil) #$NSLineBreakByClipping)))
    112     ;; Clear existing tab stops.
    113     (send p :set-tab-stops (send (@class ns-array) 'array))
    114     (do* ((i 1 (1+ i)))
    115          ((= i 100) p)
    116       (let* ((tabstop (make-objc-instance
    117                        'ns-text-tab
    118                        :with-type #$NSLeftTabStopType
    119                        :location  (* (* i *tab-width*)
    120                                         charwidth))))
    121         (send p :add-tab-stop tabstop)
    122         (send tabstop 'release)))))
    123    
    124 (defun create-text-attributes (&key (font (default-font))
    125                                     (line-break-mode :char)
    126                                     (color nil))
    127   (let* ((dict (make-objc-instance
    128                 'ns-mutable-dictionary
    129                 :with-capacity (if color 3 2))))
    130     (send dict 'retain)
    131     (send dict
    132           :set-object (create-paragraph-style font line-break-mode)
    133           :for-key #@"NSParagraphStyle")
    134     (send dict :set-object font :for-key #@"NSFont")
    135     (when color
    136       (send dict :set-object color :for-key #@"NSColor"))
    137     dict))
    13875                                   
    13976 
    14077(defclass lisp-editor-window-controller (ns:ns-window-controller)
    141     ((textview :foreign-type :id)       ;The (primary) textview
    142      (packagename :foreign-type :id)    ;Textfield for package name display
    143      (echoarea :foreign-type :id)       ;Textfield for message display.
    144      (history-count :foreign-type :int) ;current history count (for prev/next)
    145      (prev-history-count :foreign-type :int) ;value of history-count before last cmd
    146      )
     78    ()
    14779  (:metaclass ns:+ns-object))
    14880
    149 (define-objc-method ((:void :display-echo-area contents) lisp-editor-window-controller)
    150   (send (slot-value self 'echoarea) :set-string-value contents))
    151 
    152 (define-objc-method ((:void clear-echo-area)
    153                      lisp-editor-window-controller)
    154   (send (slot-value self 'echoarea) :set-string-value #@""))
    155 
    156 (define-objc-method ((:void :display-package-name name)
    157                      lisp-editor-window-controller)
    158   (send (slot-value self 'packagename) :set-string-value name))
    159 
    160 (defun shortest-package-name (package)
    161   (let* ((shortest (package-name package))
    162          (shortest-len (length shortest)))
    163     (declare (fixnum shortest-len))
    164     (dolist (nick (package-nicknames package) shortest)
    165       (let* ((nicklen (length nick)))
    166         (declare (fixnum nicklen))
    167         (if (< nicklen shortest-len)
    168           (setq shortest-len nicklen shortest nick))))))
    169              
    170 (define-objc-method ((:void update-package-name)  lisp-editor-window-controller)
    171   (let* ((info (info-from-controller self))
    172          (package (and info (getf (cocoa-editor-info-modeline-plist info)
    173                                   :package)))
    174          (name (if (and package (typep package 'package))
    175                  (shortest-package-name package)
    176                  "#<PACKAGE unset>")))
    177     (with-cstrs ((name name))
    178       (send self
    179             :display-package-name (send (@class ns-string)
    180                                         :string-with-c-string name)))))
    18181   
    18282;;; The LispEditorWindowController is the textview's "delegate": it
     
    18484;;; perform actions on behalf of the textview.
    18585
    186 ;;; Action methods implemented by the controller (in its role as the
    187 ;;; textview's delegate).
    188 
    189 ;;; If the first line of the buffer contains text between a pair of
    190 ;;; "-*-"s, treat the line as an attribute line.
    191 (define-objc-method ((:void :range-for-modeline-in-text-view tv
    192                             :result ((* :<NSR>ange) r))
    193                      lisp-editor-window-controller)
    194   (let* ((textstring (send tv 'string)))
    195     (slet ((linerange
    196             (send textstring :line-range-for-range (ns-make-range 0 0))))
    197       (when (> (pref linerange :<NSR>ange.length) 0)
    198         (decf (pref linerange :<NSR>ange.length)))
    199       (slet ((matchrange1
    200               (send textstring
    201                     :range-of-string #@"-*-"
    202                     :options 0
    203                     :range linerange)))
    204         (rlet ((matchrange2 :<NSR>ange))
    205           (if (and (> (pref matchrange1 :<NSR>ange.length) 0)
    206                    (progn
    207                      (incf (pref matchrange1 :<NSR>ange.location)
    208                            (pref matchrange1 :<NSR>ange.length))
    209                      (setf (pref matchrange1 :<NSR>ange.length)
    210                            (- (pref linerange :<NSR>ange.length)
    211                               (pref matchrange1 :<NSR>ange.location)))
    212                      (send/stret matchrange2 textstring
    213                                  :range-of-string #@"-*-"
    214                                  :options 0
    215                                  :range matchrange1)
    216                      (> (pref matchrange2 :<NSR>ange.length) 0))) 
    217             (setf (pref r :<NSR>ange.location)
    218                   (pref matchrange1 :<NSR>ange.location)
    219                   (pref r :<NSR>ange.length)
    220                   (- (pref matchrange2 :<NSR>ange.location)
    221                      (pref r :<NSR>ange.location)))
    222             (setf (pref r :<NSR>ange.location) 0
    223                   (pref r :<NSR>ange.length) 0)))))))
    224 
    225 ;;; Return a list whose elements are of the form:
    226 ;;;  (opt-name-keyword . (opt-value-start . opt-value-end))
    227 ;;;  for each option.  Options are separated colons semicolons;
    228 ;;;  option names are separated from option values by colons.
    229 (defun extract-modeline-components (string)
    230   (let* ((start 0)
    231          (end (length string))
    232          (options ()))
    233     (if (find #\: string)
    234       (block parse-options
    235         (do* ((opt-start start (1+ semi))
    236               semi
    237               colon)
    238              (nil)
    239           (setq colon (position #\: string :start opt-start :end end))
    240           (unless colon
    241             (return nil))
    242           (setq semi (or (position #\; string :start colon :end end) end))
    243           (push
    244            (cons
    245             (intern
    246              (nstring-upcase (string-trim '(#\space #\tab)
    247                                           (subseq string opt-start colon)))
    248              *keyword-package*)     
    249             (cons
    250              (do* ((i (1+ colon) (1+ i)))
    251                   ((= i semi) (return-from parse-options nil))
    252                (unless (whitespacep (schar string i))
    253                  (return i)))
    254              (do* ((i semi j)
    255                    (j (1- i) (1- j)))
    256                   (())
    257                (unless (whitespacep (schar string j))
    258                  (return i)))))
    259            options)
    260           (when (= semi end) (return options)))))))
    261 
    262 (defun process-modeline-components (components info)
    263   (let* ((plist ()))
    264     (dolist (c components (setf (cocoa-editor-info-modeline-plist info) plist))
    265       (let* ((indicator (car c))
    266              (value (cdr c)))
    267         (case indicator
    268           (:package (let* ((spec (let* ((*package* *keyword-package*))
    269                                    (ignore-errors (read-from-string value)))))
    270                       (when spec
    271                         (let* ((pkg (ignore-errors (find-package
    272                                                     (if (atom spec)
    273                                                       spec
    274                                                       (car spec))))))
    275                           (if pkg
    276                             (setf (getf plist indicator) pkg))))))
    277           (t (setf (getf plist indicator) value)))))))
    278 
    279 (define-objc-method ((:id :reparse-modeline tv)
    280                      lisp-editor-window-controller)
    281   (unless (%null-ptr-p tv)
    282     (let* ((info (info-from-controller self)))
    283       (when info
    284         (let* ((textstring (send tv 'string)))
    285           (rlet ((modelinerange :<NSR>ange))
    286             (send self
    287                   :range-for-modeline-in-text-view tv
    288                   :result modelinerange)
    289             (unless (zerop (pref modelinerange :<NSR>ange.length))
    290               (let* ((string (lisp-string-from-nsstring
    291                               (send textstring
    292                                     :substring-with-range modelinerange)))
    293                      (components
    294                       (mapcar #'(lambda (x)
    295                                   (destructuring-bind (name start . end) x
    296                                     (cons name
    297                                           (subseq string start end))))
    298                               (extract-modeline-components string))))
    299                 (process-modeline-components components info)
    300                 (send self 'update-package-name))))))))
    301   self)
    302  
    303 
    304 (define-objc-method ((:id :add-modeline tv)
    305                      lisp-editor-window-controller)
    306   (let* ((textstring (send tv 'string)))
    307     (rlet ((modelinerange :<NSR>ange)
    308            (selrange :<NSR>ange))
    309       (send self :range-for-modeline-in-text-view  tv :result modelinerange)
    310       (when (= (pref modelinerange :<NSR>ange.length) 0)
    311         (let* ((info (info-from-document self))
    312                (package (or (if info
    313                               (getf
    314                                :package
    315                                (cocoa-editor-info-modeline-plist info)))
    316                             (symbol-value-in-top-listener-process
    317                              '*package*)
    318                             *package*))
    319                (package-name (package-name package))
    320                (namelen (length package-name)))
    321           (with-cstrs ((pname package-name))
    322             (with-nsstr (nsstr pname namelen)
    323               (let* ((proto (send (@class ns-string)
    324                                   :string-with-format
    325                                   #@";;;-*- Mode: LISP; Package: %@ -*-
    326 "
    327                                   (:id nsstr))))
    328                 (send tv :set-selected-range (ns-make-range 0 0))
    329                 (send tv :insert-text proto)
    330                 (setf (pref modelinerange :<NSR>ange.location)
    331                       6
    332                       (pref modelinerange :<NSR>ange.length)
    333                       (- (send proto 'length) (+ 6 1 3))))))))
    334     (let* ((components (extract-modeline-components
    335                         (lisp-string-from-nsstring
    336                          (send textstring
    337                                :substring-with-range modelinerange))))
    338            (package-component (assoc :PACKAGE components)))
    339       (if package-component
    340         (destructuring-bind (start . end) (cdr package-component)
    341           (setf (pref selrange :<NSR>ange.location)
    342                 (+ start (pref modelinerange :<NSR>ange.location))
    343                 (pref selrange :<NSR>ange.length)
    344                 (- end start)))
    345         (setf (pref selrange :<NSR>ange.location)
    346               (pref modelinerange :<NSR>ange.location)
    347               (pref selrange :<NSR>ange.length)
    348               0))
    349       (send tv :set-selected-range selrange)
    350       (send tv :scroll-range-to-visible selrange)
    351       (send tv 'display))))
    352   self)
    353 
    354 ;;; Interrupt/abort something.  When that means something ...
    355 (define-objc-method ((:id :interrupt tv) lisp-editor-window-controller)
    356   (declare (ignore tv))
    357   self)
    358 
    359 
    360 (define-objc-method ((:id :eval-defun tv)
    361                      lisp-editor-window-controller)
    362   (rlet ((workrange :<NSR>ange))
    363     (let* ((textbuf (send tv 'string))
    364            (textlen (send textbuf 'length)))
    365       (slet ((defunrange (send tv 'selected-range)))
    366         (let* ((pointpos (pref defunrange :<NSR>ange.location)))
    367           (if (> (pref defunrange :<NSR>ange.length) 0)
    368             (progn
    369               (setf (pref workrange :<NSR>ange.location)
    370                     (pref defunrange :<NSR>ange.location)
    371                     (pref workrange :<NSR>ange.length)
    372                     (pref defunrange :<NSR>ange.length))
    373               (multiple-value-bind (ok non-wsp)
    374                   (balanced-expressions-in-range-forward workrange textbuf)
    375                 (unless (and ok non-wsp)
    376                   (setf (pref defunrange :<NSR>ange.length) 0))))
    377             (let* ((defun-start (previous-start-of-defun textbuf pointpos)))
    378               (when defun-start
    379                 (setf (pref workrange :<NSR>ange.location) defun-start
    380                       (pref workrange :<NSR>ange.length) (- textlen defun-start))
    381                 (if (forward-over-list workrange textbuf)
    382                   (setf (pref defunrange :<NSR>ange.location)
    383                         defun-start
    384                         (pref defunrange :<NSR>ange.length)
    385                         (- (1+ (pref workrange :<NSR>ange.location))
    386                            defun-start))
    387                   (setf (pref defunrange :<NSR>ange.length)
    388                         0)))))
    389           (if (and (> (pref defunrange :<NSR>ange.length) 0)
    390                    #|(> pointpos (+ (pref defunrange :<NSR>ange.location)
    391                                   (pref defunrange :<NSR>ange.length)))|#)
    392             (send-to-top-listener
    393              (info-from-controller self)
    394              (send textbuf :substring-with-range defunrange))
    395             (#_NSBeep))))))
    396   self)
    397 
    398 
    399 ;;; Also a delegate method
    400 (define-objc-method ((:<BOOL> :text-view tv
    401                               :do-command-by-selector (:<SEL> selector))
    402                      lisp-editor-window-controller)
    403   (with-slots (history-count prev-history-count) self
    404     (setq prev-history-count history-count
    405           history-count 0))
    406   (if (not (send self :responds-to-selector selector))
    407     #$NO
    408     (progn
    409       (send self :perform-selector selector :with-object tv)
    410       #$YES)))
    41186
    41287
     
    41590
    41691(defclass lisp-editor-document (ns:ns-document)
    417   ((text-view :foreign-type :id)
    418    (filedata :foreign-type :id)
    419    (packagename :foreign-type :id)
    420    (echoarea :foreign-type :id))
     92    ((textstorage :foreign-type :id))
    42193  (:metaclass ns:+ns-object))
    42294
    423 (define-objc-method ((:id window-nib-name) lisp-editor-document)
    424   #@"lispeditor")
     95(define-objc-method ((:id init) lisp-editor-document)
     96  (let* ((doc (send-super 'init)))
     97    (setf (slot-value doc 'textstorage)
     98          (make-textstorage-for-hemlock-buffer
     99           (hemlock-buffer-from-nsstring
     100            #@""
     101            (lisp-string-from-nsstring (send doc 'display-name))
     102            "Lisp")))
     103    doc))
     104                     
    425105
    426106(define-objc-method ((:void make-window-controllers) lisp-editor-document)
    427107  (let* ((controller (make-objc-instance
    428108                      'lisp-editor-window-controller
    429                       :with-window-nib-name (send self 'window-nib-name)
    430                       :owner self)))
     109                      :with-window (%hemlock-frame-for-textstorage
     110                                    (slot-value self 'textstorage) nil nil))))
    431111    (send self :add-window-controller controller)
    432112    (send controller 'release)))
    433113
     114(define-objc-method ((:<BOOL> :load-data-representation data :of-type type)
     115                     lisp-editor-document)
     116    (declare (ignorable data type))
     117  (let* ((nsstring
     118  nil)
     119 
    434120
    435121(define-objc-method ((:id :data-representation-of-type ((* :char) type))
     
    441127
    442128         
    443 (define-objc-method ((:<BOOL> :load-data-representation data
    444                               :of-type type)
    445                      lisp-editor-document)
    446   (declare (ignorable type))
    447   (setf (slot-value self 'filedata) data)
    448   (not (%null-ptr-p data)))
    449129
     130#|
    450131(define-objc-method ((:void :window-controller-did-load-nib acontroller)
    451132                     lisp-editor-document)
     
    488169                            :with-data filedata
    489170                            :encoding #$NSASCIIStringEncoding))
    490         (send acontroller :reparse-modeline text-view)))))
     171))))
     172|#
    491173
    492174(define-objc-method ((:void close) lisp-editor-document)
     
    502184              (delete info *open-editor-documents*))))))
    503185
    504 ;;; Syntax utilities
    505 
    506 ;;; If range is non-empty, return the current char without affecting range.
    507 (defun current-char-in-range (rangeptr textbuf)
    508   (let* ((width (pref rangeptr :<NSR>ange.length)))
    509     (declare (ingeger width))
    510     (if (zerop width)
    511       nil
    512       (code-char
    513        (send textbuf
    514              :character-at-index (pref rangeptr :<NSR>ange.location))))))
    515 
    516 (defun next-char-in-range (rangeptr textbuf)
    517   (let* ((width (pref rangeptr :<NSR>ange.length)))
    518     (declare (integer width))
    519     (unless (zerop width)
    520       (setf (pref rangeptr :<NSR>ange.length) (1- width)
    521             (pref rangeptr :<NSR>ange.location)
    522             (1+ (pref rangeptr :<NSR>ange.location)))
    523       (current-char-in-range rangeptr textbuf))))
    524 
    525 ;;; Try to extend the range backward, unless its location is
    526 ;;; already at (or below) limit.
    527 (defun prev-char-in-range (rangeptr textbuf &optional (limit 0))
    528   (let* ((pos (pref rangeptr :<NSR>ange.location)))
    529     (when (> pos limit)
    530       (setf (pref rangeptr :<NSR>ange.location)
    531             (1- (pref rangeptr :<NSR>ange.location))
    532             (pref rangeptr :<NSR>ange.length)
    533             (1+ (pref rangeptr :<NSR>ange.length)))
    534       (current-char-in-range rangeptr textbuf))))
    535 
    536 (defun forward-over-#-comment (rangeptr textbuf)
    537   ;; We've just read a "#|" : the range points to the |.  Return
    538   ;; T if the number of open #| comments reaches 0 (with the range
    539   ;; pointing to the outermost closing #), NIL if we hit EOF first.
    540   (do* ((count 1)
    541         (pending-open nil)
    542         (pending-close nil))
    543        ((zerop count) t)
    544     (declare (fixnum count))            ; Pretty unlikely not to be.
    545     (case (next-char-in-range rangeptr textbuf)
    546       ((nil) (return))
    547       (#\| (if pending-open
    548              (progn (incf count) (setq pending-open nil))
    549              (setq pending-close t)))
    550       (#\# (if pending-close
    551              (progn (decf count) (setq pending-close nil))
    552              (setq pending-open t))))))
    553 
    554 (defun backward-over-#-comment (rangeptr textbuf &optional (limit 0))
    555   ;; We've just read a trailing "|#" : the range points to the |.  Return
    556   ;; T if the number of open #| comments reaches 0 (with the range
    557   ;; pointing to the outermost closing #), NIL if we hit EOF first.
    558   (do* ((count 1)
    559         (pending-open nil)
    560         (pending-close nil))
    561        ((zerop count) t)
    562     (declare (fixnum count))            ; Pretty unlikely not to be.
    563     (case (prev-char-in-range rangeptr textbuf limit)
    564       ((nil) (return))
    565       (#\| (if pending-open
    566              (progn (incf count) (setq pending-open nil))
    567              (setq pending-close t)))
    568       (#\# (if pending-close
    569              (progn (decf count) (setq pending-close nil))
    570              (setq pending-open t))))))
    571 
    572 (defun forward-until-match (rangeptr textbuf matchchar)
    573   (do* ((ch (next-char-in-range rangeptr textbuf)
    574             (next-char-in-range rangeptr textbuf)))
    575        ((eql ch matchchar) t)
    576     (when (null ch)
    577       (return nil))))
    578 
    579 ;;; Range points to #\; .  Win if we find a newline before EOF; leave
    580 ;;; range pointing to newline on success.
    581 (defun forward-over-semi-comment (rangeptr textbuf)
    582   (forward-until-match rangeptr textbuf #\Newline))
    583 
    584 ;;; (Harder to find semi-comments backward ...)
    585 
    586 ;;; Range points to #\|; find match & leave range pointing there.
    587 (defun forward-over-multi-escape (rangeptr textbuf)
    588   (forward-until-match rangeptr textbuf #\|))
    589 
    590 ;;; Advance over a string.  The range points to a leading (unescaped)
    591 ;;; #\".  If we find a trailing unescaped #\", return T with the
    592 ;;; range pointing to it, else return NIL.
    593 (defun forward-over-string (rangeptr textbuf)
    594   (do* ((ch (next-char-in-range rangeptr textbuf)
    595             (next-char-in-range rangeptr textbuf)))
    596        ((null ch))
    597     (if (eql ch #\")
    598       (return t)
    599       (if (eql ch #\\)
    600         (when (null (next-char-in-range rangeptr textbuf))
    601           (return nil))))))
    602 
    603 ;;; The range points to the trailing unescaped #\".  Back up until
    604 ;;; we find a matching unescaped #\".  (We have to back up an extra
    605 ;;; char, then move forward if the extra char wasn't a #\\.)  Return
    606 ;;; T (with the range pointing at the leading #\"), else NIL.
    607 (defun backward-over-string (rangeptr textbuf &optional (limit 0))
    608   (do* ((ch (prev-char-in-range rangeptr textbuf limit)
    609             (prev-char-in-range rangeptr textbuf limit)))
    610        ((null ch) nil)
    611     (when (eql ch #\")
    612       (setq ch (prev-char-in-range rangeptr textbuf limit))
    613       (if (null ch)
    614         (return)
    615         (unless (eql ch #\\)
    616           (next-char-in-range rangeptr textbuf)
    617           (return t))))))
    618 
    619 ;;; Point the range to the first non-whitespace character.
    620 (defun forward-skip-whitespace (rangeptr textbuf)
    621   (do* ((ch (current-char-in-range rangeptr textbuf)
    622             (next-char-in-range rangeptr textbuf)))
    623        ((null ch))
    624     (unless (whitespacep ch)
    625       (return t))))
    626 
    627 ;;; Range points to list-open character (e.g., open-paren.)  Return
    628 ;;; T if we can advance so that range points to list-close char,
    629 ;;; seeing nothing but balanced expressions along the way.
    630 (defun forward-over-list (rangeptr textbuf &optional (close #\)))
    631   (loop
    632       (let* ((ch (next-char-in-range rangeptr textbuf)))
    633         (if (eql ch close)
    634           (return t)
    635           (case ch
    636             ((nil #\) #\] #\}) (return nil))
    637             ;; I suppose that this could be made non-recursive.
    638             ;; Anything nested more than a dozen or two levels
    639             ;; deep probably means that the cat fell asleep
    640             ;; on the keyboard ...
    641             (#\( (unless (forward-over-list rangeptr textbuf #\))
    642                  (return nil)))
    643             (#\[ (unless (forward-over-list rangeptr textbuf #\])
    644                    (return nil)))
    645             (#\{ (unless (forward-over-list rangeptr textbuf #\})
    646                    (return nil)))
    647 
    648             (#\# (setq ch (next-char-in-range rangeptr textbuf))
    649                  (if (or (null ch)
    650                          (and (eql ch #\|)
    651                               (not (forward-over-#-comment rangeptr textbuf))))
    652                    (return nil)))
    653             (#\" (unless (forward-over-string rangeptr textbuf)
    654                    (return nil)))
    655             (#\| (unless (forward-over-multi-escape rangeptr textbuf))
    656                  (return nil))
    657             (#\\ (if (null (next-char-in-range rangeptr textbuf))
    658                    (return nil)))
    659             (#\; (unless (forward-over-semi-comment rangeptr textbuf)
    660                    (return nil))))))))
    661 
    662 ;;; Return (values T T) if all expressions in range are properly
    663 ;;; balanced and something other than semantic whitespace was
    664 ;;; seen, else return (values T NIL) if all expressions are
    665 ;;; balanced, else return (values NIL NIL) if some expression
    666 ;;; is unterminated but nothing's prematurely terminated, else
    667 ;;; return (values NIL T)
    668 (defun balanced-expressions-in-range-forward (rangeptr textbuf)
    669   (do* ((ch (current-char-in-range rangeptr textbuf)
    670             (next-char-in-range rangeptr textbuf))
    671         (seen-something-interesting nil))
    672        ((null ch) (return (values t seen-something-interesting)))
    673     (case ch
    674       ((#\) #\] #\}) (return (values nil t)))
    675       (#\( (if (forward-over-list rangeptr textbuf #\))
    676              (setq seen-something-interesting t)
    677              (return (values nil nil))))
    678       (#\[ (if (forward-over-list rangeptr textbuf #\])
    679              (setq seen-something-interesting t)
    680              (return (values nil nil))))
    681       (#\{ (if (forward-over-list rangeptr textbuf #\})
    682              (setq seen-something-interesting t)
    683              (return (values nil nil))))
    684       (#\" (if (forward-over-string rangeptr textbuf)
    685              (setq seen-something-interesting t)
    686              (return (values nil nil))))
    687       (#\| (if (forward-over-multi-escape rangeptr textbuf)
    688              (setq seen-something-interesting t)
    689              (return (values nil nil))))
    690       (#\; (unless (forward-over-semi-comment rangeptr textbuf)
    691              (return (values nil nil))))
    692       (#\# (let* ((nextch (next-char-in-range rangeptr textbuf)))
    693              (if (null nextch)
    694                (return (values nil nil))
    695                (if (eql nextch #\|)
    696                  (unless (forward-over-#-comment rangeptr textbuf)
    697                    (return (values nil nil)))))))
    698       (t
    699        (unless seen-something-interesting
    700          (unless (whitespacep ch)
    701            (setq seen-something-interesting t)))))))
    702  
    703 (defun previous-start-of-defun (textbuf startpos)
    704   (rlet ((linerange :<NSR>ange)
    705          (posrange :<NSR>ange :length 0))
    706     (do* ((pos startpos (1- (pref linerange :<NSR>ange.location))))
    707          ((< pos 0))
    708       (setf (pref posrange :<NSR>ange.location) pos)
    709       (send/stret linerange textbuf :line-range-for-range posrange)
    710       (if (eql (current-char-in-range linerange textbuf) #\()
    711         (return (pref linerange :<NSR>ange.location))))))
    712186
    713187(provide "COCOA-EDITOR")
  • trunk/ccl/examples/cocoa-listener.lisp

    r430 r568  
    2222         (type list *open-editor-documents*))
    2323
     24#-hemlock
     25(progn
    2426(defun new-listener-process (procname input-fd output-fd)
    2527  (make-mcl-listener-process
     
    335337
    336338
    337 (defloadvar *cocoa-listener-count* 0)
     339(defloadvar *cocoa-listener-count* 17)
    338340
    339341(define-objc-method ((:void :window-controller-did-load-nib acontroller)
     
    389391
    390392
     393); #-hemlock
  • trunk/ccl/examples/cocoa-window.lisp

    r541 r568  
    267267                                                  #'cocoa-startup)
    268268                                                 (toplevel)))))
     269
     270(defparameter *default-font-name* "Courier")
     271(defparameter *default-font-size* 12.0e0)
     272
     273   
     274;;; Try to find the specified font.  If it doesn't exist (or isn't
     275;;; fixed-pitch), try to find a fixed-pitch font of the indicated size.
     276(defun default-font (&key (name *default-font-name*)
     277                          (size *default-font-size*))
     278  (setq size (float size 0.0f0))
     279  (with-cstrs ((name name))
     280    (with-autorelease-pool
     281        (rletz ((matrix (:array :float 6)))
     282          (setf (%get-single-float matrix 0) size
     283                (%get-single-float matrix 12) size)
     284          (let* ((fontname (send (@class ns-string) :string-with-c-string name))
     285                 (font (send (@class ns-font)
     286                                  :font-with-name fontname :matrix matrix)))
     287            (if (or (%null-ptr-p font)
     288                    (and
     289                     (not (send font 'is-fixed-pitch))
     290                     (not (eql #$YES (objc-message-send font "_isFakeFixedPitch" :<BOOL>)))))
     291              (setq font (send (@class ns-font)
     292                               :user-fixed-pitch-font-of-size size)))
     293            font)))))
     294
     295(defparameter *tab-width* 8)
     296
     297;;; Create a paragraph style, mostly so that we can set tabs reasonably.
     298(defun create-paragraph-style (font line-break-mode)
     299  (let* ((p (make-objc-instance 'ns-mutable-paragraph-style))
     300         (charwidth (send (send font 'screen-font)
     301                          :width-of-string #@" ")))
     302    (send p
     303          :set-line-break-mode
     304          (ecase line-break-mode
     305            (:char #$NSLineBreakByCharWrapping)
     306            (:word #$NSLineBreakByWordWrapping)
     307            ;; This doesn't seem to work too well.
     308            ((nil) #$NSLineBreakByClipping)))
     309    ;; Clear existing tab stops.
     310    (send p :set-tab-stops (send (@class ns-array) 'array))
     311    (do* ((i 1 (1+ i)))
     312         ((= i 100) p)
     313      (let* ((tabstop (make-objc-instance
     314                       'ns-text-tab
     315                       :with-type #$NSLeftTabStopType
     316                       :location  (* (* i *tab-width*)
     317                                        charwidth))))
     318        (send p :add-tab-stop tabstop)
     319        (send tabstop 'release)))))
     320   
     321(defun create-text-attributes (&key (font (default-font))
     322                                    (line-break-mode :char)
     323                                    (color nil))
     324  (let* ((dict (make-objc-instance
     325                'ns-mutable-dictionary
     326                :with-capacity (if color 3 2))))
     327    (send dict 'retain)
     328    (send dict
     329          :set-object (create-paragraph-style font line-break-mode)
     330          :for-key #@"NSParagraphStyle")
     331    (send dict :set-object font :for-key #@"NSFont")
     332    (when color
     333      (send dict :set-object color :for-key #@"NSColor"))
     334    dict))
  • trunk/ccl/examples/hemlock-textstorage.lisp

    r566 r568  
    261261                            :font (default-font
    262262                                      :name "Courier New Bold Italic"
    263                                       :size 9.0)))
     263                                      :size 10.0)))
    264264
    265265(defun buffer-for-modeline-view (mv)
     
    364364
    365365   
    366 (defun make-scrolling-text-view-for-buffer (buffer x y width height)
     366(defun make-scrolling-text-view-for-textstorage (textstorage x y width height)
    367367  (slet ((contentrect (ns-make-rect x y width height)))
    368     (let* ((textstorage (make-textstorage-for-hemlock-buffer buffer))
    369            (scrollview (send (make-objc-instance
     368    (let* ((scrollview (send (make-objc-instance
    370369                              'modeline-scroll-view
    371370                              :with-frame contentrect) 'autorelease)))
     
    413412
    414413
    415 (defun make-scrolling-textview-for-pane (pane buffer)
     414(defun make-scrolling-textview-for-pane (pane textstorage)
    416415  (slet ((contentrect (send (send pane 'content-view) 'frame)))
    417416    (multiple-value-bind (tv scrollview)
    418         (make-scrolling-text-view-for-buffer
    419          buffer
     417        (make-scrolling-text-view-for-textstorage
     418         textstorage
    420419         (pref contentrect :<NSR>ect.origin.x)
    421420         (pref contentrect :<NSR>ect.origin.y)
     
    470469  (send w :make-key-and-order-front nil))
    471470
    472 (defun new-hemlock-document-window (title &key
    473                                           (x 0.0)
    474                                           (y 0.0)
    475                                           (height 200.0)
    476                                           (width 500.0)
    477                                           (closable t)
    478                                           (iconifyable t)
    479                                           (metal t)
    480                                           (expandable t)
    481                                           (backing :buffered)
    482                                           (defer nil)
    483                                           (accepts-mouse-moved-events nil)
    484                                           (auto-display t)
    485                                           (activate t))
     471(defun new-hemlock-document-window (&key
     472                                    (x 0.0)
     473                                    (y 0.0)
     474                                    (height 200.0)
     475                                    (width 500.0)
     476                                    (closable t)
     477                                    (iconifyable t)
     478                                    (metal t)
     479                                    (expandable t)
     480                                    (backing :buffered)
     481                                    (defer nil)
     482                                    (accepts-mouse-moved-events nil)
     483                                    (auto-display t)
     484                                    (activate t))
    486485  (rlet ((frame :<NSR>ect :origin.x (float x) :origin.y (float y) :size.width (float width) :size.height (float height)))
    487486    (let* ((stylemask
     
    502501               :backing backing-type
    503502               :defer defer)))
    504       (send w :set-title (%make-nsstring title))
    505503      (setf (get-cocoa-window-flag w :accepts-mouse-moved-events)
    506504            accepts-mouse-moved-events
     
    523521                                       
    524522                                     
    525 (defun textview-for-hemlock-buffer (b)
    526   (process-interrupt
    527    *cocoa-event-process*
    528    #'(lambda ()
    529       (let* ((name (hi::buffer-name b)))
    530         (multiple-value-bind (window pane)
    531             (new-hemlock-document-window name :activate nil)
    532           (let* ((tv (make-scrolling-textview-for-pane pane b)))
    533             (multiple-value-bind (height width)
    534                 (size-of-char-in-font (default-font))
    535               (size-textview-containers tv height width 24 80))
    536             (activate-window window)
    537             tv))))))
     523(defun textpane-for-textstorage (ts)
     524  (let* ((pane (nth-value
     525                1
     526                (new-hemlock-document-window :activate nil)))
     527         (tv (make-scrolling-textview-for-pane pane ts)))
     528    (multiple-value-bind (height width)
     529        (size-of-char-in-font (default-font))
     530      (size-textview-containers tv height width 24 80))
     531    pane))
    538532
    539533
     
    541535  (hemlock::find-file-buffer path))
    542536
    543 (defun hemlock-buffer-from-nsstring (nsstring name)
    544   (let* ((buffer (hi::make-buffer name)))
     537(defun hemlock-buffer-from-nsstring (nsstring name &rest modes)
     538  (let* ((buffer (hi::make-buffer name :modes modes)))
    545539    (hi::delete-region (hi::buffer-region buffer))
    546540    (hi::modifying-buffer buffer)
     
    584578                      (setq previous line))))
    585579                (setq line-start (pref line-end-index :unsigned))))))))
     580    (setf (hi::buffer-modified buffer) nil)
    586581    buffer))
    587582
     
    590585                              (#_NSBeep)))
    591586
     587;;; This function must run in the main event thread.
     588(defun %hemlock-frame-for-textstorage (ts title activate)
     589  (let* ((pane (textpane-for-textstorage ts))
     590         (w (send pane 'window)))
     591    (when title (send w :set-title (%make-nsstring title)))
     592    (when activate (activate-window w))
     593    w))
     594
     595(defun hemlock-frame-for-textstorage (ts title activate)
     596  (process-interrupt *cocoa-event-process*
     597                     #'%hemlock-frame-for-textstorage
     598                     ts title activate))
     599 
     600
    592601(defun edit (path)
    593   (textview-for-hemlock-buffer (read-file-to-hemlock-buffer path)))
     602  (let* ((buffer (read-file-to-hemlock-buffer path))
     603         (textstorage (make-textstorage-for-hemlock-buffer buffer)))
     604    (hemlock-frame-for-textstorage textstorage (hi::buffer-name buffer) t)))
    594605
    595606(defun for-each-textview-using-storage (textstorage f)
Note: See TracChangeset for help on using the changeset viewer.