Changeset 8428

Show
Ignore:
Timestamp:
02/05/08 17:01:48 (4 years ago)
Author:
gz
Message:

Merge of the 'event-ide' branch. Hemlock's thread model has been changed
so that Hemlock commands now run in the Cocoa event thread -- see the
Hemlock file view.lisp for an overview.

IDE compilation has also been reorganized. Hemlock is now more fully
integrated into the IDE and cannot be compiled separately, sorry.

The hemlock-ext package has been repurposed to contain all interfaces
to window-system specific functionality.

There are also many many assorted other changes, cleanups and fixes.

The Hemlock documentation (Hemlock Command Implementor's Manual) in
 http://trac.clozure.com/openmcl/wiki now correctly reflects the
implementation, although it doesn't (yet) describe the integration
with Cocoa or the threading model.

Location:
trunk/source/cocoa-ide
Files:
5 removed
52 modified
5 copied

Legend:

Unmodified
Added
Removed
  • trunk/source/cocoa-ide/cocoa-editor.lisp

    r7804 r8428  
    2626 
    2727(def-cocoa-default *use-screen-fonts* :bool t "Use bitmap screen fonts when available") 
     28 
     29 
     30(defgeneric hemlock-view (ns-object)) 
     31 
     32(defmethod hemlock-view ((unknown t)) 
     33  nil) 
     34 
     35(defgeneric hemlock-buffer (ns-object)) 
     36 
     37(defmethod hemlock-buffer ((unknown t)) 
     38  (let ((view (hemlock-view unknown))) 
     39    (when view (hi::hemlock-view-buffer view)))) 
    2840 
    2941(defmacro nsstring-encoding-to-nsinteger (n) 
     
    145157    buf)) 
    146158 
    147 ;;; Define some key event modifiers. 
    148  
    149 ;;; HEMLOCK-EXT::DEFINE-CLX-MODIFIER is kind of misnamed; we can use 
    150 ;;; it to map NSEvent modifier keys to key-event modifiers. 
    151  
    152 (hemlock-ext::define-clx-modifier #$NSShiftKeyMask "Shift") 
    153 (hemlock-ext::define-clx-modifier #$NSControlKeyMask "Control") 
    154 (hemlock-ext::define-clx-modifier #$NSAlternateKeyMask "Meta") 
    155 (hemlock-ext::define-clx-modifier #$NSAlphaShiftKeyMask "Lock") 
     159;;; Define some key event modifiers and keysym codes 
     160 
     161(hi:define-modifier-bit #$NSShiftKeyMask "Shift") 
     162(hi:define-modifier-bit #$NSControlKeyMask "Control") 
     163(hi:define-modifier-bit #$NSAlternateKeyMask "Meta") 
     164(hi:define-modifier-bit #$NSAlphaShiftKeyMask "Lock") 
     165 
     166(hi:define-keysym-code :F1 #$NSF1FunctionKey) 
     167(hi:define-keysym-code :F2 #$NSF2FunctionKey) 
     168(hi:define-keysym-code :F3 #$NSF3FunctionKey) 
     169(hi:define-keysym-code :F4 #$NSF4FunctionKey) 
     170(hi:define-keysym-code :F5 #$NSF5FunctionKey) 
     171(hi:define-keysym-code :F6 #$NSF6FunctionKey) 
     172(hi:define-keysym-code :F7 #$NSF7FunctionKey) 
     173(hi:define-keysym-code :F8 #$NSF8FunctionKey) 
     174(hi:define-keysym-code :F9 #$NSF9FunctionKey) 
     175(hi:define-keysym-code :F10 #$NSF10FunctionKey) 
     176(hi:define-keysym-code :F11 #$NSF11FunctionKey) 
     177(hi:define-keysym-code :F12 #$NSF12FunctionKey) 
     178(hi:define-keysym-code :F13 #$NSF13FunctionKey) 
     179(hi:define-keysym-code :F14 #$NSF14FunctionKey) 
     180(hi:define-keysym-code :F15 #$NSF15FunctionKey) 
     181(hi:define-keysym-code :F16 #$NSF16FunctionKey) 
     182(hi:define-keysym-code :F17 #$NSF17FunctionKey) 
     183(hi:define-keysym-code :F18 #$NSF18FunctionKey) 
     184(hi:define-keysym-code :F19 #$NSF19FunctionKey) 
     185(hi:define-keysym-code :F20 #$NSF20FunctionKey) 
     186(hi:define-keysym-code :F21 #$NSF21FunctionKey) 
     187(hi:define-keysym-code :F22 #$NSF22FunctionKey) 
     188(hi:define-keysym-code :F23 #$NSF23FunctionKey) 
     189(hi:define-keysym-code :F24 #$NSF24FunctionKey) 
     190(hi:define-keysym-code :F25 #$NSF25FunctionKey) 
     191(hi:define-keysym-code :F26 #$NSF26FunctionKey) 
     192(hi:define-keysym-code :F27 #$NSF27FunctionKey) 
     193(hi:define-keysym-code :F28 #$NSF28FunctionKey) 
     194(hi:define-keysym-code :F29 #$NSF29FunctionKey) 
     195(hi:define-keysym-code :F30 #$NSF30FunctionKey) 
     196(hi:define-keysym-code :F31 #$NSF31FunctionKey) 
     197(hi:define-keysym-code :F32 #$NSF32FunctionKey) 
     198(hi:define-keysym-code :F33 #$NSF33FunctionKey) 
     199(hi:define-keysym-code :F34 #$NSF34FunctionKey) 
     200(hi:define-keysym-code :F35 #$NSF35FunctionKey) 
     201 
     202;;; Upper right key bank. 
     203;;; 
     204(hi:define-keysym-code :Printscreen #$NSPrintScreenFunctionKey) 
     205;; Couldn't type scroll lock. 
     206(hi:define-keysym-code :Pause #$NSPauseFunctionKey) 
     207 
     208;;; Middle right key bank. 
     209;;; 
     210(hi:define-keysym-code :Insert #$NSInsertFunctionKey) 
     211(hi:define-keysym-code :Del #$NSDeleteFunctionKey) 
     212(hi:define-keysym-code :Home #$NSHomeFunctionKey) 
     213(hi:define-keysym-code :Pageup #$NSPageUpFunctionKey) 
     214(hi:define-keysym-code :End #$NSEndFunctionKey) 
     215(hi:define-keysym-code :Pagedown #$NSPageDownFunctionKey) 
     216 
     217;;; Arrows. 
     218;;; 
     219(hi:define-keysym-code :Leftarrow #$NSLeftArrowFunctionKey) 
     220(hi:define-keysym-code :Uparrow #$NSUpArrowFunctionKey) 
     221(hi:define-keysym-code :Downarrow #$NSDownArrowFunctionKey) 
     222(hi:define-keysym-code :Rightarrow #$NSRightArrowFunctionKey) 
     223 
     224;;; 
     225 
     226;(hi:define-keysym-code :linefeed 65290) 
     227 
     228 
     229 
    156230 
    157231 
     
    195269  (:metaclass ns:+ns-object)) 
    196270 
     271(defmethod hemlock-buffer ((self hemlock-buffer-string)) 
     272  (let ((cache (hemlock-buffer-string-cache self))) 
     273    (when cache 
     274      (hemlock-buffer cache)))) 
     275 
    197276;;; Cocoa wants to treat the buffer as a linear array of characters; 
    198277;;; Hemlock wants to treat it as a doubly-linked list of lines, so 
     
    215294  workline-start-font-index             ; current font index at start of workline 
    216295  ) 
     296 
     297(defmethod hemlock-buffer ((self buffer-cache)) 
     298  (buffer-cache-buffer self)) 
    217299 
    218300;;; Initialize (or reinitialize) a buffer cache, so that it points 
     
    303385;;; offset on the appropriate line. 
    304386(defun move-hemlock-mark-to-absolute-position (mark cache abspos) 
     387  ;; TODO: figure out if updating the cache matters, and if not, use hi:move-to-absolute-position. 
    305388  (let* ((hi::*current-buffer* (buffer-cache-buffer cache))) 
    306389    (multiple-value-bind (line idx) (update-line-cache-for-index cache abspos) 
    307390      #+debug 
    308391      (#_NSLog #@"Moving point from current pos %d to absolute position %d" 
    309                :int (mark-absolute-position mark) 
     392               :int (hi:mark-absolute-position mark) 
    310393               :int abspos) 
    311394      (hemlock::move-to-position mark idx line) 
    312395      #+debug 
    313       (#_NSLog #@"Moved mark to %d" :int (mark-absolute-position mark))))) 
    314  
    315 ;;; Return the absolute position of the mark in the containing buffer. 
    316 ;;; This doesn't use the caching mechanism, so it's always linear in the 
    317 ;;; number of preceding lines. 
    318 (defun mark-absolute-position (mark) 
    319   (let* ((hi::*current-buffer* (hi::line-%buffer (hi::mark-line mark))) 
    320          (pos (hi::mark-charpos mark))) 
    321     (+ (hi::get-line-origin (hi::mark-line mark)) pos))) 
     396      (#_NSLog #@"Moved mark to %d" :int (hi:mark-absolute-position mark))))) 
    322397 
    323398;;; Return the length of the abstract string, i.e., the number of 
     
    427502(declaim (special hemlock-text-storage)) 
    428503 
     504(defmethod hemlock-buffer ((self hemlock-text-storage)) 
     505  (let ((string (slot-value self 'hemlock-string))) 
     506    (unless (%null-ptr-p string) 
     507      (hemlock-buffer string)))) 
    429508 
    430509;;; This is only here so that calls to it can be logged for debugging. 
     
    451530 
    452531(defmethod assume-not-editing ((ts hemlock-text-storage)) 
    453   #+debug (assert (eql (slot-value ts 'edit-count) 0))) 
     532  #+debug NIL (assert (eql (slot-value ts 'edit-count) 0))) 
    454533 
    455534(defun textstorage-note-insertion-at-position (self pos n) 
     
    469548  (assume-cocoa-thread) 
    470549  (let* ((mirror (#/mirror self)) 
    471         (hemlock-string (#/hemlockString self)) 
     550        (hemlock-string (#/hemlockString self)) 
    472551         (display (hemlock-buffer-string-cache hemlock-string)) 
    473552         (buffer (buffer-cache-buffer display)) 
    474553         (hi::*current-buffer* buffer) 
    475          (font (buffer-active-font buffer)) 
     554         (attributes (buffer-active-font-attributes buffer)) 
    476555         (document (#/document self)) 
    477556         (undo-mgr (and document (#/undoManager document)))) 
     
    490569         (#/prepareWithInvocationTarget: undo-mgr self) 
    491570         pos n #@""))) 
    492     (#/setAttributes:range: mirror font (ns:make-ns-range pos n))     
     571    (#/setAttributes:range: mirror attributes (ns:make-ns-range pos n)) 
    493572    (textstorage-note-insertion-at-position self pos n))) 
    494573 
     
    654733  (with-slots (mirror styles) self 
    655734    (when (>= index (#/length mirror)) 
    656       (#_NSLog #@"Attributes at index: %lu  edit-count: %d mirror: %@ layout: %@" :<NSUI>nteger index ::unsigned (slot-value self 'edit-count) :id mirror :id (#/objectAtIndex: (#/layoutManagers self) 0)) 
    657       (for-each-textview-using-storage self 
    658                                        (lambda (tv) 
    659                                          (let* ((w (#/window tv)) 
    660                                                 (proc (slot-value w 'command-thread))) 
    661                                            (process-interrupt proc #'ccl::dbg)))) 
     735      (#_NSLog #@"Bounds error - Attributes at index: %lu  edit-count: %d mirror: %@ layout: %@" :<NSUI>nteger index ::unsigned (slot-value self 'edit-count) :id mirror :id (#/objectAtIndex: (#/layoutManagers self) 0)) 
    662736      (ccl::dbg)) 
    663737    (let* ((attrs (#/attributesAtIndex:effectiveRange: mirror index rangeptr))) 
     
    683757      (#/replaceCharactersInRange:withString: self r string)))) 
    684758 
     759;; In theory (though not yet in practice) we allow for a buffer to be shown in multiple 
     760;; windows, and any change to a buffer through one window has to be reflected in all of 
     761;; them.  Once hemlock really supports multiple views of a buffer, it will have some 
     762;; mechanims to ensure that. 
     763;; In Cocoa, we get some messages for the buffer (i.e. the document or the textstorage) 
     764;; with no reference to a view.  There used to be code here that tried to do special- 
     765;; case stuff for all views on the buffer, but that's not necessary, because as long 
     766;; as hemlock doesn't support it, there will only be one view, and as soon as hemlock 
     767;; does support it, will take care of updating all other views.  So all we need is to 
     768;; get our hands on one of the views and do whatever it is through it. 
     769(defun front-view-for-buffer (buffer) 
     770  (loop 
     771     with win-arr =  (#/orderedWindows *NSApp*) 
     772     for i from 0 below (#/count win-arr) as w = (#/objectAtIndex: win-arr i) 
     773     thereis (and (eq (hemlock-buffer w) buffer) (hemlock-view w)))) 
     774 
    685775(objc:defmethod (#/replaceCharactersInRange:withString: :void) 
    686776    ((self hemlock-text-storage) (r :<NSR>ange) string) 
    687   #+debug (#_NSLog #@"Replace in range %ld/%ld with %@" 
    688                     :<NSI>nteger (pref r :<NSR>ange.location) 
    689                     :<NSI>nteger (pref r :<NSR>ange.length) 
    690                     :id string) 
    691   (let* ((cache (hemlock-buffer-string-cache (#/hemlockString  self))) 
    692          (buffer (if cache (buffer-cache-buffer cache))) 
    693          (hi::*current-buffer* buffer) 
    694          (location (pref r :<NSR>ange.location)) 
     777  (let* ((buffer (hemlock-buffer self)) 
     778         (position (pref r :<NSR>ange.location)) 
    695779         (length (pref r :<NSR>ange.length)) 
    696          (point (hi::buffer-point buffer))) 
    697     (let* ((lisp-string (if (> (#/length string) 0) (lisp-string-from-nsstring string))) 
    698            (document (if buffer (hi::buffer-document buffer))) 
    699            (textstorage (if document (slot-value document 'textstorage)))) 
    700       #+gz (unless (eql textstorage self) (break "why is self.ne.textstorage?")) 
    701       (when textstorage 
    702         (assume-cocoa-thread) 
    703         (#/beginEditing textstorage)) 
    704       (setf (hi::buffer-region-active buffer) nil) 
    705       (hi::with-mark ((start point :right-inserting)) 
    706         (move-hemlock-mark-to-absolute-position start cache location) 
    707         (unless (zerop length) 
    708           (hi::delete-characters start length)) 
    709         (when lisp-string 
    710           (hi::insert-string start lisp-string))) 
    711       (when textstorage 
    712         (#/endEditing textstorage) 
    713         (for-each-textview-using-storage 
    714          textstorage 
    715          (lambda (tv) 
    716            (hi::disable-self-insert 
    717             (hemlock-frame-event-queue (#/window tv))))) 
    718         (#/ensureSelectionVisible textstorage))))) 
    719  
     780         (lisp-string (if (> (#/length string) 0) (lisp-string-from-nsstring string))) 
     781         (view (front-view-for-buffer buffer))) 
     782    (when view 
     783      (hi::handle-hemlock-event view #'(lambda () 
     784                                         (hi:paste-characters position length 
     785                                                              lisp-string)))))) 
    720786 
    721787(objc:defmethod (#/setAttributes:range: :void) ((self hemlock-text-storage) 
     
    744810(objc:defmethod #/description ((self hemlock-text-storage)) 
    745811  (#/stringWithFormat: ns:ns-string #@"%s : string %@" (#_object_getClassName self) (slot-value self 'hemlock-string))) 
    746  
    747 ;;; This needs to happen on the main thread. 
    748 (objc:defmethod (#/ensureSelectionVisible :void) ((self hemlock-text-storage)) 
    749   (assume-cocoa-thread) 
    750   (for-each-textview-using-storage 
    751    self 
    752    #'(lambda (tv) 
    753        (assume-not-editing tv) 
    754        (#/scrollRangeToVisible: tv (#/selectedRange tv))))) 
    755  
    756812 
    757813(defun close-hemlock-textstorage (ts) 
     
    770826                (slot-value hemlock-string 'cache) nil 
    771827                (hi::buffer-document buffer) nil) 
    772           (let* ((p (hi::buffer-process buffer))) 
    773             (when p 
    774               (setf (hi::buffer-process buffer) nil) 
    775               (process-kill p))) 
    776828          (when (eq buffer hi::*current-buffer*) 
    777             (setf (hi::current-buffer) 
    778                   (car (last hi::*buffer-list*)))) 
    779           (hi::invoke-hook (hi::buffer-delete-hook buffer) buffer) 
    780           (hi::invoke-hook hemlock::delete-buffer-hook buffer) 
    781           (setq hi::*buffer-list* (delq buffer hi::*buffer-list*)) 
    782          (hi::delete-string (hi::buffer-name buffer) hi::*buffer-names*)))))) 
     829            (setf hi::*current-buffer* nil)) 
     830          (hi::delete-buffer buffer)))))) 
    783831 
    784832 
     
    808856(declaim (special hemlock-textstorage-text-view)) 
    809857 
     858(defmethod hemlock-view ((self hemlock-textstorage-text-view)) 
     859  (let ((frame (#/window self))) 
     860    (unless (%null-ptr-p frame) 
     861      (hemlock-view frame)))) 
     862 
     863(defmethod activate-hemlock-view ((self hemlock-textstorage-text-view)) 
     864  (assume-cocoa-thread) 
     865  (let* ((the-hemlock-frame (#/window self))) 
     866    #+debug (log-debug "Activating ~s" self) 
     867    (with-slots ((echo peer)) self 
     868      (deactivate-hemlock-view echo)) 
     869    (#/setEditable: self t) 
     870    (#/makeFirstResponder: the-hemlock-frame self))) 
     871 
     872(defmethod deactivate-hemlock-view ((self hemlock-textstorage-text-view)) 
     873  (assume-cocoa-thread) 
     874  #+debug (log-debug "deactivating ~s" self) 
     875  (assume-not-editing self) 
     876  (#/setSelectable: self nil)) 
     877 
     878(defmethod eventqueue-abort-pending-p ((self hemlock-textstorage-text-view)) 
     879  ;; Return true if cmd-. is in the queue.  Not sure what to do about c-g: 
     880  ;; would have to distinguish c-g from c-q c-g or c-q c-q c-g etc.... Maybe 
     881  ;; c-g will need to be synchronous meaning just end current command, 
     882  ;; while cmd-. is the real abort. 
     883  #| 
     884   (let* ((now (#/dateWithTimeIntervalSinceNow: ns:ns-date 0.0d0))) 
     885    (loop (let* ((event (#/nextEventMatchingMask:untilDate:inMode:dequeue: 
     886                         target (logior #$whatever) now #&NSDefaultRunLoopMode t))) 
     887            (when (%null-ptr-p event) (return))))) 
     888  "target" can either be an NSWindow or the global shared application object; 
     889  |# 
     890  nil) 
     891 
     892(defvar *buffer-being-edited* nil) 
     893 
     894(objc:defmethod (#/keyDown: :void) ((self hemlock-textstorage-text-view) event) 
     895  #+debug (#_NSLog #@"Key down event = %@" :address event) 
     896  (let* ((view (hemlock-view self)) 
     897         ;; quote-p means handle characters natively 
     898         (quote-p (and view (hi::hemlock-view-quote-next-p view)))) 
     899    #+GZ (log-debug "~&quote-p ~s event ~s" quote-p event) 
     900    (if (or (null view) 
     901            (#/hasMarkedText self) 
     902            (and quote-p (zerop (#/length (#/characters event))))) ;; dead key, e.g. option-E 
     903      (call-next-method event) 
     904      (unless (eventqueue-abort-pending-p self) 
     905        (let ((hemlock-key (nsevent-to-key-event event quote-p))) 
     906          (when hemlock-key 
     907            (hi::handle-hemlock-event view hemlock-key))))))) 
     908 
     909(defmethod hi::handle-hemlock-event :around ((view hi:hemlock-view) event) 
     910  (declare (ignore event)) 
     911  (with-autorelease-pool 
     912   (call-next-method))) 
     913 
     914(defconstant +shift-event-mask+ (hi:key-event-modifier-mask "Shift")) 
     915 
     916;;; Translate a keyDown NSEvent to a Hemlock key-event. 
     917(defun nsevent-to-key-event (event quote-p) 
     918  (let* ((modifiers (#/modifierFlags event))) 
     919    (unless (logtest #$NSCommandKeyMask modifiers) 
     920      (let* ((chars (if quote-p 
     921                      (#/characters event) 
     922                      (#/charactersIgnoringModifiers event))) 
     923             (n (if (%null-ptr-p chars) 
     924                  0 
     925                  (#/length chars))) 
     926             (c (and (eql n 1) 
     927                     (#/characterAtIndex: chars 0)))) 
     928        (when c 
     929          (let* ((bits 0) 
     930                 (useful-modifiers (logandc2 modifiers 
     931                                             (logior 
     932                                              ;#$NSShiftKeyMask 
     933                                              #$NSAlphaShiftKeyMask)))) 
     934            (unless quote-p 
     935              (dolist (map hi:*modifier-translations*) 
     936                (when (logtest useful-modifiers (car map)) 
     937                  (setq bits (logior bits 
     938                                     (hi:key-event-modifier-mask (cdr map))))))) 
     939            (let* ((char (code-char c))) 
     940              (when (and char (standard-char-p char)) 
     941                (setq bits (logandc2 bits +shift-event-mask+)))) 
     942            (hi:make-key-event c bits))))))) 
     943 
     944;; For now, this is only used to abort i-search.  All actual mouse handling is done 
     945;; by Cocoa.   In the future might want to allow users to extend via hemlock, e.g. 
     946;; to implement mouse-copy. 
     947;; Also -- shouldn't this happen on mouse up? 
     948(objc:defmethod (#/mouseDown: :void) ((self hemlock-textstorage-text-view) event) 
     949  ;; If no modifier keys are pressed, send hemlock a no-op. 
     950  ;; (Or almost a no-op - this does an update-hemlock-selection as a side-effect) 
     951  (unless (logtest #$NSDeviceIndependentModifierFlagsMask (#/modifierFlags event)) 
     952    (let* ((view (hemlock-view self))) 
     953      (when view 
     954        (unless (eventqueue-abort-pending-p self) 
     955          (hi::handle-hemlock-event view #k"leftdown"))))) 
     956  (call-next-method event)) 
     957 
     958#+GZ 
     959(objc:defmethod  (#/mouseUp: :void) ((self hemlock-textstorage-text-view) event) 
     960  (log-debug "~&MOUSE UP!!") 
     961  (call-next-method event)) 
    810962 
    811963(defmethod assume-not-editing ((tv hemlock-textstorage-text-view)) 
     
    8911043(defmethod update-blink ((self hemlock-textstorage-text-view)) 
    8921044  (disable-blink self) 
    893   (let* ((d (hemlock-buffer-string-cache (#/hemlockString (#/textStorage self)))) 
    894          (buffer (buffer-cache-buffer d))) 
     1045  (let* ((buffer (hemlock-buffer self))) 
    8951046    (when (and buffer (string= (hi::buffer-major-mode buffer) "Lisp")) 
    8961047      (let* ((hi::*current-buffer* buffer) 
     
    9051056                     #+debug (#_NSLog #@"enable blink, forward") 
    9061057                     (setf (text-view-blink-location self) 
    907                            (1- (mark-absolute-position temp)) 
     1058                           (1- (hi:mark-absolute-position temp)) 
    9081059                           (text-view-blink-enabled self) #$YES))))) 
    9091060              ((eql (hi::previous-character point) #\)) 
     
    9141065                     #+debug (#_NSLog #@"enable blink, backward") 
    9151066                     (setf (text-view-blink-location self) 
    916                            (mark-absolute-position temp) 
     1067                           (hi:mark-absolute-position temp) 
    9171068                           (text-view-blink-enabled self) #$YES)))))))))) 
    9181069 
     
    9391090                                 nil) 
    9401091    (assume-not-editing self) 
    941     (#/scrollRangeToVisible: self range) 
    9421092    (when (> length 0) 
    9431093      (let* ((ts (#/textStorage self))) 
     
    9631113    ((pane :foreign-type :id :accessor text-view-pane) 
    9641114     (char-width :foreign-type :<CGF>loat :accessor text-view-char-width) 
    965      (char-height :foreign-type :<CGF>loat :accessor text-view-char-height)) 
     1115     (line-height :foreign-type :<CGF>loat :accessor text-view-line-height)) 
    9661116  (:metaclass ns:+ns-object)) 
     1117(declaim (special hemlock-text-view)) 
     1118 
     1119(defmethod hemlock-view ((self hemlock-text-view)) 
     1120  (let ((pane (text-view-pane self))) 
     1121    (when pane (hemlock-view pane)))) 
    9671122 
    9681123(objc:defmethod (#/evalSelection: :void) ((self hemlock-text-view) sender) 
    9691124  (declare (ignore sender)) 
    970   (let* ((dc (#/sharedDocumentController ns:ns-document-controller)) 
    971          (doc (#/documentForWindow: dc (#/window self))) 
    972          (buffer (hemlock-document-buffer doc)) 
     1125  (let* ((buffer (hemlock-buffer self)) 
    9731126         (package-name (hi::variable-value 'hemlock::current-package :buffer buffer)) 
    9741127         (pathname (hi::buffer-pathname buffer)) 
     
    9831136(objc:defmethod (#/loadBuffer: :void) ((self hemlock-text-view) sender) 
    9841137  (declare (ignore sender)) 
    985   (let* ((dc (#/sharedDocumentController ns:ns-document-controller)) 
    986          (doc (#/documentForWindow: dc (#/window self))) 
    987          (buffer (hemlock-document-buffer doc)) 
     1138  (let* ((buffer (hemlock-buffer self)) 
    9881139         (package-name (hi::variable-value 'hemlock::current-package :buffer buffer)) 
    9891140         (pathname (hi::buffer-pathname buffer))) 
     
    9921143(objc:defmethod (#/compileBuffer: :void) ((self hemlock-text-view) sender) 
    9931144  (declare (ignore sender)) 
    994   (let* ((dc (#/sharedDocumentController ns:ns-document-controller)) 
    995          (doc (#/documentForWindow: dc (#/window self))) 
    996          (buffer (hemlock-document-buffer doc)) 
     1145  (let* ((buffer (hemlock-buffer self)) 
    9971146         (package-name (hi::variable-value 'hemlock::current-package :buffer buffer)) 
    9981147         (pathname (hi::buffer-pathname buffer))) 
     
    10011150(objc:defmethod (#/compileAndLoadBuffer: :void) ((self hemlock-text-view) sender) 
    10021151  (declare (ignore sender)) 
    1003   (let* ((dc (#/sharedDocumentController ns:ns-document-controller)) 
    1004          (doc (#/documentForWindow: dc (#/window self))) 
    1005          (buffer (hemlock-document-buffer doc)) 
     1152  (let* ((buffer (hemlock-buffer self)) 
    10061153         (package-name (hi::variable-value 'hemlock::current-package :buffer buffer)) 
    10071154         (pathname (hi::buffer-pathname buffer))) 
     
    11051252 
    11061253 
    1107  
    1108 ;;; Access the underlying buffer in one swell foop. 
    1109 (defmethod text-view-buffer ((self hemlock-textstorage-text-view)) 
    1110   (buffer-cache-buffer (hemlock-buffer-string-cache (#/hemlockString (#/textStorage self))))) 
    1111  
    1112  
    1113  
     1254(defmethod text-view-string-cache ((self hemlock-textstorage-text-view)) 
     1255  (hemlock-buffer-string-cache (#/hemlockString (#/textStorage self)))) 
    11141256 
    11151257(objc:defmethod (#/selectionRangeForProposedRange:granularity: :ns-range) 
     
    11371279                            (hi::with-mark ((m2 m1)) 
    11381280                              (when (hemlock::list-offset m2 1) 
    1139                                 (ns:init-ns-range r index (- (mark-absolute-position m2) index)) 
     1281                                (ns:init-ns-range r index (- (hi:mark-absolute-position m2) index)) 
    11401282                                (return-from HANDLED r)))) 
    11411283                           ((eql (hi::previous-character m1) #\)) 
    11421284                            (hi::with-mark ((m2 m1)) 
    11431285                              (when (hemlock::list-offset m2 -1) 
    1144                                 (ns:init-ns-range r (mark-absolute-position m2) (- index (mark-absolute-position m2))) 
     1286                                (ns:init-ns-range r (hi:mark-absolute-position m2) (- index (hi:mark-absolute-position m2))) 
    11451287                                (return-from HANDLED r)))))))))))) 
    11461288       (call-next-method proposed g) 
     
    11531295 
    11541296 
    1155    
    1156  
    1157  
    1158 ;;; Translate a keyDown NSEvent to a Hemlock key-event. 
    1159 (defun nsevent-to-key-event (nsevent &optional quoted) 
    1160   (let* ((modifiers (#/modifierFlags nsevent))) 
    1161     (unless (logtest #$NSCommandKeyMask modifiers) 
    1162       (let* ((chars (if quoted 
    1163                       (#/characters nsevent) 
    1164                       (#/charactersIgnoringModifiers nsevent))) 
    1165              (n (if (%null-ptr-p chars) 
    1166                   0 
    1167                   (#/length chars))) 
    1168              (c (if (eql n 1) 
    1169                   (#/characterAtIndex: chars 0)))) 
    1170         (when c 
    1171           (let* ((bits 0) 
    1172                  (useful-modifiers (logandc2 modifiers 
    1173                                              (logior ;#$NSShiftKeyMask 
    1174                                                      #$NSAlphaShiftKeyMask)))) 
    1175             (unless quoted 
    1176               (dolist (map hemlock-ext::*modifier-translations*) 
    1177                 (when (logtest useful-modifiers (car map)) 
    1178                   (setq bits (logior bits (hemlock-ext::key-event-modifier-mask 
    1179                                          (cdr map))))))) 
    1180             (let* ((char (code-char c))) 
    1181               (when (and char (standard-char-p char)) 
    1182                 (setq bits (logandc2 bits hi::+shift-event-mask+)))) 
    1183             (hemlock-ext::make-key-event c bits))))))) 
    1184  
    1185 (defun pass-key-down-event-to-hemlock (self event q) 
    1186   #+debug 
    1187   (#_NSLog #@"Key down event = %@" :address event) 
    1188   (let* ((buffer (text-view-buffer self))) 
    1189     (when buffer 
    1190       (let* ((hemlock-event (nsevent-to-key-event event (hi::frame-event-queue-quoted-insert q )))) 
    1191         (when hemlock-event 
    1192           (hi::enqueue-key-event q hemlock-event)))))) 
    1193  
    1194 (defun hi::enqueue-buffer-operation (buffer thunk) 
    1195   (dolist (w (hi::buffer-windows buffer)) 
    1196     (let* ((q (hemlock-frame-event-queue (#/window w))) 
    1197            (op (hi::make-buffer-operation :thunk thunk))) 
    1198       (hi::event-queue-insert q op)))) 
    1199  
    1200  
    1201  
    1202 ;;; Process a key-down NSEvent in a Hemlock text view by translating it 
    1203 ;;; into a Hemlock key event and passing it into the Hemlock command 
    1204 ;;; interpreter.  
    1205  
    1206 (defun handle-key-down (self event) 
    1207   (let* ((q (hemlock-frame-event-queue (#/window self)))) 
    1208     (if (or (and (zerop (#/length (#/characters event))) 
    1209                  (hi::frame-event-queue-quoted-insert q)) 
    1210             (#/hasMarkedText self)) 
    1211       nil 
    1212       (progn 
    1213         (pass-key-down-event-to-hemlock self event q) 
    1214         t)))) 
    1215    
    1216  
    1217 (objc:defmethod (#/keyDown: :void) ((self hemlock-text-view) event) 
    1218   (or (handle-key-down self event) 
    1219       (call-next-method event))) 
    1220  
    1221 (objc:defmethod (#/mouseDown: :void) ((self hemlock-text-view) event) 
    1222   ;; If no modifier keys are pressed, send hemlock a no-op. 
    1223   (unless (logtest #$NSDeviceIndependentModifierFlagsMask (#/modifierFlags event)) 
    1224     (let* ((q (hemlock-frame-event-queue (#/window self)))) 
    1225       (hi::enqueue-key-event q #k"leftdown"))) 
    1226   (call-next-method event)) 
     1297(defun append-output (view string) 
     1298  (assume-cocoa-thread) 
     1299  ;; Arrange to do the append in command context 
     1300  (when view 
     1301    (hi::handle-hemlock-event view #'(lambda () 
     1302                                       (hemlock::append-buffer-output (hi::hemlock-view-buffer view) string))))) 
     1303 
    12271304 
    12281305;;; Update the underlying buffer's point (and "active region", if appropriate. 
     
    12821359             ;; In all cases, activate Hemlock selection. 
    12831360             (unless still-selecting 
    1284                 (let* ((pointpos (mark-absolute-position point)) 
     1361                (let* ((pointpos (hi:mark-absolute-position point)) 
    12851362                       (selection-end (+ location len)) 
    12861363                       (mark (hi::copy-mark point :right-inserting))) 
     
    13641441      (let* ((tv (text-pane-text-view pane))) 
    13651442        (unless (%null-ptr-p tv) 
    1366           (text-view-buffer tv)))))) 
     1443          (hemlock-buffer tv)))))) 
    13671444 
    13681445;;; Draw a string in the modeline view.  The font and other attributes 
     
    13711448;;; used in the event dispatch mechanism, 
    13721449(defun draw-modeline-string (the-modeline-view) 
    1373   (with-slots (pane text-attributes) the-modeline-view 
     1450  (with-slots (text-attributes) the-modeline-view 
    13741451    (let* ((buffer (buffer-for-modeline-view the-modeline-view))) 
    13751452      (when buffer 
     
    13781455                       (mapcar 
    13791456                        #'(lambda (field) 
    1380                             (funcall (hi::modeline-field-function field) 
    1381                                      buffer pane)) 
     1457                            (funcall (hi::modeline-field-function field) buffer)) 
    13821458                        (hi::buffer-modeline-fields buffer))))) 
    13831459          (#/drawAtPoint:withAttributes: (%make-nsstring string) 
     
    14741550 
    14751551(defclass text-pane (ns:ns-box) 
    1476     ((text-view :foreign-type :id :accessor text-pane-text-view) 
     1552    ((hemlock-view :initform nil :reader text-pane-hemlock-view) 
     1553     (text-view :foreign-type :id :accessor text-pane-text-view) 
    14771554     (mode-line :foreign-type :id :accessor text-pane-mode-line) 
    14781555     (scroll-view :foreign-type :id :accessor text-pane-scroll-view)) 
    14791556  (:metaclass ns:+ns-object)) 
    14801557 
    1481 ;;; Mark the pane's modeline as needing display.  This is called whenever 
     1558(defmethod hemlock-view ((self text-pane)) 
     1559  (text-pane-hemlock-view self)) 
     1560 
     1561;;; Mark the buffer's modeline as needing display.  This is called whenever 
    14821562;;; "interesting" attributes of a buffer are changed. 
    1483  
    1484 (defun hi::invalidate-modeline (pane) 
    1485   (#/setNeedsDisplay: (text-pane-mode-line pane) t)) 
     1563(defun hemlock-ext:invalidate-modeline (buffer) 
     1564  (let* ((doc (hi::buffer-document buffer))) 
     1565    (when doc 
     1566      (document-invalidate-modeline doc)))) 
    14861567 
    14871568(def-cocoa-default *text-pane-margin-width* :float 0.0f0 "width of indented margin around text pane") 
     
    15961677      tv))) 
    15971678 
    1598  
    1599 (objc:defmethod (#/activateHemlockView :void) ((self text-pane)) 
    1600   (let* ((the-hemlock-frame (#/window self)) 
    1601          (text-view (text-pane-text-view self))) 
    1602     #+debug (#_NSLog #@"Activating text pane") 
    1603     (with-slots ((echo peer)) text-view 
    1604       (deactivate-hemlock-view echo)) 
    1605     (#/setEditable: text-view t) 
    1606     (#/makeFirstResponder: the-hemlock-frame text-view))) 
    1607  
    1608 (defmethod hi::activate-hemlock-view ((view text-pane)) 
    1609   (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    1610    view 
    1611    (@selector #/activateHemlockView) 
    1612    +null-ptr+ 
    1613    t)) 
    1614  
    1615  
    1616  
    1617 (defmethod deactivate-hemlock-view ((self hemlock-text-view)) 
    1618   #+debug (#_NSLog #@"deactivating text view") 
    1619   (#/setSelectable: self nil)) 
     1679(defmethod hemlock-ext:change-active-pane ((view hi:hemlock-view) new-pane) 
     1680  #+GZ (log-debug "change active pane to ~s" new-pane) 
     1681  (let* ((pane (hi::hemlock-view-pane view)) 
     1682         (text-view (text-pane-text-view pane)) 
     1683         (tv (ecase new-pane 
     1684               (:echo (slot-value text-view 'peer)) 
     1685               (:text text-view)))) 
     1686    (activate-hemlock-view tv))) 
    16201687 
    16211688(defclass echo-area-view (hemlock-textstorage-text-view) 
    16221689    () 
    16231690  (:metaclass ns:+ns-object)) 
    1624  
    1625 (objc:defmethod (#/activateHemlockView :void) ((self echo-area-view)) 
    1626   (assume-cocoa-thread) 
    1627   (let* ((the-hemlock-frame (#/window self))) 
    1628     #+debug 
    1629     (#_NSLog #@"Activating echo area") 
    1630     (with-slots ((pane peer)) self 
    1631       (deactivate-hemlock-view pane)) 
    1632     (#/setEditable: self t) 
    1633   (#/makeFirstResponder: the-hemlock-frame self))) 
    1634  
    1635 (defmethod hi::activate-hemlock-view ((view echo-area-view)) 
    1636   (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    1637    view 
    1638    (@selector #/activateHemlockView) 
    1639    +null-ptr+ 
    1640    t)) 
    1641  
    1642 (defmethod deactivate-hemlock-view ((self echo-area-view)) 
    1643   (assume-cocoa-thread) 
    1644   #+debug (#_NSLog #@"deactivating echo area") 
    1645   (let* ((ts (#/textStorage self))) 
    1646     #+debug 0 
    1647     (when (#/editingInProgress ts) 
    1648       (#_NSLog #@"deactivating %@, edit-count = %d" :id self :int (slot-value ts 'edit-count))) 
    1649     (do* () 
    1650          ((not (#/editingInProgress ts))) 
    1651       (#/endEditing ts)) 
    1652  
    1653     (#/setSelectable: self nil))) 
    1654  
     1691(declaim (special echo-area-view)) 
     1692 
     1693(defmethod hemlock-view ((self echo-area-view)) 
     1694  (let ((text-view (slot-value self 'peer))) 
     1695    (when text-view 
     1696      (hemlock-view text-view)))) 
    16551697 
    16561698;;; The "document" for an echo-area isn't a real NSDocument. 
     
    16591701  (:metaclass ns:+ns-object)) 
    16601702 
     1703(defmethod hemlock-buffer ((self echo-area-document)) 
     1704  (let ((ts (slot-value self 'textstorage))) 
     1705    (unless (%null-ptr-p ts) 
     1706      (hemlock-buffer ts)))) 
     1707 
    16611708(objc:defmethod (#/undoManager :<BOOL>) ((self echo-area-document)) 
    16621709  nil) ;For now, undo is not supported for echo-areas 
     
    16641711(defmethod update-buffer-package ((doc echo-area-document) buffer) 
    16651712  (declare (ignore buffer))) 
     1713 
     1714(defmethod document-invalidate-modeline ((self echo-area-document)) 
     1715  nil) 
    16661716 
    16671717(objc:defmethod (#/close :void) ((self echo-area-document)) 
     
    16711721      (close-hemlock-textstorage ts)))) 
    16721722 
    1673 (objc:defmethod (#/updateChangeCount: :void) 
    1674     ((self echo-area-document) 
    1675      (change :<NSD>ocument<C>hange<T>ype)) 
     1723(objc:defmethod (#/updateChangeCount: :void) ((self echo-area-document) (change :<NSD>ocument<C>hange<T>ype)) 
    16761724  (declare (ignore change))) 
    1677  
    1678 (objc:defmethod (#/documentChangeCleared :void) ((self echo-area-document))) 
    1679  
    1680 (objc:defmethod (#/keyDown: :void) ((self echo-area-view) event) 
    1681   (or (handle-key-down self event) 
    1682       (call-next-method event))) 
    1683  
    1684  
    1685 (defloadvar *hemlock-frame-count* 0) 
    16861725 
    16871726(defun make-echo-area (the-hemlock-frame x y width height main-buffer color) 
     
    16981737      (#/setAutoresizesSubviews: box t) 
    16991738      (#/release clipview) 
    1700       (let* ((buffer (hi:make-buffer (format nil "Echo Area ~d" 
    1701                                              (prog1 
    1702                                                  *hemlock-frame-count* 
    1703                                                (incf *hemlock-frame-count*))) 
    1704                                      :modes '("Echo Area"))) 
     1739      (let* ((buffer (hi::make-echo-buffer)) 
    17051740             (textstorage 
    17061741              (progn 
    17071742                ;; What's the reason for sharing this?  Is it just the lock? 
    1708                 (setf (hi::buffer-gap-context buffer) (hi::buffer-gap-context main-buffer)) 
     1743                (setf (hi::buffer-gap-context buffer) (hi::ensure-buffer-gap-context main-buffer)) 
    17091744                (make-textstorage-for-hemlock-buffer buffer))) 
    17101745             (doc (make-instance 'echo-area-document)) 
     
    17571792    ((echo-area-view :foreign-type :id) 
    17581793     (pane :foreign-type :id) 
    1759      (event-queue :initform (ccl::init-dll-header (hi::make-frame-event-queue)) 
    1760                   :reader hemlock-frame-event-queue) 
    1761      (command-thread :initform nil) 
    17621794     (echo-area-buffer :initform nil :accessor hemlock-frame-echo-area-buffer) 
    17631795     (echo-area-stream :initform nil :accessor hemlock-frame-echo-area-stream)) 
    17641796  (:metaclass ns:+ns-object)) 
    17651797(declaim (special hemlock-frame)) 
     1798 
     1799(defmethod hemlock-view ((self hemlock-frame)) 
     1800  (let ((pane (slot-value self 'pane))) 
     1801    (unless (%null-ptr-p pane) 
     1802      (hemlock-view pane)))) 
    17661803 
    17671804(defun double-%-in (string) 
     
    17741811 
    17751812(defun nsstring-for-lisp-condition (cond) 
    1776   (%make-nsstring (double-%-in (princ-to-string cond)))) 
    1777  
    1778 (objc:defmethod (#/runErrorSheet: :void) ((self hemlock-frame) info) 
    1779   (let* ((message (#/objectAtIndex: info 0)) 
    1780          (signal (#/objectAtIndex: info 1))) 
    1781     #+debug (#_NSLog #@"runErrorSheet: signal = %@" :id signal) 
    1782     (#_NSBeginAlertSheet #@"Error in Hemlock command processing" ;title 
    1783                          (if (logbitp 0 (random 2)) 
    1784                            #@"Not OK, but what can you do?" 
    1785                            #@"The sky is falling. FRED never did this!") 
    1786                          +null-ptr+ 
    1787                          +null-ptr+ 
    1788                          self 
    1789                          self 
    1790                          (@selector #/sheetDidEnd:returnCode:contextInfo:) 
    1791                          (@selector #/sheetDidDismiss:returnCode:contextInfo:) 
    1792                          signal 
    1793                          message))) 
    1794  
    1795 (objc:defmethod (#/sheetDidEnd:returnCode:contextInfo: :void) ((self hemlock-frame)) 
    1796  (declare (ignore sheet code info)) 
    1797   #+debug 
    1798   (#_NSLog #@"Sheet did end")) 
    1799  
    1800 (objc:defmethod (#/sheetDidDismiss:returnCode:contextInfo: :void) 
    1801     ((self hemlock-frame) sheet code info) 
    1802   (declare (ignore sheet code)) 
    1803   #+debug (#_NSLog #@"dismiss sheet: semaphore = %lx" :unsigned-doubleword (#/unsignedLongValue info)) 
    1804   (ccl::%signal-semaphore-ptr (%int-to-ptr (#/unsignedLongValue info)))) 
    1805    
     1813  (%make-nsstring (double-%-in (or (ignore-errors (princ-to-string cond)) 
     1814                                   "#<error printing error message>")))) 
     1815 
     1816(objc:defmethod (#/runErrorSheet: :void) ((self hemlock-frame) message) 
     1817  #+debug (#_NSLog #@"runErrorSheet: signal = %@" :id signal) 
     1818  (#_NSBeginAlertSheet #@"Error in Hemlock command processing" ;title 
     1819                       (if (logbitp 0 (random 2)) 
     1820                         #@"Not OK, but what can you do?" 
     1821                         #@"The sky is falling. FRED never did this!") 
     1822                       +null-ptr+ 
     1823                       +null-ptr+ 
     1824                       self 
     1825                       self 
     1826                       +null-ptr+ 
     1827                       +null-ptr+ 
     1828                       +null-ptr+ 
     1829                       message)) 
     1830 
    18061831(defun report-condition-in-hemlock-frame (condition frame) 
    1807   (let* ((semaphore (make-semaphore)) 
    1808          (message (nsstring-for-lisp-condition condition)) 
    1809          (sem-value (make-instance 'ns:ns-number 
    1810                                    :with-unsigned-long (%ptr-to-int (ccl::semaphore.value semaphore))))) 
    1811     #+debug 
    1812     (#_NSLog #@"created semaphore with value %lx" :address (semaphore.value semaphore)) 
    1813     (rlet ((paramptrs (:array :id 2))) 
    1814       (setf (paref paramptrs (:array :id) 0) message 
    1815             (paref paramptrs (:array :id) 1) sem-value) 
    1816       (let* ((params (make-instance 'ns:ns-array 
    1817                                     :with-objects paramptrs 
    1818                                     :count 2)) 
    1819              #|(*debug-io* *typeout-stream*)|#) 
    1820         (stream-clear-output *debug-io*) 
    1821         (ignore-errors (print-call-history :detailed-p t)) 
    1822         (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    1823          frame (@selector #/runErrorSheet:) params t) 
    1824         (wait-on-semaphore semaphore))))) 
    1825  
    1826 (defun hi::report-hemlock-error (condition) 
    1827   (let ((pane (hi::current-window))) 
     1832  (assume-cocoa-thread) 
     1833  (let ((message (nsstring-for-lisp-condition condition))) 
     1834    (#/performSelectorOnMainThread:withObject:waitUntilDone: 
     1835     frame 
     1836     (@selector #/runErrorSheet:) 
     1837     message 
     1838     t))) 
     1839 
     1840(defmethod hemlock-ext:report-hemlock-error ((view hi:hemlock-view) condition debug-p) 
     1841  (when debug-p (maybe-log-callback-error condition)) 
     1842  (let ((pane (hi::hemlock-view-pane view))) 
    18281843    (when (and pane (not (%null-ptr-p pane))) 
    18291844      (report-condition-in-hemlock-frame condition (#/window pane))))) 
    18301845                        
    1831  
    1832 (defun hemlock-thread-function (q buffer pane echo-buffer echo-window) 
    1833   (let* ((hi::*real-editor-input* q) 
    1834          (hi::*editor-input* q) 
    1835          (hi::*current-buffer* hi::*current-buffer*) 
    1836          (hi::*current-window* pane) 
    1837          (hi::*echo-area-window* echo-window) 
    1838          (hi::*echo-area-buffer* echo-buffer) 
    1839          (region (hi::buffer-region echo-buffer)) 
    1840          (hi::*echo-area-region* region) 
    1841          (hi::*echo-area-stream* (hi::make-hemlock-output-stream 
    1842                               (hi::region-end region) :full)) 
    1843          (hi::*parse-starting-mark* 
    1844           (hi::copy-mark (hi::buffer-point hi::*echo-area-buffer*) 
    1845                          :right-inserting)) 
    1846          (hi::*parse-input-region* 
    1847           (hi::region hi::*parse-starting-mark* 
    1848                       (hi::region-end region))) 
    1849          (hi::*cache-modification-tick* -1) 
    1850          (hi::*disembodied-buffer-counter* 0) 
    1851          (hi::*in-a-recursive-edit* nil) 
    1852          (hi::*last-key-event-typed* nil) 
    1853          (hi::*input-transcript* nil) 
    1854          (hemlock::*target-column* 0) 
    1855          (hemlock::*last-comment-start* " ") 
    1856          (hi::*translate-key-temp* (make-array 10 :fill-pointer 0 :adjustable t)) 
    1857          (hi::*current-command* (make-array 10 :fill-pointer 0 :adjustable t)) 
    1858          (hi::*current-translation* (make-array 10 :fill-pointer 0 :adjustable t)) 
    1859          (hi::*prompt-key* (make-array 10 :adjustable t :fill-pointer 0)) 
    1860          (hi::*command-key-event-buffer* buffer)) 
    1861      
    1862     (setf (hi::current-buffer) buffer) 
    1863     (unwind-protect 
    1864          (loop 
    1865            (catch 'hi::editor-top-level-catcher 
    1866              (handler-bind ((error #'(lambda (condition) 
    1867                                        (hi::lisp-error-error-handler condition 
    1868                                                                      :internal)))) 
    1869                (hi::invoke-hook hemlock::abort-hook) 
    1870                (hi::%command-loop)))) 
    1871       (hi::invoke-hook hemlock::exit-hook)))) 
    1872  
    1873  
    18741846(objc:defmethod (#/close :void) ((self hemlock-frame)) 
    18751847  (let* ((content-view (#/contentView self)) 
     
    18781850         ((< i 0)) 
    18791851      (#/removeFromSuperviewWithoutNeedingDisplay (#/objectAtIndex: subviews i)))) 
    1880   (let* ((proc (slot-value self 'command-thread))) 
    1881     (when proc 
    1882       (setf (slot-value self 'command-thread) nil) 
    1883       (process-kill proc))) 
    18841852  (let* ((buf (hemlock-frame-echo-area-buffer self)) 
    18851853         (echo-doc (if buf (hi::buffer-document buf)))) 
     
    19221890    (nsstring-to-buffer nsstring buffer))) 
    19231891 
    1924 (defun %nsstring-to-mark (nsstring mark) 
     1892(defun %nsstring-to-hemlock-string (nsstring) 
    19251893  "returns line-termination of string" 
    19261894  (let* ((string (lisp-string-from-nsstring nsstring)) 
     
    19291897         (line-termination (if crpos 
    19301898                             (if (eql lfpos (1+ crpos)) 
    1931                                :cp/m 
    1932                                :macos) 
    1933                              :unix))) 
    1934     (hi::insert-string mark 
    1935                            (case line-termination 
    1936                              (:cp/m (remove #\return string)) 
    1937                              (:macos (nsubstitute #\linefeed #\return string)) 
    1938                              (t string))) 
    1939     line-termination)) 
    1940    
     1899                               :crlf 
     1900                               :cr) 
     1901                             :lf)) 
     1902         (hemlock-string (case line-termination 
     1903                           (:crlf (remove #\return string)) 
     1904                           (:cr (nsubstitute #\linefeed #\return string)) 
     1905                           (t string)))) 
     1906    (values hemlock-string line-termination))) 
     1907 
     1908;: TODO: I think this is jumping through hoops because it want to be invokable outside the main 
     1909;; cocoa thread. 
    19411910(defun nsstring-to-buffer (nsstring buffer) 
    19421911  (let* ((document (hi::buffer-document buffer)) 
    19431912         (hi::*current-buffer* buffer) 
    19441913         (region (hi::buffer-region buffer))) 
    1945     (setf (hi::buffer-document buffer) nil) 
    1946     (unwind-protect 
    1947          (progn 
    1948            (hi::delete-region region) 
    1949            (hi::modifying-buffer buffer 
    1950                                  (hi::with-mark ((mark (hi::buffer-point buffer) :left-inserting)) 
    1951                                    (setf (hi::buffer-line-termination buffer) 
    1952                                          (%nsstring-to-mark nsstring mark))) 
    1953                                  (setf (hi::buffer-modified buffer) nil) 
    1954                                  (hi::buffer-start (hi::buffer-point buffer)) 
    1955                                  (hi::renumber-region region) 
    1956                                  buffer)) 
    1957       (setf (hi::buffer-document buffer) document)))) 
    1958  
     1914    (multiple-value-bind (hemlock-string line-termination) 
     1915                         (%nsstring-to-hemlock-string nsstring) 
     1916      (setf (hi::buffer-line-termination buffer) line-termination) 
     1917 
     1918      (setf (hi::buffer-document buffer) nil) ;; What's this about?? 
     1919      (unwind-protect 
     1920          (let ((point (hi::buffer-point buffer))) 
     1921            (hi::delete-region region) 
     1922            (hi::insert-string point hemlock-string) 
     1923            (setf (hi::buffer-modified buffer) nil) 
     1924            (hi::buffer-start point) 
     1925            ;; TODO: why would this be needed? insert-string should take care of any internal bookkeeping. 
     1926            (hi::renumber-region region) 
     1927            buffer) 
     1928        (setf (hi::buffer-document buffer) document))))) 
    19591929 
    19601930 
     
    19681938  (assume-cocoa-thread) 
    19691939  (let* ((pane (textpane-for-textstorage class ts ncols nrows container-tracks-text-view-width color style)) 
     1940         (buffer (hemlock-buffer ts)) 
    19701941         (frame (#/window pane)) 
    1971          (buffer (text-view-buffer (text-pane-text-view pane))) 
    19721942         (echo-area (make-echo-area-for-window frame buffer color)) 
     1943         (echo-buffer (hemlock-buffer (#/textStorage echo-area))) 
    19731944         (tv (text-pane-text-view pane))) 
     1945    #+GZ (assert echo-buffer) 
    19741946    (with-slots (peer) tv 
    19751947      (setq peer echo-area)) 
    19761948    (with-slots (peer) echo-area 
    19771949      (setq peer tv)) 
    1978     (hi::activate-hemlock-view pane) 
    19791950    (setf (slot-value frame 'echo-area-view) echo-area 
    19801951          (slot-value frame 'pane) pane) 
    1981     (setf (slot-value frame 'command-thread) 
    1982           (process-run-function (format nil "Hemlock window thread for ~s" 
    1983                                         (hi::buffer-name buffer)) 
    1984                                 #'(lambda () 
    1985                                     (hemlock-thread-function 
    1986                                      (hemlock-frame-event-queue frame) 
    1987                                      buffer 
    1988                                      pane 
    1989                                      (hemlock-frame-echo-area-buffer frame) 
    1990                                      (slot-value frame 'echo-area-view))))) 
    1991     frame)) 
    1992           
    1993      
    1994  
    1995  
    1996 (defun hemlock-frame-for-textstorage (class ts ncols nrows container-tracks-text-view-width color style) 
    1997   (process-interrupt *cocoa-event-process* 
    1998                      #'%hemlock-frame-for-textstorage 
    1999                      class ts  ncols nrows container-tracks-text-view-width color style)) 
    2000  
     1952    (setf (slot-value pane 'hemlock-view) 
     1953          (make-instance 'hi:hemlock-view 
     1954            :buffer buffer 
     1955            :pane pane 
     1956            :echo-area-buffer echo-buffer)) 
     1957    (activate-hemlock-view tv) 
     1958   frame)) 
    20011959 
    20021960 
     
    20071965  (release-lock (hi::buffer-lock b)))  
    20081966 
    2009 (defun hi::document-begin-editing (document) 
    2010   (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    2011    (slot-value document 'textstorage) 
    2012    (@selector #/beginEditing) 
    2013    +null-ptr+ 
    2014    t)) 
     1967(defun hemlock-ext:invoke-modifying-buffer-storage (buffer thunk) 
     1968  (assume-cocoa-thread) 
     1969  (when buffer ;; nil means just get rid of any prior buffer 
     1970    (setq buffer (require-type buffer 'hi::buffer))) 
     1971  (let ((old *buffer-being-edited*)) 
     1972    (if (eq buffer old) 
     1973      (funcall thunk) 
     1974      (unwind-protect 
     1975          (progn 
     1976            (buffer-document-end-editing old) 
     1977            (buffer-document-begin-editing buffer) 
     1978            (funcall thunk)) 
     1979        (buffer-document-end-editing buffer) 
     1980        (buffer-document-begin-editing old))))) 
     1981 
     1982(defun buffer-document-end-editing (buffer) 
     1983  (when buffer 
     1984    (let* ((document (hi::buffer-document (require-type buffer 'hi::buffer)))) 
     1985      (when document 
     1986        (setq *buffer-being-edited* nil) 
     1987        (let ((ts (slot-value document 'textstorage))) 
     1988          (#/endEditing ts) 
     1989          (update-hemlock-selection ts)))))) 
     1990 
     1991(defun buffer-document-begin-editing (buffer) 
     1992  (when buffer 
     1993    (let* ((document (hi::buffer-document buffer))) 
     1994      (when document 
     1995        (setq *buffer-being-edited* buffer) 
     1996        (#/beginEditing (slot-value document 'textstorage)))))) 
    20151997 
    20161998(defun document-edit-level (document) 
    20171999  (assume-cocoa-thread) ;; see comment in #/editingInProgress 
    20182000  (slot-value (slot-value document 'textstorage) 'edit-count)) 
    2019  
    2020 (defun hi::document-end-editing (document) 
    2021   (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    2022    (slot-value document 'textstorage) 
    2023    (@selector #/endEditing) 
    2024    +null-ptr+ 
    2025    t)) 
    2026  
    2027 (defun hi::document-set-point-position (document) 
    2028   (declare (ignorable document)) 
    2029   #+debug 
    2030   (#_NSLog #@"Document set point position called") 
    2031   (let* ((textstorage (slot-value document 'textstorage))) 
    2032     (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    2033      textstorage (@selector #/updateHemlockSelection) +null-ptr+ t))) 
    2034  
    2035  
    20362001 
    20372002(defun perform-edit-change-notification (textstorage selector pos n &optional (extra 0)) 
     
    20652030    (let* ((document (hi::buffer-document buffer)) 
    20662031           (textstorage (if document (slot-value document 'textstorage))) 
    2067            (pos (mark-absolute-position (hi::region-start region))) 
    2068            (n (- (mark-absolute-position (hi::region-end region)) pos))) 
     2032           (pos (hi:mark-absolute-position (hi::region-start region))) 
     2033           (n (- (hi:mark-absolute-position (hi::region-end region)) pos))) 
    20692034      (perform-edit-change-notification textstorage 
    20702035                                        (@selector #/noteHemlockAttrChangeAtPosition:length:) 
     
    20732038                                        font)))) 
    20742039 
    2075 (defun buffer-active-font (buffer) 
     2040(defun buffer-active-font-attributes (buffer) 
    20762041  (let* ((style 0) 
    20772042         (region (hi::buffer-active-font-region buffer)) 
     
    20902055           (textstorage (if document (slot-value document 'textstorage)))) 
    20912056      (when textstorage 
    2092         (let* ((pos (mark-absolute-position mark))) 
     2057        (let* ((pos (hi:mark-absolute-position mark))) 
    20932058          (when (eq (hi::mark-%kind mark) :left-inserting) 
    20942059            ;; Make up for the fact that the mark moved forward with the insertion. 
     
    21072072            (perform-edit-change-notification textstorage 
    21082073                                              (@selector #/noteHemlockModificationAtPosition:length:) 
    2109                                               (mark-absolute-position mark) 
     2074                                              (hi:mark-absolute-position mark) 
    21102075                                              n))))) 
    21112076   
     
    21162081           (textstorage (if document (slot-value document 'textstorage)))) 
    21172082      (when textstorage 
    2118         (let* ((pos (mark-absolute-position mark))) 
     2083        (let* ((pos (hi:mark-absolute-position mark))) 
    21192084          (perform-edit-change-notification textstorage 
    21202085                                            (@selector #/noteHemlockDeletionAtPosition:length:) 
     
    21242089 
    21252090 
    2126 (defun hi::set-document-modified (document flag) 
    2127   (unless flag 
    2128     (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    2129      document 
    2130      (@selector #/documentChangeCleared) 
    2131      +null-ptr+ 
    2132      t))) 
    2133  
    2134  
    2135 (defmethod hi::document-panes ((document t)) 
    2136   ) 
    2137  
    2138  
    2139  
    2140      
     2091(defun hemlock-ext:note-buffer-saved (buffer) 
     2092  (assume-cocoa-thread) 
     2093  (let* ((document (hi::buffer-document buffer))) 
     2094    (when document 
     2095      ;; Hmm... I guess this is always done by the act of saving. 
     2096      nil))) 
     2097 
     2098(defun hemlock-ext:note-buffer-unsaved (buffer) 
     2099  (assume-cocoa-thread) 
     2100  (let* ((document (hi::buffer-document buffer))) 
     2101    (when document 
     2102      (#/updateChangeCount: document #$NSChangeCleared)))) 
     2103 
    21412104 
    21422105(defun size-of-char-in-font (f) 
     
    21512114 
    21522115 
    2153 (defun size-text-pane (pane char-height char-width nrows ncols) 
     2116(defun size-text-pane (pane line-height char-width nrows ncols) 
    21542117  (let* ((tv (text-pane-text-view pane)) 
    2155          (height (fceiling (* nrows char-height))) 
     2118         (height (fceiling (* nrows line-height))) 
    21562119         (width (fceiling (* ncols char-width))) 
    21572120         (scrollview (text-pane-scroll-view pane)) 
     
    21632126                      height) 
    21642127      (when has-vertical-scroller  
    2165         (#/setVerticalLineScroll: scrollview char-height) 
    2166         (#/setVerticalPageScroll: scrollview (cgfloat 0.0) #|char-height|#)) 
     2128        (#/setVerticalLineScroll: scrollview line-height) 
     2129        (#/setVerticalPageScroll: scrollview (cgfloat 0.0) #|line-height|#)) 
    21672130      (when has-horizontal-scroller 
    21682131        (#/setHorizontalLineScroll: scrollview char-width) 
     
    21782141        (#/setContentSize: window sv-size) 
    21792142        (setf (slot-value tv 'char-width) char-width 
    2180               (slot-value tv 'char-height) char-height) 
     2143              (slot-value tv 'line-height) line-height) 
    21812144        (#/setResizeIncrements: window 
    2182                                 (ns:make-ns-size char-width char-height)))))) 
     2145                                (ns:make-ns-size char-width line-height)))))) 
    21832146                                     
    21842147   
     
    21872150  (:metaclass ns:+ns-object)) 
    21882151 
     2152(defmethod hemlock-view ((self hemlock-editor-window-controller)) 
     2153  (let ((frame (#/window self))) 
     2154    (unless (%null-ptr-p frame) 
     2155      (hemlock-view frame)))) 
    21892156 
    21902157;;; Map *default-file-character-encoding* to an :<NSS>tring<E>ncoding 
     
    22222189  (:metaclass ns:+ns-object)) 
    22232190 
    2224 (objc:defmethod (#/documentChangeCleared :void) ((self hemlock-editor-document)) 
    2225   (#/updateChangeCount: self #$NSChangeCleared)) 
     2191(defmethod hemlock-buffer ((self hemlock-editor-document)) 
     2192  (let ((ts (slot-value self 'textstorage))) 
     2193    (unless (%null-ptr-p ts) 
     2194      (hemlock-buffer ts)))) 
    22262195 
    22272196(defmethod assume-not-editing ((doc hemlock-editor-document)) 
    22282197  (assume-not-editing (slot-value doc 'textstorage))) 
     2198 
     2199(defmethod document-invalidate-modeline ((self hemlock-editor-document)) 
     2200  (for-each-textview-using-storage 
     2201   (slot-value self 'textstorage) 
     2202   #'(lambda (tv) 
     2203       (let* ((pane (text-view-pane tv))) 
     2204         (unless (%null-ptr-p pane) 
     2205           (#/setNeedsDisplay: (text-pane-mode-line pane) t)))))) 
    22292206 
    22302207(defmethod update-buffer-package ((doc hemlock-editor-document) buffer) 
     
    22392216          (setf (hi::variable-value 'hemlock::current-package :buffer buffer) name)))))) 
    22402217 
    2241 (defun hi::document-note-selection-set-by-search (doc) 
    2242   (with-slots (textstorage) doc 
    2243     (when textstorage 
    2244       (with-slots (selection-set-by-search) textstorage 
    2245         (setq selection-set-by-search #$YES))))) 
     2218(defun hemlock-ext:note-selection-set-by-search (buffer) 
     2219  (let* ((doc (hi::buffer-document buffer))) 
     2220    (when doc 
     2221      (with-slots (textstorage) doc 
     2222        (when textstorage 
     2223          (with-slots (selection-set-by-search) textstorage 
     2224            (setq selection-set-by-search #$YES))))))) 
    22462225 
    22472226(objc:defmethod (#/validateMenuItem: :<BOOL>) 
     
    22652244               (eql action (@selector #/compileBuffer:)) 
    22662245               (eql action (@selector #/compileAndLoadBuffer:)))  
    2267            (let* ((d (hemlock-buffer-string-cache (#/hemlockString (#/textStorage self)))) 
    2268                   (buffer (buffer-cache-buffer d)) 
     2246           (let* ((buffer (hemlock-buffer self)) 
    22692247                  (pathname (hi::buffer-pathname buffer))) 
    22702248             (not (null pathname)))) 
     
    22762254(defvar *encoding-name-hash* (make-hash-table)) 
    22772255 
    2278 (defmethod hi::document-encoding-name ((doc hemlock-editor-document)) 
     2256(defmethod document-encoding-name ((doc hemlock-editor-document)) 
    22792257  (with-slots (encoding) doc 
    22802258    (if (eql encoding 0) 
     
    22842262                (lisp-string-from-nsstring (nsstring-for-nsstring-encoding encoding))))))) 
    22852263 
    2286  
     2264(defun hi::buffer-encoding-name (buffer) 
     2265  (let ((doc (hi::buffer-document buffer))) 
     2266    (and doc (document-encoding-name doc)))) 
     2267 
     2268;; TODO: make each buffer have a slot, and this is just the default value. 
    22872269(defmethod textview-background-color ((doc hemlock-editor-document)) 
    22882270  *editor-background-color*) 
     
    23112293                                  :encoding encoding 
    23122294                                  :error +null-ptr+)) 
    2313          (buffer (hemlock-document-buffer self)) 
     2295         (buffer (hemlock-buffer self)) 
    23142296         (old-length (hemlock-buffer-length buffer)) 
    23152297         (hi::*current-buffer* buffer) 
    23162298         (textstorage (slot-value self 'textstorage)) 
    23172299         (point (hi::buffer-point buffer)) 
    2318          (pointpos (mark-absolute-position point))) 
    2319     (#/beginEditing textstorage) 
    2320     (#/edited:range:changeInLength: 
    2321      textstorage #$NSTextStorageEditedCharacters (ns:make-ns-range 0 old-length) (- old-length)) 
    2322     (nsstring-to-buffer nsstring buffer) 
    2323     (let* ((newlen (hemlock-buffer-length buffer))) 
    2324       (#/edited:range:changeInLength: textstorage  #$NSTextStorageEditedAttributes (ns:make-ns-range 0 0) newlen) 
    2325       (#/edited:range:changeInLength: textstorage #$NSTextStorageEditedCharacters (ns:make-ns-range 0 newlen) 0) 
    2326       (let* ((ts-string (#/hemlockString textstorage)) 
    2327              (display (hemlock-buffer-string-cache ts-string))) 
    2328         (reset-buffer-cache display)  
    2329         (update-line-cache-for-index display 0) 
    2330         (move-hemlock-mark-to-absolute-position point 
    2331                                                 display 
    2332                                                 (min newlen pointpos)))) 
    2333     (#/updateMirror textstorage) 
    2334     (#/endEditing textstorage) 
    2335     (hi::document-set-point-position self) 
    2336     (setf (hi::buffer-modified buffer) nil) 
    2337     (hi::queue-buffer-change buffer) 
     2300         (pointpos (hi:mark-absolute-position point))) 
     2301    (hemlock-ext:invoke-modifying-buffer-storage 
     2302     buffer 
     2303     #'(lambda () 
     2304         (#/edited:range:changeInLength: 
     2305          textstorage #$NSTextStorageEditedCharacters (ns:make-ns-range 0 old-length) (- old-length)) 
     2306         (nsstring-to-buffer nsstring buffer) 
     2307         (let* ((newlen (hemlock-buffer-length buffer))) 
     2308           (#/edited:range:changeInLength: textstorage  #$NSTextStorageEditedAttributes (ns:make-ns-range 0 0) newlen) 
     2309           (#/edited:range:changeInLength: textstorage #$NSTextStorageEditedCharacters (ns:make-ns-range 0 newlen) 0) 
     2310           (let* ((ts-string (#/hemlockString textstorage)) 
     2311                  (display (hemlock-buffer-string-cache ts-string))) 
     2312             (reset-buffer-cache display)  
     2313             (update-line-cache-for-index display 0) 
     2314             (move-hemlock-mark-to-absolute-position point 
     2315                                                     display 
     2316                                                     (min newlen pointpos)))) 
     2317         (#/updateMirror textstorage) 
     2318         (setf (hi::buffer-modified buffer) nil) 
     2319         (hi::note-modeline-change buffer))) 
    23382320    t)) 
    2339           
    2340              
    2341    
     2321 
     2322 
     2323(defvar *last-document-created* nil) 
     2324 
    23422325(objc:defmethod #/init ((self hemlock-editor-document)) 
    23432326  (let* ((doc (call-next-method))) 
     
    23482331                                (#/displayName doc)) 
    23492332                               :modes '("Lisp" "Editor"))))) 
     2333    (setq *last-document-created* doc) 
    23502334    doc)) 
    23512335 
    23522336   
     2337(defun make-buffer-for-document (ns-document pathname) 
     2338  (let* ((buffer-name (hi::pathname-to-buffer-name pathname)) 
     2339         (buffer (make-hemlock-buffer buffer-name))) 
     2340    (setf (slot-value ns-document 'textstorage) 
     2341          (make-textstorage-for-hemlock-buffer buffer)) 
     2342    (setf (hi::buffer-pathname buffer) pathname) 
     2343    buffer)) 
     2344 
    23532345(objc:defmethod (#/readFromURL:ofType:error: :<BOOL>) 
    23542346    ((self hemlock-editor-document) url type (perror (:* :id))) 
    23552347  (declare (ignorable type)) 
    2356   (rlet ((pused-encoding :<NSS>tring<E>ncoding 0)) 
    2357     (let* ((pathname 
    2358             (lisp-string-from-nsstring 
    2359              (if (#/isFileURL url) 
    2360                (#/path url) 
    2361                (#/absoluteString url)))) 
    2362            (buffer-name (hi::pathname-to-buffer-name pathname)) 
    2363            (buffer (or 
    2364                     (hemlock-document-buffer self) 
    2365                     (let* ((b (make-hemlock-buffer buffer-name))) 
    2366                       (setf (hi::buffer-pathname b) pathname) 
    2367                       (setf (slot-value self 'textstorage) 
    2368                             (make-textstorage-for-hemlock-buffer b)) 
    2369                       b))) 
    2370            (selected-encoding (slot-value (#/sharedDocumentController (find-class 'hemlock-document-controller)) 'last-encoding)) 
    2371            (string 
     2348  (with-callback-context "readFromURL" 
     2349    (rlet ((pused-encoding :<NSS>tring<E>ncoding 0)) 
     2350      (let* ((pathname 
     2351              (lisp-string-from-nsstring 
     2352               (if (#/isFileURL url) 
     2353                 (#/path url) 
     2354                 (#/absoluteString url)))) 
     2355             (buffer (or (hemlock-buffer self) 
     2356                         (make-buffer-for-document self pathname))) 
     2357             (selected-encoding (slot-value (#/sharedDocumentController (find-class 'hemlock-document-controller)) 'last-encoding)) 
     2358             (string 
     2359              (if (zerop selected-encoding) 
     2360                (#/stringWithContentsOfURL:usedEncoding:error: 
     2361                 ns:ns-string 
     2362                 url 
     2363                 pused-encoding 
     2364                 perror) 
     2365                +null-ptr+))) 
     2366         
     2367        (if (%null-ptr-p string) 
     2368          (progn 
    23722369            (if (zerop selected-encoding) 
    2373               (#/stringWithContentsOfURL:usedEncoding:error: 
    2374                ns:ns-string 
    2375                url 
    2376                pused-encoding 
    2377                perror) 
    2378               +null-ptr+))) 
    2379  
    2380       (if (%null-ptr-p string) 
    2381         (progn 
    2382           (if (zerop selected-encoding) 
    2383             (setq selected-encoding (get-default-encoding))) 
    2384           (setq string (#/stringWithContentsOfURL:encoding:error: 
    2385                         ns:ns-string 
    2386                         url 
    2387                         selected-encoding 
    2388                         perror))) 
    2389         (setq selected-encoding (pref pused-encoding :<NSS>tring<E>ncoding))) 
    2390       (unless (%null-ptr-p string) 
    2391         (with-slots (encoding) self (setq encoding selected-encoding)) 
    2392         (hi::queue-buffer-change buffer) 
    2393         (hi::document-begin-editing self) 
    2394         (nsstring-to-buffer string buffer) 
    2395  
    2396         (let* ((textstorage (slot-value self 'textstorage)) 
    2397                (display (hemlock-buffer-string-cache (#/hemlockString textstorage)))) 
    2398  
    2399           (reset-buffer-cache display)  
    2400  
    2401           (#/updateMirror textstorage) 
    2402  
    2403           (update-line-cache-for-index display 0) 
    2404  
    2405           (textstorage-note-insertion-at-position 
    2406            textstorage 
    2407            0 
    2408            (hemlock-buffer-length buffer))) 
    2409  
    2410         (hi::document-end-editing self) 
    2411  
    2412         (setf (hi::buffer-modified buffer) nil) 
    2413         (hi::process-file-options buffer pathname) 
    2414         t)))) 
    2415  
     2370              (setq selected-encoding (get-default-encoding))) 
     2371            (setq string (#/stringWithContentsOfURL:encoding:error: 
     2372                          ns:ns-string 
     2373                          url 
     2374                          selected-encoding 
     2375                          perror))) 
     2376          (setq selected-encoding (pref pused-encoding :<NSS>tring<E>ncoding))) 
     2377        (unless (%null-ptr-p string) 
     2378          (with-slots (encoding) self (setq encoding selected-encoding)) 
     2379 
     2380          ;; ** TODO: Argh.  How about we just let hemlock insert it. 
     2381          (let* ((textstorage (slot-value self 'textstorage)) 
     2382                 (display (hemlock-buffer-string-cache (#/hemlockString textstorage))) 
     2383                 (hi::*current-buffer* buffer)) 
     2384            (hemlock-ext:invoke-modifying-buffer-storage 
     2385             buffer 
     2386             #'(lambda () 
     2387                 (nsstring-to-buffer string buffer) 
     2388                 (reset-buffer-cache display)  
     2389                 (#/updateMirror textstorage) 
     2390                 (update-line-cache-for-index display 0) 
     2391                 (textstorage-note-insertion-at-position 
     2392                  textstorage 
     2393                  0 
     2394                  (hemlock-buffer-length buffer)) 
     2395                 (hi::note-modeline-change buffer) 
     2396                 (setf (hi::buffer-modified buffer) nil)))) 
     2397          t))))) 
    24162398 
    24172399 
     
    24512433              
    24522434 
    2453 (defmethod hemlock-document-buffer (document) 
    2454   (let* ((string (#/hemlockString (slot-value document 'textstorage)))) 
    2455     (unless (%null-ptr-p string) 
    2456       (let* ((cache (hemlock-buffer-string-cache string))) 
    2457         (when cache (buffer-cache-buffer cache)))))) 
    2458  
    2459 (defmethod hi:window-buffer ((frame hemlock-frame)) 
    2460   (let* ((dc (#/sharedDocumentController ns:ns-document-controller)) 
    2461          (doc (#/documentForWindow: dc frame))) 
    2462     ;; Sometimes doc is null.  Why?  What would cause a hemlock frame to 
    2463     ;; not have a document?  (When it happened, there seemed to be a hemlock 
    2464     ;; frame in (windows) that didn't correspond to any visible window). 
    2465     (unless (%null-ptr-p doc) 
    2466       (hemlock-document-buffer doc)))) 
    2467  
    2468 (defmethod hi:window-buffer ((pane text-pane)) 
    2469   (hi:window-buffer (#/window pane))) 
    2470  
    2471 (defun ordered-hemlock-windows () 
    2472   (delete-if-not #'(lambda (win) 
    2473                      (and (typep win 'hemlock-frame) 
    2474                           (hi:window-buffer win))) 
    2475                    (windows))) 
     2435(defmethod hemlock-view ((frame hemlock-frame)) 
     2436  (let ((pane (slot-value frame 'pane))) 
     2437    (when (and pane (not (%null-ptr-p pane))) 
     2438      (hemlock-view pane)))) 
     2439 
     2440(defun hemlock-ext:all-hemlock-views () 
     2441  "List of all hemlock views, in z-order, frontmost first" 
     2442  (loop for win in (windows) 
     2443    as buf = (and (typep win 'hemlock-frame) (hemlock-view win)) 
     2444    when buf collect buf)) 
    24762445 
    24772446(defmethod hi::document-panes ((document hemlock-editor-document)) 
     
    24902459  (with-slots (encoding) self 
    24912460    (setq encoding (nsinteger-to-nsstring-encoding (#/selectedTag popup))) 
    2492     ;; Force modeline update. 
    2493     (hi::queue-buffer-change (hemlock-document-buffer self)))) 
     2461    (hi::note-modeline-change (hemlock-buffer self)))) 
    24942462 
    24952463(objc:defmethod (#/prepareSavePanel: :<BOOL>) ((self hemlock-editor-document) 
     
    25152483  (with-slots (encoding textstorage) self 
    25162484    (let* ((string (#/string textstorage)) 
    2517            (buffer (hemlock-document-buffer self))) 
     2485           (buffer (hemlock-buffer self))) 
    25182486      (case (when buffer (hi::buffer-line-termination buffer)) 
    2519         (:cp/m (unless (typep string 'ns:ns-mutable-string) 
    2520                 (setq string (make-instance 'ns:ns-mutable-string :with string string)) 
    2521               (#/replaceOccurrencesOfString:withString:options:range: 
    2522                 string *ns-lf-string* *ns-crlf-string* #$NSLiteralSearch (ns:make-ns-range 0 (#/length string))))) 
    2523         (:macos (setq string (if (typep string 'ns:ns-mutable-string) 
    2524                               string 
    2525                               (make-instance 'ns:ns-mutable-string :with string string))) 
    2526                 (#/replaceOccurrencesOfString:withString:options:range: 
    2527                 string *ns-lf-string* *ns-cr-string* #$NSLiteralSearch (ns:make-ns-range 0 (#/length string))))) 
     2487        (:crlf (unless (typep string 'ns:ns-mutable-string) 
     2488                (setq string (make-instance 'ns:ns-mutable-string :with string string)) 
     2489                (#/replaceOccurrencesOfString:withString:options:range: 
     2490                  string *ns-lf-string* *ns-crlf-string* #$NSLiteralSearch (ns:make-ns-range 0 (#/length string))))) 
     2491        (:cr (setq string (if (typep string 'ns:ns-mutable-string) 
     2492                            string 
     2493                            (make-instance 'ns:ns-mutable-string :with string string))) 
     2494             (#/replaceOccurrencesOfString:withString:options:range: 
     2495              string *ns-lf-string* *ns-cr-string* #$NSLiteralSearch (ns:make-ns-range 0 (#/length string))))) 
    25282496      (when (#/writeToURL:atomically:encoding:error: 
    25292497             string url t encoding error) 
     
    25402508                                        url) 
    25412509  (call-next-method url) 
    2542   (let* ((buffer (hemlock-document-buffer self))) 
     2510  (let* ((buffer (hemlock-buffer self))) 
    25432511    (when buffer 
    25442512      (let* ((new-pathname (lisp-string-from-nsstring (#/path url)))) 
     
    25752543  #+debug 
    25762544  (#_NSLog #@"Make window controllers") 
    2577   (let* ((textstorage  (slot-value self 'textstorage)) 
    2578          (window (%hemlock-frame-for-textstorage 
    2579                   hemlock-frame 
    2580                   textstorage 
    2581                   *editor-columns* 
    2582                   *editor-rows* 
    2583                   nil 
    2584                   (textview-background-color self) 
    2585                   (user-input-style self))) 
    2586          (controller (make-instance 
    2587                       'hemlock-editor-window-controller 
    2588                       :with-window window))) 
    2589     (#/setDelegate: (text-pane-text-view (slot-value window 'pane)) self) 
    2590     (#/addWindowController: self controller) 
    2591     (#/release controller) 
    2592     (ns:with-ns-point  (current-point 
    2593                         (or *next-editor-x-pos* 
    2594                             (x-pos-for-window window *initial-editor-x-pos*)) 
    2595                         (or *next-editor-y-pos* 
    2596                             (y-pos-for-window window *initial-editor-y-pos*))) 
    2597       (let* ((new-point (#/cascadeTopLeftFromPoint: window current-point))) 
    2598         (setq *next-editor-x-pos* (ns:ns-point-x new-point) 
    2599               *next-editor-y-pos* (ns:ns-point-y new-point)))))) 
     2545  (with-callback-context "makeWindowControllers" 
     2546    (let* ((textstorage  (slot-value self 'textstorage)) 
     2547           (window (%hemlock-frame-for-textstorage 
     2548                    hemlock-frame 
     2549                    textstorage 
     2550                    *editor-columns* 
     2551                    *editor-rows* 
     2552                    nil 
     2553                    (textview-background-color self) 
     2554                    (user-input-style self))) 
     2555           (controller (make-instance 
     2556                           'hemlock-editor-window-controller 
     2557                         :with-window window))) 
     2558      (#/setDelegate: (text-pane-text-view (slot-value window 'pane)) self) 
     2559      (#/addWindowController: self controller) 
     2560      (#/release controller) 
     2561      (ns:with-ns-point  (current-point 
     2562                          (or *next-editor-x-pos* 
     2563                              (x-pos-for-window window *initial-editor-x-pos*)) 
     2564                          (or *next-editor-y-pos* 
     2565                              (y-pos-for-window window *initial-editor-y-pos*))) 
     2566        (let* ((new-point (#/cascadeTopLeftFromPoint: window current-point))) 
     2567          (setq *next-editor-x-pos* (ns:ns-point-x new-point) 
     2568                *next-editor-y-pos* (ns:ns-point-y new-point)))) 
     2569      (let ((view (hemlock-view window))) 
     2570        (hi::handle-hemlock-event view #'(lambda () 
     2571                                           (hi::process-file-options))))))) 
    26002572 
    26012573 
     
    26142586  (call-next-method)) 
    26152587 
    2616 (defun window-visible-range (text-view) 
    2617   (let* ((rect (#/visibleRect text-view)) 
    2618          (layout (#/layoutManager text-view)) 
    2619          (text-container (#/textContainer text-view)) 
    2620          (container-origin (#/textContainerOrigin text-view))) 
     2588(defmethod view-screen-lines ((view hi:hemlock-view)) 
     2589    (let* ((pane (hi::hemlock-view-pane view))) 
     2590      (floor (ns:ns-size-height (#/contentSize (text-pane-scroll-view pane))) 
     2591             (text-view-line-height (text-pane-text-view pane))))) 
     2592 
     2593;; Beware this doesn't seem to take horizontal scrolling into account. 
     2594(defun visible-charpos-range (tv) 
     2595  (let* ((rect (#/visibleRect tv)) 
     2596         (container-origin (#/textContainerOrigin tv)) 
     2597         (layout (#/layoutManager tv))) 
    26212598    ;; Convert from view coordinates to container coordinates 
    26222599    (decf (pref rect :<NSR>ect.origin.x) (pref container-origin :<NSP>oint.x)) 
    26232600    (decf (pref rect :<NSR>ect.origin.y) (pref container-origin :<NSP>oint.y)) 
    26242601    (let* ((glyph-range (#/glyphRangeForBoundingRect:inTextContainer: 
    2625                          layout rect text-container)) 
    2626            (char-range (#/characterRangeForGlyphRange:actualGlyphRange: 
    2627                         layout glyph-range +null-ptr+))) 
     2602                         layout rect (#/textContainer tv))) 
     2603           (char-range (#/characterRangeForGlyphRange:actualGlyphRange: 
     2604                        layout glyph-range +null-ptr+))) 
    26282605      (values (pref char-range :<NSR>ange.location) 
    2629               (pref char-range :<NSR>ange.length))))) 
    2630      
    2631 (defun hi::scroll-window (textpane n) 
    2632   (when n 
    2633     (let* ((sv (text-pane-scroll-view textpane)) 
    2634            (tv (text-pane-text-view textpane)) 
    2635            (char-height (text-view-char-height tv)) 
    2636            (sv-height (ns:ns-size-height (#/contentSize sv))) 
    2637            (nlines (floor sv-height char-height)) 
    2638            (count (case n 
    2639                     (:page-up (- nlines)) 
    2640                     (:page-down nlines) 
    2641                     (t n)))) 
    2642       (multiple-value-bind (pages lines) (floor (abs count) nlines) 
    2643         (dotimes (i pages) 
    2644           (if (< count 0) 
    2645               (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    2646                tv 
    2647                (@selector #/scrollPageUp:) 
    2648                +null-ptr+ 
    2649                t) 
    2650               (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    2651                tv 
    2652                (@selector #/scrollPageDown:) 
    2653                +null-ptr+ 
    2654                t))) 
    2655         (dotimes (i lines) 
    2656           (if (< count 0) 
    2657               (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    2658                tv 
    2659                (@selector #/scrollLineUp:) 
    2660                +null-ptr+ 
    2661                t) 
    2662               (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    2663                tv 
    2664                (@selector #/scrollLineDown:) 
    2665                +null-ptr+ 
    2666                t)))) 
    2667       ;; If point is not on screen, move it. 
    2668       (let* ((point (hi::current-point)) 
    2669              (point-pos (mark-absolute-position point))) 
    2670         (multiple-value-bind (win-pos win-len) (window-visible-range tv) 
    2671           (unless (and (<= win-pos point-pos) (< point-pos (+ win-pos win-len))) 
    2672             (let* ((point (hi::current-point-collapsing-selection)) 
    2673                    (cache (hemlock-buffer-string-cache 
    2674                            (#/hemlockString (#/textStorage tv))))) 
    2675               (move-hemlock-mark-to-absolute-position point cache win-pos) 
    2676               ;; We should be done, but unfortunately, well, we're not. 
    2677               ;; Something insists on recentering around point, so fake it out 
    2678               #-work-around-overeager-centering 
    2679               (or (hi::line-offset point (floor nlines 2)) 
    2680                   (if (< count 0) 
    2681                       (hi::buffer-start point) 
    2682                       (hi::buffer-end point)))))))))) 
    2683  
    2684  
    2685 (defmethod hemlock::center-text-pane ((pane text-pane)) 
    2686   (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    2687    (text-pane-text-view pane) 
    2688    (@selector #/centerSelectionInVisibleArea:) 
    2689    +null-ptr+ 
    2690    t)) 
    2691  
     2606              (pref char-range :<NSR>ange.length))))) 
     2607 
     2608(defun charpos-xy (tv charpos) 
     2609  (let* ((layout (#/layoutManager tv)) 
     2610         (glyph-range (#/glyphRangeForCharacterRange:actualCharacterRange: 
     2611                       layout 
     2612                       (ns:make-ns-range charpos 0) 
     2613                       +null-ptr+)) 
     2614         (rect (#/boundingRectForGlyphRange:inTextContainer: 
     2615                layout 
     2616                glyph-range 
     2617                (#/textContainer tv))) 
     2618         (container-origin (#/textContainerOrigin tv))) 
     2619    (values (+ (pref rect :<NSR>ect.origin.x) (pref container-origin :<NSP>oint.x)) 
     2620            (+ (pref rect :<NSR>ect.origin.y) (pref container-origin :<NSP>oint.y))))) 
     2621 
     2622;;(nth-value 1 (charpos-xy tv (visible-charpos-range tv))) - this is smaller as it 
     2623;; only includes lines fully scrolled off... 
     2624(defun text-view-vscroll (tv) 
     2625  ;; Return the number of pixels scrolled off the top of the view. 
     2626  (let* ((scroll-view (text-pane-scroll-view (text-view-pane tv))) 
     2627         (clip-view (#/contentView scroll-view)) 
     2628         (bounds (#/bounds clip-view))) 
     2629    (ns:ns-rect-y bounds))) 
     2630 
     2631(defun set-text-view-vscroll (tv vscroll) 
     2632  (let* ((scroll-view (text-pane-scroll-view (text-view-pane tv))) 
     2633         (clip-view (#/contentView scroll-view)) 
     2634         (bounds (#/bounds clip-view))) 
     2635    (decf vscroll (mod vscroll (text-view-line-height tv))) ;; show whole line 
     2636    (ns:with-ns-point (new-origin (ns:ns-rect-x bounds) vscroll) 
     2637      (#/scrollToPoint: clip-view (#/constrainScrollPoint: clip-view new-origin)) 
     2638      (#/reflectScrolledClipView: scroll-view clip-view)))) 
     2639 
     2640(defun scroll-by-lines (tv nlines) 
     2641  "Change the vertical origin of the containing scrollview's clipview" 
     2642  (set-text-view-vscroll tv (+ (text-view-vscroll tv) 
     2643                               (* nlines (text-view-line-height tv))))) 
     2644 
     2645;; TODO: should be a hemlock variable.. 
     2646(defvar *next-screen-context-lines* 2) 
     2647 
     2648(defmethod hemlock-ext:scroll-view ((view hi:hemlock-view) how &optional where) 
     2649  (assume-cocoa-thread) 
     2650  (let* ((tv (text-pane-text-view (hi::hemlock-view-pane view)))) 
     2651    (when (eq how :line) 
     2652      (setq where (require-type where '(integer 0))) 
     2653      (let* ((line-y (nth-value 1 (charpos-xy tv where))) 
     2654             (top-y (text-view-vscroll tv)) 
     2655             (nlines (floor (- line-y top-y) (text-view-line-height tv)))) 
     2656        (setq how :lines-down where nlines))) 
     2657    (ecase how 
     2658      (:center-selection 
     2659       (#/centerSelectionInVisibleArea: tv +null-ptr+)) 
     2660      (:page-up 
     2661       (require-type where 'null) 
     2662       ;; TODO: next-screen-context-lines 
     2663       (scroll-by-lines tv (- *next-screen-context-lines* (view-screen-lines view)))) 
     2664      (:page-down 
     2665       (require-type where 'null) 
     2666       (scroll-by-lines tv (- (view-screen-lines view) *next-screen-context-lines*))) 
     2667      (:lines-up 
     2668       (scroll-by-lines tv (- (require-type where 'integer)))) 
     2669      (:lines-down 
     2670       (scroll-by-lines tv (require-type where 'integer)))) 
     2671    ;; If point is not on screen, move it. 
     2672    (let* ((point (hi::current-point)) 
     2673           (point-pos (hi::mark-absolute-position point))) 
     2674      (multiple-value-bind (win-pos win-len) (visible-charpos-range tv) 
     2675        (unless (and (<= win-pos point-pos) (< point-pos (+ win-pos win-len))) 
     2676          (let* ((point (hi::current-point-collapsing-selection)) 
     2677                 (cache (hemlock-buffer-string-cache (#/hemlockString (#/textStorage tv))))) 
     2678            (move-hemlock-mark-to-absolute-position point cache win-pos) 
     2679            (update-hemlock-selection (#/textStorage tv)))))))) 
    26922680 
    26932681(defun iana-charset-name-of-nsstringencoding (ns) 
     
    27812769  (make-editor-style-map)) 
    27822770 
    2783 ;;; This needs to run on the main thread. 
    2784 (objc:defmethod (#/updateHemlockSelection :void) ((self hemlock-text-storage)) 
     2771;;; This needs to run on the main thread.  Sets the cocoa selection from the 
     2772;;; hemlock selection. 
     2773(defmethod update-hemlock-selection ((self hemlock-text-storage)) 
    27852774  (assume-cocoa-thread) 
    2786   (let* ((string (#/hemlockString self)) 
    2787          (buffer (buffer-cache-buffer (hemlock-buffer-string-cache string))) 
    2788          (hi::*current-buffer* buffer) 
    2789          (point (hi::buffer-point buffer)) 
    2790          (pointpos (mark-absolute-position point)) 
    2791          (location pointpos) 
    2792          (len 0)) 
    2793     (when (hemlock::%buffer-region-active-p buffer) 
    2794       (let* ((mark (hi::buffer-%mark buffer))) 
    2795         (when mark 
    2796           (let* ((markpos (mark-absolute-position mark))) 
    2797             (if (< markpos pointpos) 
    2798               (setq location markpos len (- pointpos markpos)) 
    2799               (if (< pointpos markpos) 
    2800                 (setq location pointpos len (- markpos pointpos)))))))) 
    2801     #+debug 
    2802     (#_NSLog #@"update Hemlock selection: charpos = %d, abspos = %d" 
    2803              :int (hi::mark-charpos point) :int pointpos) 
    2804     (for-each-textview-using-storage 
    2805      self 
    2806      #'(lambda (tv) 
    2807          (#/updateSelection:length:affinity: tv location len (if (eql location 0) #$NSSelectionAffinityUpstream #$NSSelectionAffinityDownstream)))))) 
    2808  
    2809  
    2810 (defun hi::allocate-temporary-object-pool () 
    2811   (create-autorelease-pool)) 
    2812  
    2813 (defun hi::free-temporary-objects (pool) 
    2814   (release-autorelease-pool pool)) 
    2815  
     2775  (let ((buffer (hemlock-buffer self))) 
     2776    (multiple-value-bind (start end) (hi:buffer-selection-range buffer) 
     2777      #+debug 
     2778      (#_NSLog #@"update Hemlock selection: charpos = %d, abspos = %d" 
     2779               :int (hi::mark-charpos (hi::buffer-point buffer)) :int start) 
     2780      (for-each-textview-using-storage 
     2781       self 
     2782       #'(lambda (tv) 
     2783           (#/updateSelection:length:affinity: tv 
     2784                                               start 
     2785                                               (- end start) 
     2786                                               (if (eql start 0) 
     2787                                                 #$NSSelectionAffinityUpstream 
     2788                                                 #$NSSelectionAffinityDownstream))))))) 
     2789 
     2790;; This should be invoked by any command that modifies the buffer, so it can show the 
     2791;; user what happened...  This ensures the Cocoa selection is made visible, so it 
     2792;; assumes the Cocoa selection has already been synchronized with the hemlock one. 
     2793(defmethod hemlock-ext:ensure-selection-visible ((view hi:hemlock-view)) 
     2794  (let ((tv (text-pane-text-view (hi::hemlock-view-pane view)))) 
     2795    (#/scrollRangeToVisible: tv (#/selectedRange tv)))) 
    28162796 
    28172797(defloadvar *general-pasteboard* nil) 
     
    28542834  (let* ((pb (general-pasteboard)) 
    28552835         (string (progn (#/types pb) (#/stringForType: pb #&NSStringPboardType)))) 
     2836    #+GZ (log-debug "   string = ~s" string) 
    28562837    (unless (%null-ptr-p string) 
    28572838      (unless (zerop (ns:ns-range-length (#/rangeOfString: string *ns-cr-string*))) 
     
    28772858 
    28782859 
    2879 (defun hi::edit-definition (name) 
    2880   (let* ((info (ccl::get-source-files-with-types&classes name))) 
    2881     (when (null info) 
    2882       (let* ((seen (list name)) 
    2883              (found ()) 
    2884              (pname (symbol-name name))) 
    2885         (dolist (pkg (list-all-packages)) 
    2886           (let ((sym (find-symbol pname pkg))) 
    2887             (when (and sym (not (member sym seen))) 
    2888               (let ((new (ccl::get-source-files-with-types&classes sym))) 
    2889                 (when new 
    2890                   (setq info (append new info)) 
    2891                   (push sym found))) 
    2892               (push sym seen)))) 
    2893         (when found 
    2894           ;; Unfortunately, this puts the message in the wrong buffer (would be better in the destination buffer). 
    2895           (hi::loud-message "No definitions for ~s, using ~s instead" 
    2896                             name (if (cdr found) found (car found)))))) 
    2897     (if info 
    2898       (if (cdr info) 
    2899         (edit-definition-list name info) 
    2900         (edit-single-definition name (car info))) 
    2901       (hi::editor-error "No known definitions for ~s" name)))) 
    2902  
    2903  
    2904 (defun find-definition-in-document (name indicator document) 
    2905   (let* ((buffer (hemlock-document-buffer document)) 
    2906          (hi::*current-buffer* buffer)) 
    2907     (hemlock::find-definition-in-buffer buffer name indicator))) 
    2908  
    2909  
    2910 (defstatic *edit-definition-id-map* (make-id-map)) 
    2911  
    2912 ;;; Need to force things to happen on the main thread. 
    2913 (defclass cocoa-edit-definition-request (ns:ns-object) 
    2914     ((name-id :foreign-type :int) 
    2915      (info-id :foreign-type :int)) 
    2916   (:metaclass ns:+ns-object)) 
    2917  
    2918 (objc:defmethod #/initWithName:info: 
    2919     ((self cocoa-edit-definition-request) 
    2920      (name :int) (info :int)) 
    2921   (#/init self) 
    2922   (setf (slot-value self 'name-id) name 
    2923         (slot-value self 'info-id) info) 
    2924   self) 
    2925  
    2926 (objc:defmethod (#/editDefinition: :void) 
    2927     ((self hemlock-document-controller) request) 
    2928   (let* ((name (id-map-free-object *edit-definition-id-map* (slot-value request 'name-id))) 
    2929          (info (id-map-free-object *edit-definition-id-map* (slot-value request 'info-id)))) 
    2930     (destructuring-bind (indicator . pathname) info 
    2931       (let* ((namestring (native-translated-namestring pathname)) 
    2932              (url (#/initFileURLWithPath: 
    2933                    (#/alloc ns:ns-url) 
    2934                    (%make-nsstring namestring))) 
    2935              (document (#/openDocumentWithContentsOfURL:display:error: 
    2936                         self 
    2937                         url 
    2938                         nil 
    2939                         +null-ptr+))) 
    2940         (unless (%null-ptr-p document) 
    2941           (if (= (#/count (#/windowControllers document)) 0) 
    2942             (#/makeWindowControllers document)) 
    2943           (find-definition-in-document name indicator document) 
    2944           (#/updateHemlockSelection (slot-value document 'textstorage)) 
    2945           (#/showWindows document)))))) 
    2946  
    2947 (defun edit-single-definition (name info) 
    2948   (let* ((request (make-instance 'cocoa-edit-definition-request 
    2949                                  :with-name (assign-id-map-id *edit-definition-id-map* name) 
    2950                                  :info (assign-id-map-id *edit-definition-id-map* info)))) 
    2951     (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    2952      (#/sharedDocumentController ns:ns-document-controller) 
    2953      (@selector #/editDefinition:) 
    2954      request 
    2955      t))) 
    2956  
    2957                                          
    2958 (defun edit-definition-list (name infolist) 
     2860;; This is called by stuff that makes a window programmatically, e.g. m-. or grep. 
     2861;; But the Open and New menus invoke the cocoa fns below directly. So just changing 
     2862;; things here will not change how the menus create views.  Instead,f make changes to 
     2863;; the subfunctions invoked by the below, e.g. #/readFromURL or #/makeWindowControllers. 
     2864(defun find-or-make-hemlock-view (&optional pathname) 
     2865  (assume-cocoa-thread) 
     2866  (rlet ((perror :id +null-ptr+)) 
     2867    (let* ((doc (if pathname 
     2868                  (#/openDocumentWithContentsOfURL:display:error: 
     2869                   (#/sharedDocumentController ns:ns-document-controller) 
     2870                   (pathname-to-url pathname) 
     2871                   #$YES 
     2872                   perror) 
     2873                  (let ((*last-document-created* nil)) 
     2874                    (#/newDocument:  
     2875                     (#/sharedDocumentController hemlock-document-controller) 
     2876                     +null-ptr+) 
     2877                    *last-document-created*)))) 
     2878      #+gz (log-debug "created ~s" doc) 
     2879      (when (%null-ptr-p doc) 
     2880        (error "Couldn't open ~s: ~a" pathname 
     2881               (let ((error (pref perror :id))) 
     2882                 (if (%null-ptr-p error) 
     2883                   "unknown error encountered" 
     2884                   (lisp-string-from-nsstring (#/localizedDescription error)))))) 
     2885      (front-view-for-buffer (hemlock-buffer doc))))) 
     2886 
     2887(defun cocoa-edit-single-definition (name info) 
     2888  (assume-cocoa-thread) 
     2889  (destructuring-bind (indicator . pathname) info 
     2890    (let ((view (find-or-make-hemlock-view pathname))) 
     2891      (hi::handle-hemlock-event view 
     2892                                #'(lambda () 
     2893                                    (hemlock::find-definition-in-buffer name indicator)))))) 
     2894 
     2895(defun hemlock-ext:edit-single-definition (name info) 
     2896  (execute-in-gui #'(lambda () (cocoa-edit-single-definition name info)))) 
     2897 
     2898(defun hemlock-ext:open-sequence-dialog (&key title sequence action (printer #'prin1)) 
    29592899  (make-instance 'sequence-window-controller 
    2960                  :sequence infolist 
    2961                  :result-callback #'(lambda (info) 
    2962                                       (edit-single-definition name info)) 
    2963                  :display #'(lambda (item stream) 
    2964                               (prin1 (car item) stream)) 
    2965                  :title (format nil "Definitions of ~s" name))) 
    2966  
    2967                                         
     2900    :title title 
     2901    :sequence sequence 
     2902    :result-callback action 
     2903    :display printer)) 
     2904 
    29682905(objc:defmethod (#/documentClassForType: :<C>lass) ((self hemlock-document-controller) 
    29692906                                                    type) 
     
    30032940   t)) 
    30042941 
     2942(defun hemlock-ext:raise-buffer-view (buffer &optional action) 
     2943  "Bring a window containing buffer to front and then execute action in 
     2944   the window.  Returns before operation completes." 
     2945  ;; Queue for after this event, so don't screw up current context. 
     2946  (queue-for-gui #'(lambda () 
     2947                     (let ((doc (hi::buffer-document buffer))) 
     2948                       (unless (and doc (not (%null-ptr-p doc))) 
     2949                         (hi:editor-error "Deleted buffer: ~s" buffer)) 
     2950                       (#/showWindows doc) 
     2951                       (when action 
     2952                         (hi::handle-hemlock-event (front-view-for-buffer buffer) action)))))) 
    30052953 
    30062954;;; Enable CL:ED 
    30072955(defun cocoa-edit (&optional arg) 
    3008   (let* ((document-controller (#/sharedDocumentController hemlock-document-controller))) 
    3009     (cond ((null arg) 
    3010            (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    3011             document-controller 
    3012             (@selector #/newDocument:) 
    3013             +null-ptr+ 
    3014             t)) 
    3015           ((or (typep arg 'string) 
    3016                (typep arg 'pathname)) 
    3017            (unless (probe-file arg) 
    3018              (ccl::touch arg)) 
    3019            (with-autorelease-pool 
    3020              (let* ((url (pathname-to-url arg)) 
    3021                     (signature (#/methodSignatureForSelector: 
    3022                                 document-controller 
    3023                                 (@selector #/openDocumentWithContentsOfURL:display:error:))) 
    3024                     (invocation (#/invocationWithMethodSignature: ns:ns-invocation 
    3025                                                                   signature))) 
    3026               
    3027                (#/setTarget: invocation document-controller) 
    3028                (#/setSelector: invocation (@selector #/openDocumentWithContentsOfURL:display:error:)) 
    3029                (rlet ((p :id) 
    3030                       (q :<BOOL>) 
    3031                       (perror :id +null-ptr+)) 
    3032                  (setf (pref p :id) url 
    3033                        (pref q :<BOOL>) #$YES) 
    3034                  (#/setArgument:atIndex: invocation p 2) 
    3035                  (#/setArgument:atIndex: invocation q 3) 
    3036                  (#/setArgument:atIndex: invocation perror 4) 
    3037                  (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    3038                   invocation 
    3039                   (@selector #/invoke) 
    3040                   +null-ptr+ 
    3041                   t))))) 
    3042           ((ccl::valid-function-name-p arg) 
    3043            (hi::edit-definition arg)) 
    3044           (t (report-bad-arg arg '(or null string pathname (satisfies ccl::valid-function-name-p))))) 
    3045     t)) 
     2956  (cond ((or (null arg) 
     2957             (typep arg 'string) 
     2958             (typep arg 'pathname)) 
     2959         (execute-in-gui #'(lambda () (find-or-make-hemlock-view arg)))) 
     2960        ((ccl::valid-function-name-p arg) 
     2961         (hemlock::edit-definition arg) 
     2962         nil) 
     2963        (t (report-bad-arg arg '(or null string pathname (satisfies ccl::valid-function-name-p)))))) 
    30462964 
    30472965(setq ccl::*resident-editor-hook* 'cocoa-edit) 
  • trunk/source/cocoa-ide/cocoa-grep.lisp

    r7804 r8428  
    77(defvar *grep-program* "grep") 
    88 
    9 (defclass cocoa-edit-grep-line-request (ns:ns-object) 
    10   ((file-id :foreign-type :int) 
    11    (line-num :foreign-type :int)) 
    12   (:metaclass ns:+ns-object)) 
    13  
    14 (objc:defmethod #/initWithFile:line: 
    15                 ((self cocoa-edit-grep-line-request) (file :int) (line :int)) 
    16   (#/init self) 
    17   (setf (slot-value self 'file-id) file 
    18         (slot-value self 'line-num) line) 
    19   self) 
    20  
    21 (objc:defmethod (#/editGrepLine: :void) 
    22     ((self hemlock-document-controller) request) 
    23   (let* ((file (id-map-free-object *edit-definition-id-map* (slot-value request 'file-id))) 
    24          (line-num (slot-value request 'line-num)) 
    25          (namestring (native-translated-namestring file)) 
    26          (url (#/initFileURLWithPath: 
    27                (#/alloc ns:ns-url) 
    28                (%make-nsstring namestring))) 
    29          (document (#/openDocumentWithContentsOfURL:display:error: 
    30                     self 
    31                     url 
    32                     nil 
    33                     +null-ptr+))) 
    34     (unless (%null-ptr-p document) 
    35       (when (= (#/count (#/windowControllers document)) 0) 
    36         (#/makeWindowControllers document)) 
    37       (let* ((buffer (hemlock-document-buffer document)) 
    38              (hi::*current-buffer* buffer)) 
    39         (edit-grep-line-in-buffer line-num)) 
    40       (#/updateHemlockSelection (slot-value document 'textstorage)) 
    41       (#/showWindows document)))) 
     9(defun cocoa-edit-grep-line (file line-num) 
     10  (assume-cocoa-thread) 
     11  (let ((view (find-or-make-hemlock-view file))) 
     12    (hi::handle-hemlock-event view #'(lambda () 
     13                                       (edit-grep-line-in-buffer line-num))))) 
    4214 
    4315(defun edit-grep-line-in-buffer (line-num) 
     
    6032  (multiple-value-bind (file line-num) (parse-grep-line line) 
    6133    (when file 
    62       (let* ((request (make-instance 'cocoa-edit-grep-line-request 
    63                                      :with-file (assign-id-map-id *edit-definition-id-map* file) 
    64                                      :line line-num))) 
    65         (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    66          (#/sharedDocumentController ns:ns-document-controller) 
    67          (@selector #/editGrepLine:) 
    68          request 
    69          t))))) 
     34      (execute-in-gui #'(lambda () 
     35                          (cocoa-edit-grep-line file line-num)))))) 
    7036 
    7137(defun grep-comment-line-p (line) 
  • trunk/source/cocoa-ide/cocoa-listener.lisp

    r8149 r8428  
    2727(def-cocoa-default *read-only-listener* :bool t "Do not allow editing old listener output") 
    2828 
    29 ;;; Setup the server end of a pty pair. 
    30 (defun setup-server-pty (pty) 
    31   (set-tty-raw pty) 
    32   pty) 
    33  
    34 ;;; Setup the client end of a pty pair. 
    35 (defun setup-client-pty (pty) 
    36   ;; Since the same (Unix) process will be reading from and writing 
    37   ;; to the pty, it's critical that we make the pty non-blocking. 
    38   ;; Has this been true for the last few years (native threads) ? 
    39   ;(fd-set-flag pty #$O_NONBLOCK) 
    40   (set-tty-raw pty) 
    41   #+no 
    42   (disable-tty-local-modes pty (logior #$ECHO #$ECHOCTL #$ISIG)) 
    43   #+no 
    44   (disable-tty-output-modes pty #$ONLCR)   
    45   pty) 
     29(defun hemlock-ext:read-only-listener-p () 
     30  *read-only-listener*) 
     31 
     32 
     33(defclass cocoa-listener-input-stream (fundamental-character-input-stream) 
     34  ((queue :initform ()) 
     35   (queue-lock :initform (make-lock)) 
     36   (read-lock :initform (make-lock)) 
     37   (queue-semaphore :initform (make-semaphore)) ;; total queue count 
     38   (text-semaphore :initform (make-semaphore))  ;; text-only queue count 
     39   (cur-string :initform nil) 
     40   (cur-string-pos :initform 0) 
     41   (cur-env :initform nil) 
     42   (cur-sstream :initform nil))) 
     43 
     44(defmethod dequeue-listener-char ((stream cocoa-listener-input-stream) wait-p) 
     45  (with-slots (queue queue-lock read-lock queue-semaphore text-semaphore cur-string cur-string-pos) stream 
     46    (with-lock-grabbed (read-lock) 
     47      (or (with-lock-grabbed (queue-lock) 
     48            (when (< cur-string-pos (length cur-string)) 
     49              (prog1 (aref cur-string cur-string-pos) (incf cur-string-pos)))) 
     50          (loop 
     51            (unless (if wait-p 
     52                      (wait-on-semaphore text-semaphore nil "Listener Input") 
     53                      (timed-wait-on-semaphore text-semaphore 0)) 
     54              (return nil)) 
     55            (assert (timed-wait-on-semaphore queue-semaphore 0) () "queue/text mismatch!") 
     56            (with-lock-grabbed (queue-lock) 
     57              (let* ((s (find-if #'stringp queue))) 
     58                (assert s () "queue/semaphore mismatch!") 
     59                (setq queue (delq s queue 1)) 
     60                (when (< 0 (length s)) 
     61                  (setf cur-string s cur-string-pos 1) 
     62                  (return (aref s 0)))))))))) 
     63 
     64(defmethod ccl::read-toplevel-form ((stream cocoa-listener-input-stream) eof-value) 
     65  (with-slots (queue queue-lock read-lock queue-semaphore text-semaphore cur-string cur-string-pos cur-sstream cur-env) stream 
     66    (with-lock-grabbed (read-lock) 
     67      (loop 
     68        (when cur-sstream 
     69          #+gz (log-debug "About to recursively read from sstring in env: ~s" cur-env) 
     70          (let* ((env cur-env) 
     71                 (form (progv (car env) (cdr env) 
     72                         (ccl::read-toplevel-form cur-sstream eof-value))) 
     73                 (last-form-in-selection (not (listen cur-sstream)))) 
     74            #+gz (log-debug " --> ~s" form) 
     75            (when last-form-in-selection 
     76              (setf cur-sstream nil cur-env nil)) 
     77            (return (values form env (or last-form-in-selection ccl::*verbose-eval-selection*))))) 
     78        (when (with-lock-grabbed (queue-lock) 
     79                (loop 
     80                  unless (< cur-string-pos (length cur-string)) return nil 
     81                  unless (whitespacep (aref cur-string cur-string-pos)) return t 
     82                  do (incf cur-string-pos))) 
     83          (return (values (call-next-method) nil t))) 
     84        (wait-on-semaphore queue-semaphore nil "Toplevel Read") 
     85        (let ((val (with-lock-grabbed (queue-lock) (pop queue)))) 
     86          (cond ((stringp val) 
     87                 (assert (timed-wait-on-semaphore text-semaphore 0) () "text/queue mismatch!") 
     88                 (setq cur-string val cur-string-pos 0)) 
     89                (t 
     90                 (destructuring-bind (string package-name pathname) val 
     91                   (let ((env (cons '(*loading-file-source-file*) (list pathname)))) 
     92                     (when package-name 
     93                       (push '*package* (car env)) 
     94                       (push (ccl::pkg-arg package-name) (cdr env))) 
     95                     (setf cur-sstream (make-string-input-stream string) cur-env env)))))))))) 
     96 
     97(defmethod enqueue-toplevel-form ((stream cocoa-listener-input-stream) string &key package-name pathname) 
     98  (with-slots (queue-lock queue queue-semaphore) stream 
     99    (with-lock-grabbed (queue-lock) 
     100      (setq queue (nconc queue (list (list string package-name pathname)))) 
     101      (signal-semaphore queue-semaphore)))) 
     102 
     103(defmethod enqueue-listener-input ((stream cocoa-listener-input-stream) string) 
     104  (with-slots (queue-lock queue queue-semaphore text-semaphore) stream 
     105    (with-lock-grabbed (queue-lock) 
     106      (setq queue (nconc queue (list string))) 
     107      (signal-semaphore queue-semaphore) 
     108      (signal-semaphore text-semaphore)))) 
     109 
     110(defmethod stream-read-char-no-hang ((stream cocoa-listener-input-stream)) 
     111  (dequeue-listener-char stream nil)) 
     112 
     113(defmethod stream-read-char ((stream cocoa-listener-input-stream)) 
     114  (dequeue-listener-char stream t)) 
     115 
     116(defmethod stream-unread-char ((stream cocoa-listener-input-stream) char) 
     117  ;; Can't guarantee the right order of reads/unreads, just make sure not to 
     118  ;; introduce any internal inconsistencies (and dtrt for the non-conflict case). 
     119  (with-slots (queue queue-lock queue-semaphore text-semaphore cur-string cur-string-pos) stream 
     120    (with-lock-grabbed (queue-lock) 
     121      (cond ((>= cur-string-pos (length cur-string)) 
     122             (push (string char) queue) 
     123             (signal-semaphore queue-semaphore) 
     124             (signal-semaphore text-semaphore)) 
     125            ((< 0 cur-string-pos) 
     126             (decf cur-string-pos) 
     127             (setf (aref cur-string cur-string-pos) char)) 
     128            (t (setf cur-string (concatenate 'string (string char) cur-string))))))) 
     129 
     130(defmethod ccl::stream-eof-transient-p ((stream cocoa-listener-input-stream)) 
     131  t) 
     132 
     133(defmethod stream-clear-input ((stream cocoa-listener-input-stream)) 
     134  (with-slots (queue-lock cur-string cur-string-pos cur-sstream cur-env) stream 
     135    (with-lock-grabbed (queue-lock) 
     136      (setf cur-string nil cur-string-pos 0 cur-sstream nil cur-env nil)))) 
     137 
     138(defparameter $listener-flush-limit 100) 
     139 
     140(defclass cocoa-listener-output-stream (fundamental-character-output-stream) 
     141  ((lock :initform (make-lock)) 
     142   (hemlock-view :initarg :hemlock-view) 
     143   (data :initform (make-array (1+ $listener-flush-limit) 
     144                               :adjustable t :fill-pointer 0 
     145                               :element-type 'character)))) 
     146 
     147(defmethod stream-element-type ((stream cocoa-listener-output-stream)) 
     148  (with-slots (data) stream 
     149    (array-element-type data))) 
     150 
     151(defmethod ccl:stream-write-char ((stream cocoa-listener-output-stream) char) 
     152  (with-slots (data lock) stream 
     153    (when (with-lock-grabbed (lock) 
     154            (>= (vector-push-extend char data) $listener-flush-limit)) 
     155      (stream-force-output stream)))) 
     156 
     157;; This isn't really thread safe, but it's not too bad...  I'll take a chance - trying 
     158;; to get it to execute in the gui thread is too deadlock-prone. 
     159(defmethod hemlock-listener-output-mark-column ((view hi::hemlock-view)) 
     160  (let* ((output-region (hi::variable-value 'hemlock::current-output-font-region 
     161                                            :buffer (hi::hemlock-view-buffer view)))) 
     162    (hi::mark-charpos (hi::region-end output-region)))) 
     163 
     164;; TODO: doesn't do the right thing for embedded tabs (in buffer or data) 
     165(defmethod ccl:stream-line-column ((stream cocoa-listener-output-stream)) 
     166  (with-slots (hemlock-view data lock) stream 
     167    (with-lock-grabbed (lock) 
     168      (let* ((n (length data)) 
     169             (pos (position #\Newline data :from-end t))) 
     170        (if (null pos) 
     171          (+ (hemlock-listener-output-mark-column hemlock-view) n) 
     172          (- n pos 1)))))) 
     173 
     174(defmethod ccl:stream-fresh-line  ((stream cocoa-listener-output-stream)) 
     175  (with-slots (hemlock-view data lock) stream 
     176    (when (with-lock-grabbed (lock) 
     177            (let ((n (length data))) 
     178              (unless (if (= n 0) 
     179                        (= (hemlock-listener-output-mark-column hemlock-view) 0) 
     180                        (eq (aref data (1- n)) #\Newline)) 
     181                (>= (vector-push-extend #\Newline data) $listener-flush-limit)))) 
     182      (stream-force-output stream)))) 
     183 
     184(defmethod ccl::stream-finish-output ((stream cocoa-listener-output-stream)) 
     185  (stream-force-output stream)) 
     186 
     187(defmethod ccl:stream-force-output ((stream cocoa-listener-output-stream)) 
     188  (if (typep *current-process* 'appkit-process) 
     189    (with-slots (hemlock-view data lock) stream 
     190      (with-lock-grabbed (lock) 
     191        (when (> (fill-pointer data) 0) 
     192          (append-output hemlock-view data) 
     193          (setf (fill-pointer data) 0)))) 
     194    (with-slots (data) stream 
     195      (when (> (fill-pointer data) 0) 
     196        (queue-for-gui #'(lambda () (stream-force-output stream))))))) 
     197 
     198(defmethod ccl:stream-clear-output ((stream cocoa-listener-output-stream)) 
     199  (with-slots (data lock) stream 
     200    (with-lock-grabbed (lock) 
     201      (setf (fill-pointer data) 0)))) 
     202 
     203(defmethod ccl:stream-line-length ((stream cocoa-listener-output-stream)) 
     204  ;; TODO: ** compute length from window size ** 
     205  80) 
    46206 
    47207 
     
    51211    ((input-stream :reader cocoa-listener-process-input-stream) 
    52212     (output-stream :reader cocoa-listener-process-output-stream) 
    53      (input-peer-stream :reader cocoa-listener-process-input-peer-stream) 
    54213     (backtrace-contexts :initform nil 
    55214                         :accessor cocoa-listener-process-backtrace-contexts) 
    56      (window :reader cocoa-listener-process-window) 
    57      (buffer :initform nil :reader cocoa-listener-process-buffer))) 
     215     (window :reader cocoa-listener-process-window))) 
    58216   
    59217 
    60 (defun new-cocoa-listener-process (procname input-fd output-fd peer-fd window buffer) 
    61   (let* ((input-stream (ccl::make-selection-input-stream 
    62                         input-fd 
    63                         :peer-fd peer-fd 
    64                         :elements-per-buffer (#_fpathconf 
    65                                               input-fd 
    66                                               #$_PC_MAX_INPUT) 
    67                         :encoding :utf-8)) 
    68          (output-stream (ccl::make-fd-stream output-fd :direction :output 
    69                                              :sharing :lock 
    70                                              :elements-per-buffer 
    71                                              (#_fpathconf 
    72                                               output-fd 
    73                                               #$_PC_MAX_INPUT) 
    74                                              :encoding :utf-8)) 
    75          (peer-stream (ccl::make-fd-stream peer-fd :direction :output 
    76                                            :sharing :lock 
    77                                            :elements-per-buffer 
    78                                            (#_fpathconf 
    79                                             peer-fd 
    80                                             #$_PC_MAX_INPUT) 
    81                                            :encoding :utf-8)) 
     218(defun new-cocoa-listener-process (procname window) 
     219  (let* ((input-stream (make-instance 'cocoa-listener-input-stream)) 
     220         (output-stream (make-instance 'cocoa-listener-output-stream 
     221                          :hemlock-view (hemlock-view window))) 
     222          
    82223         (proc 
    83224          (ccl::make-mcl-listener-process  
     
    85226           input-stream 
    86227           output-stream 
     228           ;; cleanup function 
    87229           #'(lambda () 
    88                (let* ((buf (find *current-process* hi:*buffer-list* 
    89                                  :key #'hi::buffer-process)) 
    90                       (doc (if buf (hi::buffer-document buf)))) 
    91                  (when doc 
    92                    (setf (hi::buffer-process buf) nil) 
    93                    (#/performSelectorOnMainThread:withObject:waitUntilDone: 
    94                     doc 
    95                     (@selector #/close) 
    96                     +null-ptr+ 
    97                     nil)))) 
     230               (mapcar #'(lambda (buf) 
     231                           (when (eq (buffer-process buf) *current-process*) 
     232                             (let ((doc (hi::buffer-document buf))) 
     233                               (when doc 
     234                                 (setf (hemlock-document-process doc) nil) ;; so #/close doesn't kill it. 
     235                                 (#/performSelectorOnMainThread:withObject:waitUntilDone: 
     236                                  doc 
     237                                  (@selector #/close) 
     238                                  +null-ptr+ 
     239                                  nil))))) 
     240                       hi:*buffer-list*)) 
    98241           :initial-function 
    99242           #'(lambda () 
    100243               (setq ccl::*listener-autorelease-pool* (create-autorelease-pool)) 
    101244               (ccl::listener-function)) 
     245           :echoing nil 
    102246           :class 'cocoa-listener-process))) 
    103247    (setf (slot-value proc 'input-stream) input-stream) 
    104248    (setf (slot-value proc 'output-stream) output-stream) 
    105     (setf (slot-value proc 'input-peer-stream) peer-stream) 
    106249    (setf (slot-value proc 'window) window) 
    107     (setf (slot-value proc 'buffer) buffer) 
    108250    proc)) 
    109           
    110  
     251   
    111252(defclass hemlock-listener-frame (hemlock-frame) 
    112253    () 
     
    116257 
    117258(defclass hemlock-listener-window-controller (hemlock-editor-window-controller) 
    118     ((filehandle :foreign-type :id)     ;Filehandle for I/O 
    119      (clientfd :foreign-type :int)      ;Client (listener)'s side of pty 
    120      (nextra :foreign-type :int)        ;count of untranslated bytes remaining 
    121      (translatebuf :foreign-type :address) ;buffer for utf8 translation 
    122      (bufsize :foreign-type :int)       ;size of translatebuf 
    123      ) 
     259    () 
    124260  (:metaclass ns:+ns-object) 
    125261  ) 
     
    133269  
    134270 
    135 (objc:defmethod #/initWithWindow: ((self hemlock-listener-window-controller) w) 
    136   (let* ((new (call-next-method w))) 
    137     (unless (%null-ptr-p new) 
    138       (multiple-value-bind (server client) (ignore-errors (open-pty-pair)) 
    139         (when server 
    140           (let* ((fh (make-instance 
    141                       'ns:ns-file-handle 
    142                       :with-file-descriptor (setup-server-pty server) 
    143                       :close-on-dealloc t))) 
    144             (setf (slot-value new 'filehandle) fh) 
    145             (setf (slot-value new 'clientfd) (setup-client-pty client)) 
    146             (let* ((bufsize #$BUFSIZ) 
    147                    (buffer (#_malloc bufsize))) 
    148               (setf (slot-value new 'translatebuf) buffer 
    149                     (slot-value new 'bufsize) bufsize 
    150                     (slot-value new 'nextra) 0)) 
    151             (#/addObserver:selector:name:object: 
    152              (#/defaultCenter ns:ns-notification-center) 
    153              new 
    154              (@selector #/gotData:) 
    155              #&NSFileHandleReadCompletionNotification 
    156              fh) 
    157             (#/readInBackgroundAndNotify fh))))) 
    158     new)) 
    159  
    160 (objc:defmethod (#/gotData: :void) ((self hemlock-listener-window-controller) 
    161                                     notification) 
    162   (with-slots (filehandle nextra translatebuf bufsize) self 
    163     (let* ((data (#/objectForKey: (#/userInfo notification) 
    164                                   #&NSFileHandleNotificationDataItem)) 
    165            (document (#/document self)) 
    166            (encoding (load-time-value (get-character-encoding :utf-8))) 
    167            (data-length (#/length data)) 
    168            (buffer (hemlock-document-buffer document)) 
    169            (n nextra) 
    170            (cursize bufsize) 
    171            (need (+ n data-length)) 
    172            (xlate translatebuf) 
    173            (fh filehandle)) 
    174       (when (> need cursize) 
    175         (let* ((new (#_malloc need))) 
    176           (dotimes (i n) (setf (%get-unsigned-byte new i) 
    177                                (%get-unsigned-byte xlate i))) 
    178           (#_free xlate) 
    179           (setq xlate new translatebuf new bufsize need))) 
    180       #+debug (#_NSLog #@"got %d bytes of data" :int data-length) 
    181       (with-macptrs ((target (%inc-ptr xlate n))) 
    182         (#/getBytes:range: data target (ns:make-ns-range 0 data-length))) 
    183       (let* ((total (+ n data-length))) 
    184         (multiple-value-bind (nchars noctets-used) 
    185             (funcall (ccl::character-encoding-length-of-memory-encoding-function encoding) 
    186                      xlate 
    187                      total 
    188                      0) 
    189           (let* ((string (make-string nchars))) 
    190             (funcall (ccl::character-encoding-memory-decode-function encoding) 
    191                      xlate 
    192                      noctets-used 
    193                      0 
    194                      string) 
    195             (unless (zerop (setq n (- total noctets-used))) 
    196               ;; By definition, the number of untranslated octets 
    197               ;; can't be more than 3. 
    198               (dotimes (i n) 
    199                 (setf (%get-unsigned-byte xlate i) 
    200                       (%get-unsigned-byte xlate (+ noctets-used i))))) 
    201             (setq nextra n) 
    202             (hi::enqueue-buffer-operation 
    203              buffer 
    204              #'(lambda () 
    205                  (unwind-protect 
    206                       (progn 
    207                         (hi::buffer-document-begin-editing buffer) 
    208                         (hemlock::append-buffer-output buffer string)) 
    209                    (hi::buffer-document-end-editing buffer)))) 
    210             (#/readInBackgroundAndNotify fh))))))) 
    211               
    212  
    213  
    214 (objc:defmethod (#/dealloc :void) ((self hemlock-listener-window-controller)) 
    215   (#/removeObserver: (#/defaultCenter ns:ns-notification-center) self) 
    216   (call-next-method)) 
    217  
    218271(objc:defmethod #/windowTitleForDocumentDisplayName: ((self hemlock-listener-window-controller) name) 
    219272  (let* ((doc (#/document self))) 
     
    221274            (not (%null-ptr-p (#/fileURL doc)))) 
    222275      (call-next-method name) 
    223       (let* ((buffer (hemlock-document-buffer doc)) 
     276      (let* ((buffer (hemlock-buffer doc)) 
    224277             (bufname (if buffer (hi::buffer-name buffer)))) 
    225278        (if bufname 
     
    232285 
    233286(defclass hemlock-listener-document (hemlock-editor-document) 
    234     () 
     287  ((process :reader %hemlock-document-process :writer (setf hemlock-document-process))) 
    235288  (:metaclass ns:+ns-object)) 
    236289(declaim (special hemlock-listener-document)) 
    237290 
     291(defgeneric hemlock-document-process (doc) 
     292  (:method ((unknown t)) nil) 
     293  (:method ((doc hemlock-listener-document)) (%hemlock-document-process doc))) 
     294 
     295;; Nowadays this is nil except for listeners. 
     296(defun buffer-process (buffer) 
     297  (hemlock-document-process (hi::buffer-document buffer))) 
     298 
    238299(defmethod update-buffer-package ((doc hemlock-listener-document) buffer) 
    239300  (declare (ignore buffer))) 
    240301 
    241 (defmethod hi::document-encoding-name ((doc hemlock-listener-document)) 
     302(defmethod document-encoding-name ((doc hemlock-listener-document)) 
    242303  "UTF-8") 
    243304