Changeset 8428
- Timestamp:
- 02/05/08 17:01:48 (4 years ago)
- Location:
- trunk/source/cocoa-ide
- Files:
-
- 5 removed
- 52 modified
- 5 copied
-
cocoa-editor.lisp (modified) (69 diffs)
-
cocoa-grep.lisp (modified) (2 diffs)
-
cocoa-listener.lisp (modified) (23 diffs)
-
cocoa-utils.lisp (modified) (2 diffs)
-
cocoa-window.lisp (modified) (7 diffs)
-
cocoa.lisp (modified) (1 diff)
-
compile-hemlock.lisp (modified) (6 diffs)
-
defsystem.lisp (modified) (2 diffs)
-
hemlock/src/bindings-gb.lisp (deleted)
-
hemlock/src/bindings.lisp (modified) (21 diffs)
-
hemlock/src/buffer.lisp (modified) (17 diffs)
-
hemlock/src/charmacs.lisp (modified) (1 diff)
-
hemlock/src/cocoa-hemlock.lisp (modified) (4 diffs)
-
hemlock/src/command.lisp (modified) (15 diffs)
-
hemlock/src/completion.lisp (modified) (5 diffs)
-
hemlock/src/cursor.lisp (deleted)
-
hemlock/src/decls.lisp (modified) (1 diff)
-
hemlock/src/defsyn.lisp (modified) (1 diff)
-
hemlock/src/doccoms.lisp (modified) (11 diffs)
-
hemlock/src/echo.lisp (modified) (17 diffs)
-
hemlock/src/echocoms.lisp (modified) (15 diffs)
-
hemlock/src/edit-defs.lisp (modified) (7 diffs)
-
hemlock/src/filecoms.lisp (modified) (12 diffs)
-
hemlock/src/files.lisp (modified) (1 diff)
-
hemlock/src/fill.lisp (modified) (4 diffs)
-
hemlock/src/font.lisp (modified) (3 diffs)
-
hemlock/src/hemlock-ext.lisp (modified) (6 diffs)
-
hemlock/src/htext1.lisp (modified) (8 diffs)
-
hemlock/src/htext2.lisp (modified) (7 diffs)
-
hemlock/src/htext3.lisp (modified) (2 diffs)
-
hemlock/src/htext4.lisp (modified) (4 diffs)
-
hemlock/src/interp.lisp (modified) (14 diffs)
-
hemlock/src/isearchcoms.lisp (copied) (copied from branches/event-ide/ccl/cocoa-ide/hemlock/src/isearchcoms.lisp)
-
hemlock/src/kbdmac.lisp (deleted)
-
hemlock/src/key-event.lisp (modified) (24 diffs)
-
hemlock/src/keysym-defs.lisp (modified) (4 diffs)
-
hemlock/src/killcoms.lisp (modified) (5 diffs)
-
hemlock/src/linimage.lisp (deleted)
-
hemlock/src/lispdep.lisp (deleted)
-
hemlock/src/lispmode.lisp (modified) (14 diffs)
-
hemlock/src/listener.lisp (modified) (12 diffs)
-
hemlock/src/macros.lisp (modified) (11 diffs)
-
hemlock/src/main.lisp (modified) (7 diffs)
-
hemlock/src/modeline.lisp (modified) (9 diffs)
-
hemlock/src/morecoms.lisp (modified) (10 diffs)
-
hemlock/src/package.lisp (modified) (31 diffs)
-
hemlock/src/pop-up-stream.lisp (modified) (3 diffs)
-
hemlock/src/register.lisp (modified) (7 diffs)
-
hemlock/src/ring.lisp (modified) (2 diffs)
-
hemlock/src/rompsite.lisp (modified) (7 diffs)
-
hemlock/src/search1.lisp (modified) (2 diffs)
-
hemlock/src/searchcoms.lisp (modified) (7 diffs)
-
hemlock/src/streams.lisp (modified) (2 diffs)
-
hemlock/src/struct.lisp (modified) (15 diffs)
-
hemlock/src/symbol-completion.lisp (modified) (1 diff)
-
hemlock/src/syntax.lisp (modified) (20 diffs)
-
hemlock/src/undo.lisp (modified) (1 diff)
-
hemlock/src/vars.lisp (modified) (9 diffs)
-
hemlock/src/views.lisp (copied) (copied from branches/event-ide/ccl/cocoa-ide/hemlock/src/views.lisp)
-
hemlock/unused/cursor.lisp (copied) (copied from branches/event-ide/ccl/cocoa-ide/hemlock/unused/cursor.lisp)
-
hemlock/unused/kbdmac.lisp (copied) (copied from branches/event-ide/ccl/cocoa-ide/hemlock/unused/kbdmac.lisp)
-
hemlock/unused/linimage.lisp (copied) (copied from branches/event-ide/ccl/cocoa-ide/hemlock/unused/linimage.lisp)
Legend:
- Unmodified
- Added
- Removed
-
trunk/source/cocoa-ide/cocoa-editor.lisp
r7804 r8428 26 26 27 27 (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)))) 28 40 29 41 (defmacro nsstring-encoding-to-nsinteger (n) … … 145 157 buf)) 146 158 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 156 230 157 231 … … 195 269 (:metaclass ns:+ns-object)) 196 270 271 (defmethod hemlock-buffer ((self hemlock-buffer-string)) 272 (let ((cache (hemlock-buffer-string-cache self))) 273 (when cache 274 (hemlock-buffer cache)))) 275 197 276 ;;; Cocoa wants to treat the buffer as a linear array of characters; 198 277 ;;; Hemlock wants to treat it as a doubly-linked list of lines, so … … 215 294 workline-start-font-index ; current font index at start of workline 216 295 ) 296 297 (defmethod hemlock-buffer ((self buffer-cache)) 298 (buffer-cache-buffer self)) 217 299 218 300 ;;; Initialize (or reinitialize) a buffer cache, so that it points … … 303 385 ;;; offset on the appropriate line. 304 386 (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. 305 388 (let* ((hi::*current-buffer* (buffer-cache-buffer cache))) 306 389 (multiple-value-bind (line idx) (update-line-cache-for-index cache abspos) 307 390 #+debug 308 391 (#_NSLog #@"Moving point from current pos %d to absolute position %d" 309 :int ( mark-absolute-position mark)392 :int (hi:mark-absolute-position mark) 310 393 :int abspos) 311 394 (hemlock::move-to-position mark idx line) 312 395 #+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))))) 322 397 323 398 ;;; Return the length of the abstract string, i.e., the number of … … 427 502 (declaim (special hemlock-text-storage)) 428 503 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)))) 429 508 430 509 ;;; This is only here so that calls to it can be logged for debugging. … … 451 530 452 531 (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))) 454 533 455 534 (defun textstorage-note-insertion-at-position (self pos n) … … 469 548 (assume-cocoa-thread) 470 549 (let* ((mirror (#/mirror self)) 471 (hemlock-string (#/hemlockString self))550 (hemlock-string (#/hemlockString self)) 472 551 (display (hemlock-buffer-string-cache hemlock-string)) 473 552 (buffer (buffer-cache-buffer display)) 474 553 (hi::*current-buffer* buffer) 475 ( font (buffer-active-fontbuffer))554 (attributes (buffer-active-font-attributes buffer)) 476 555 (document (#/document self)) 477 556 (undo-mgr (and document (#/undoManager document)))) … … 490 569 (#/prepareWithInvocationTarget: undo-mgr self) 491 570 pos n #@""))) 492 (#/setAttributes:range: mirror font (ns:make-ns-range pos n))571 (#/setAttributes:range: mirror attributes (ns:make-ns-range pos n)) 493 572 (textstorage-note-insertion-at-position self pos n))) 494 573 … … 654 733 (with-slots (mirror styles) self 655 734 (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)) 662 736 (ccl::dbg)) 663 737 (let* ((attrs (#/attributesAtIndex:effectiveRange: mirror index rangeptr))) … … 683 757 (#/replaceCharactersInRange:withString: self r string)))) 684 758 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 685 775 (objc:defmethod (#/replaceCharactersInRange:withString: :void) 686 776 ((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)) 695 779 (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)))))) 720 786 721 787 (objc:defmethod (#/setAttributes:range: :void) ((self hemlock-text-storage) … … 744 810 (objc:defmethod #/description ((self hemlock-text-storage)) 745 811 (#/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-storage751 self752 #'(lambda (tv)753 (assume-not-editing tv)754 (#/scrollRangeToVisible: tv (#/selectedRange tv)))))755 756 812 757 813 (defun close-hemlock-textstorage (ts) … … 770 826 (slot-value hemlock-string 'cache) nil 771 827 (hi::buffer-document buffer) nil) 772 (let* ((p (hi::buffer-process buffer)))773 (when p774 (setf (hi::buffer-process buffer) nil)775 (process-kill p)))776 828 (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)))))) 783 831 784 832 … … 808 856 (declaim (special hemlock-textstorage-text-view)) 809 857 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 "~"e-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)) 810 962 811 963 (defmethod assume-not-editing ((tv hemlock-textstorage-text-view)) … … 891 1043 (defmethod update-blink ((self hemlock-textstorage-text-view)) 892 1044 (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))) 895 1046 (when (and buffer (string= (hi::buffer-major-mode buffer) "Lisp")) 896 1047 (let* ((hi::*current-buffer* buffer) … … 905 1056 #+debug (#_NSLog #@"enable blink, forward") 906 1057 (setf (text-view-blink-location self) 907 (1- ( mark-absolute-position temp))1058 (1- (hi:mark-absolute-position temp)) 908 1059 (text-view-blink-enabled self) #$YES))))) 909 1060 ((eql (hi::previous-character point) #\)) … … 914 1065 #+debug (#_NSLog #@"enable blink, backward") 915 1066 (setf (text-view-blink-location self) 916 ( mark-absolute-position temp)1067 (hi:mark-absolute-position temp) 917 1068 (text-view-blink-enabled self) #$YES)))))))))) 918 1069 … … 939 1090 nil) 940 1091 (assume-not-editing self) 941 (#/scrollRangeToVisible: self range)942 1092 (when (> length 0) 943 1093 (let* ((ts (#/textStorage self))) … … 963 1113 ((pane :foreign-type :id :accessor text-view-pane) 964 1114 (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)) 966 1116 (: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)))) 967 1122 968 1123 (objc:defmethod (#/evalSelection: :void) ((self hemlock-text-view) sender) 969 1124 (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)) 973 1126 (package-name (hi::variable-value 'hemlock::current-package :buffer buffer)) 974 1127 (pathname (hi::buffer-pathname buffer)) … … 983 1136 (objc:defmethod (#/loadBuffer: :void) ((self hemlock-text-view) sender) 984 1137 (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)) 988 1139 (package-name (hi::variable-value 'hemlock::current-package :buffer buffer)) 989 1140 (pathname (hi::buffer-pathname buffer))) … … 992 1143 (objc:defmethod (#/compileBuffer: :void) ((self hemlock-text-view) sender) 993 1144 (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)) 997 1146 (package-name (hi::variable-value 'hemlock::current-package :buffer buffer)) 998 1147 (pathname (hi::buffer-pathname buffer))) … … 1001 1150 (objc:defmethod (#/compileAndLoadBuffer: :void) ((self hemlock-text-view) sender) 1002 1151 (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)) 1006 1153 (package-name (hi::variable-value 'hemlock::current-package :buffer buffer)) 1007 1154 (pathname (hi::buffer-pathname buffer))) … … 1105 1252 1106 1253 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)))) 1114 1256 1115 1257 (objc:defmethod (#/selectionRangeForProposedRange:granularity: :ns-range) … … 1137 1279 (hi::with-mark ((m2 m1)) 1138 1280 (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)) 1140 1282 (return-from HANDLED r)))) 1141 1283 ((eql (hi::previous-character m1) #\)) 1142 1284 (hi::with-mark ((m2 m1)) 1143 1285 (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))) 1145 1287 (return-from HANDLED r)))))))))))) 1146 1288 (call-next-method proposed g) … … 1153 1295 1154 1296 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 1227 1304 1228 1305 ;;; Update the underlying buffer's point (and "active region", if appropriate. … … 1282 1359 ;; In all cases, activate Hemlock selection. 1283 1360 (unless still-selecting 1284 (let* ((pointpos ( mark-absolute-position point))1361 (let* ((pointpos (hi:mark-absolute-position point)) 1285 1362 (selection-end (+ location len)) 1286 1363 (mark (hi::copy-mark point :right-inserting))) … … 1364 1441 (let* ((tv (text-pane-text-view pane))) 1365 1442 (unless (%null-ptr-p tv) 1366 ( text-view-buffer tv))))))1443 (hemlock-buffer tv)))))) 1367 1444 1368 1445 ;;; Draw a string in the modeline view. The font and other attributes … … 1371 1448 ;;; used in the event dispatch mechanism, 1372 1449 (defun draw-modeline-string (the-modeline-view) 1373 (with-slots ( panetext-attributes) the-modeline-view1450 (with-slots (text-attributes) the-modeline-view 1374 1451 (let* ((buffer (buffer-for-modeline-view the-modeline-view))) 1375 1452 (when buffer … … 1378 1455 (mapcar 1379 1456 #'(lambda (field) 1380 (funcall (hi::modeline-field-function field) 1381 buffer pane)) 1457 (funcall (hi::modeline-field-function field) buffer)) 1382 1458 (hi::buffer-modeline-fields buffer))))) 1383 1459 (#/drawAtPoint:withAttributes: (%make-nsstring string) … … 1474 1550 1475 1551 (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) 1477 1554 (mode-line :foreign-type :id :accessor text-pane-mode-line) 1478 1555 (scroll-view :foreign-type :id :accessor text-pane-scroll-view)) 1479 1556 (:metaclass ns:+ns-object)) 1480 1557 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 1482 1562 ;;; "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)))) 1486 1567 1487 1568 (def-cocoa-default *text-pane-margin-width* :float 0.0f0 "width of indented margin around text pane") … … 1596 1677 tv))) 1597 1678 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))) 1620 1687 1621 1688 (defclass echo-area-view (hemlock-textstorage-text-view) 1622 1689 () 1623 1690 (: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)))) 1655 1697 1656 1698 ;;; The "document" for an echo-area isn't a real NSDocument. … … 1659 1701 (:metaclass ns:+ns-object)) 1660 1702 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 1661 1708 (objc:defmethod (#/undoManager :<BOOL>) ((self echo-area-document)) 1662 1709 nil) ;For now, undo is not supported for echo-areas … … 1664 1711 (defmethod update-buffer-package ((doc echo-area-document) buffer) 1665 1712 (declare (ignore buffer))) 1713 1714 (defmethod document-invalidate-modeline ((self echo-area-document)) 1715 nil) 1666 1716 1667 1717 (objc:defmethod (#/close :void) ((self echo-area-document)) … … 1671 1721 (close-hemlock-textstorage ts)))) 1672 1722 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)) 1676 1724 (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)1686 1725 1687 1726 (defun make-echo-area (the-hemlock-frame x y width height main-buffer color) … … 1698 1737 (#/setAutoresizesSubviews: box t) 1699 1738 (#/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)) 1705 1740 (textstorage 1706 1741 (progn 1707 1742 ;; 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)) 1709 1744 (make-textstorage-for-hemlock-buffer buffer))) 1710 1745 (doc (make-instance 'echo-area-document)) … … 1757 1792 ((echo-area-view :foreign-type :id) 1758 1793 (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)1762 1794 (echo-area-buffer :initform nil :accessor hemlock-frame-echo-area-buffer) 1763 1795 (echo-area-stream :initform nil :accessor hemlock-frame-echo-area-stream)) 1764 1796 (:metaclass ns:+ns-object)) 1765 1797 (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)))) 1766 1803 1767 1804 (defun double-%-in (string) … … 1774 1811 1775 1812 (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 1806 1831 (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))) 1828 1843 (when (and pane (not (%null-ptr-p pane))) 1829 1844 (report-condition-in-hemlock-frame condition (#/window pane))))) 1830 1845 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-stream1842 (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-protect1864 (loop1865 (catch 'hi::editor-top-level-catcher1866 (handler-bind ((error #'(lambda (condition)1867 (hi::lisp-error-error-handler condition1868 :internal))))1869 (hi::invoke-hook hemlock::abort-hook)1870 (hi::%command-loop))))1871 (hi::invoke-hook hemlock::exit-hook))))1872 1873 1874 1846 (objc:defmethod (#/close :void) ((self hemlock-frame)) 1875 1847 (let* ((content-view (#/contentView self)) … … 1878 1850 ((< i 0)) 1879 1851 (#/removeFromSuperviewWithoutNeedingDisplay (#/objectAtIndex: subviews i)))) 1880 (let* ((proc (slot-value self 'command-thread)))1881 (when proc1882 (setf (slot-value self 'command-thread) nil)1883 (process-kill proc)))1884 1852 (let* ((buf (hemlock-frame-echo-area-buffer self)) 1885 1853 (echo-doc (if buf (hi::buffer-document buf)))) … … 1922 1890 (nsstring-to-buffer nsstring buffer))) 1923 1891 1924 (defun %nsstring-to- mark (nsstring mark)1892 (defun %nsstring-to-hemlock-string (nsstring) 1925 1893 "returns line-termination of string" 1926 1894 (let* ((string (lisp-string-from-nsstring nsstring)) … … 1929 1897 (line-termination (if crpos 1930 1898 (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. 1941 1910 (defun nsstring-to-buffer (nsstring buffer) 1942 1911 (let* ((document (hi::buffer-document buffer)) 1943 1912 (hi::*current-buffer* buffer) 1944 1913 (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))))) 1959 1929 1960 1930 … … 1968 1938 (assume-cocoa-thread) 1969 1939 (let* ((pane (textpane-for-textstorage class ts ncols nrows container-tracks-text-view-width color style)) 1940 (buffer (hemlock-buffer ts)) 1970 1941 (frame (#/window pane)) 1971 (buffer (text-view-buffer (text-pane-text-view pane)))1972 1942 (echo-area (make-echo-area-for-window frame buffer color)) 1943 (echo-buffer (hemlock-buffer (#/textStorage echo-area))) 1973 1944 (tv (text-pane-text-view pane))) 1945 #+GZ (assert echo-buffer) 1974 1946 (with-slots (peer) tv 1975 1947 (setq peer echo-area)) 1976 1948 (with-slots (peer) echo-area 1977 1949 (setq peer tv)) 1978 (hi::activate-hemlock-view pane)1979 1950 (setf (slot-value frame 'echo-area-view) echo-area 1980 1951 (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)) 2001 1959 2002 1960 … … 2007 1965 (release-lock (hi::buffer-lock b))) 2008 1966 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)))))) 2015 1997 2016 1998 (defun document-edit-level (document) 2017 1999 (assume-cocoa-thread) ;; see comment in #/editingInProgress 2018 2000 (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 #+debug2030 (#_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 2036 2001 2037 2002 (defun perform-edit-change-notification (textstorage selector pos n &optional (extra 0)) … … 2065 2030 (let* ((document (hi::buffer-document buffer)) 2066 2031 (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))) 2069 2034 (perform-edit-change-notification textstorage 2070 2035 (@selector #/noteHemlockAttrChangeAtPosition:length:) … … 2073 2038 font)))) 2074 2039 2075 (defun buffer-active-font (buffer)2040 (defun buffer-active-font-attributes (buffer) 2076 2041 (let* ((style 0) 2077 2042 (region (hi::buffer-active-font-region buffer)) … … 2090 2055 (textstorage (if document (slot-value document 'textstorage)))) 2091 2056 (when textstorage 2092 (let* ((pos ( mark-absolute-position mark)))2057 (let* ((pos (hi:mark-absolute-position mark))) 2093 2058 (when (eq (hi::mark-%kind mark) :left-inserting) 2094 2059 ;; Make up for the fact that the mark moved forward with the insertion. … … 2107 2072 (perform-edit-change-notification textstorage 2108 2073 (@selector #/noteHemlockModificationAtPosition:length:) 2109 ( mark-absolute-position mark)2074 (hi:mark-absolute-position mark) 2110 2075 n))))) 2111 2076 … … 2116 2081 (textstorage (if document (slot-value document 'textstorage)))) 2117 2082 (when textstorage 2118 (let* ((pos ( mark-absolute-position mark)))2083 (let* ((pos (hi:mark-absolute-position mark))) 2119 2084 (perform-edit-change-notification textstorage 2120 2085 (@selector #/noteHemlockDeletionAtPosition:length:) … … 2124 2089 2125 2090 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 2141 2104 2142 2105 (defun size-of-char-in-font (f) … … 2151 2114 2152 2115 2153 (defun size-text-pane (pane char-height char-width nrows ncols)2116 (defun size-text-pane (pane line-height char-width nrows ncols) 2154 2117 (let* ((tv (text-pane-text-view pane)) 2155 (height (fceiling (* nrows char-height)))2118 (height (fceiling (* nrows line-height))) 2156 2119 (width (fceiling (* ncols char-width))) 2157 2120 (scrollview (text-pane-scroll-view pane)) … … 2163 2126 height) 2164 2127 (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|#)) 2167 2130 (when has-horizontal-scroller 2168 2131 (#/setHorizontalLineScroll: scrollview char-width) … … 2178 2141 (#/setContentSize: window sv-size) 2179 2142 (setf (slot-value tv 'char-width) char-width 2180 (slot-value tv ' char-height) char-height)2143 (slot-value tv 'line-height) line-height) 2181 2144 (#/setResizeIncrements: window 2182 (ns:make-ns-size char-width char-height))))))2145 (ns:make-ns-size char-width line-height)))))) 2183 2146 2184 2147 … … 2187 2150 (:metaclass ns:+ns-object)) 2188 2151 2152 (defmethod hemlock-view ((self hemlock-editor-window-controller)) 2153 (let ((frame (#/window self))) 2154 (unless (%null-ptr-p frame) 2155 (hemlock-view frame)))) 2189 2156 2190 2157 ;;; Map *default-file-character-encoding* to an :<NSS>tring<E>ncoding … … 2222 2189 (:metaclass ns:+ns-object)) 2223 2190 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)))) 2226 2195 2227 2196 (defmethod assume-not-editing ((doc hemlock-editor-document)) 2228 2197 (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)))))) 2229 2206 2230 2207 (defmethod update-buffer-package ((doc hemlock-editor-document) buffer) … … 2239 2216 (setf (hi::variable-value 'hemlock::current-package :buffer buffer) name)))))) 2240 2217 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))))))) 2246 2225 2247 2226 (objc:defmethod (#/validateMenuItem: :<BOOL>) … … 2265 2244 (eql action (@selector #/compileBuffer:)) 2266 2245 (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)) 2269 2247 (pathname (hi::buffer-pathname buffer))) 2270 2248 (not (null pathname)))) … … 2276 2254 (defvar *encoding-name-hash* (make-hash-table)) 2277 2255 2278 (defmethod hi::document-encoding-name ((doc hemlock-editor-document))2256 (defmethod document-encoding-name ((doc hemlock-editor-document)) 2279 2257 (with-slots (encoding) doc 2280 2258 (if (eql encoding 0) … … 2284 2262 (lisp-string-from-nsstring (nsstring-for-nsstring-encoding encoding))))))) 2285 2263 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. 2287 2269 (defmethod textview-background-color ((doc hemlock-editor-document)) 2288 2270 *editor-background-color*) … … 2311 2293 :encoding encoding 2312 2294 :error +null-ptr+)) 2313 (buffer (hemlock- document-buffer self))2295 (buffer (hemlock-buffer self)) 2314 2296 (old-length (hemlock-buffer-length buffer)) 2315 2297 (hi::*current-buffer* buffer) 2316 2298 (textstorage (slot-value self 'textstorage)) 2317 2299 (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 point2331 display2332 (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))) 2338 2320 t)) 2339 2340 2341 2321 2322 2323 (defvar *last-document-created* nil) 2324 2342 2325 (objc:defmethod #/init ((self hemlock-editor-document)) 2343 2326 (let* ((doc (call-next-method))) … … 2348 2331 (#/displayName doc)) 2349 2332 :modes '("Lisp" "Editor"))))) 2333 (setq *last-document-created* doc) 2350 2334 doc)) 2351 2335 2352 2336 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 2353 2345 (objc:defmethod (#/readFromURL:ofType:error: :<BOOL>) 2354 2346 ((self hemlock-editor-document) url type (perror (:* :id))) 2355 2347 (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 2372 2369 (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))))) 2416 2398 2417 2399 … … 2451 2433 2452 2434 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)) 2476 2445 2477 2446 (defmethod hi::document-panes ((document hemlock-editor-document)) … … 2490 2459 (with-slots (encoding) self 2491 2460 (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)))) 2494 2462 2495 2463 (objc:defmethod (#/prepareSavePanel: :<BOOL>) ((self hemlock-editor-document) … … 2515 2483 (with-slots (encoding textstorage) self 2516 2484 (let* ((string (#/string textstorage)) 2517 (buffer (hemlock- document-buffer self)))2485 (buffer (hemlock-buffer self))) 2518 2486 (case (when buffer (hi::buffer-line-termination buffer)) 2519 (:c p/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 string2525 (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))))) 2528 2496 (when (#/writeToURL:atomically:encoding:error: 2529 2497 string url t encoding error) … … 2540 2508 url) 2541 2509 (call-next-method url) 2542 (let* ((buffer (hemlock- document-buffer self)))2510 (let* ((buffer (hemlock-buffer self))) 2543 2511 (when buffer 2544 2512 (let* ((new-pathname (lisp-string-from-nsstring (#/path url)))) … … 2575 2543 #+debug 2576 2544 (#_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))))))) 2600 2572 2601 2573 … … 2614 2586 (call-next-method)) 2615 2587 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))) 2621 2598 ;; Convert from view coordinates to container coordinates 2622 2599 (decf (pref rect :<NSR>ect.origin.x) (pref container-origin :<NSP>oint.x)) 2623 2600 (decf (pref rect :<NSR>ect.origin.y) (pref container-origin :<NSP>oint.y)) 2624 2601 (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+))) 2628 2605 (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)))))))) 2692 2680 2693 2681 (defun iana-charset-name-of-nsstringencoding (ns) … … 2781 2769 (make-editor-style-map)) 2782 2770 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)) 2785 2774 (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)))) 2816 2796 2817 2797 (defloadvar *general-pasteboard* nil) … … 2854 2834 (let* ((pb (general-pasteboard)) 2855 2835 (string (progn (#/types pb) (#/stringForType: pb #&NSStringPboardType)))) 2836 #+GZ (log-debug " string = ~s" string) 2856 2837 (unless (%null-ptr-p string) 2857 2838 (unless (zerop (ns:ns-range-length (#/rangeOfString: string *ns-cr-string*))) … … 2877 2858 2878 2859 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)) 2959 2899 (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 2968 2905 (objc:defmethod (#/documentClassForType: :<C>lass) ((self hemlock-document-controller) 2969 2906 type) … … 3003 2940 t)) 3004 2941 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)))))) 3005 2953 3006 2954 ;;; Enable CL:ED 3007 2955 (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)))))) 3046 2964 3047 2965 (setq ccl::*resident-editor-hook* 'cocoa-edit) -
trunk/source/cocoa-ide/cocoa-grep.lisp
r7804 r8428 7 7 (defvar *grep-program* "grep") 8 8 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))))) 42 14 43 15 (defun edit-grep-line-in-buffer (line-num) … … 60 32 (multiple-value-bind (file line-num) (parse-grep-line line) 61 33 (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)))))) 70 36 71 37 (defun grep-comment-line-p (line) -
trunk/source/cocoa-ide/cocoa-listener.lisp
r8149 r8428 27 27 (def-cocoa-default *read-only-listener* :bool t "Do not allow editing old listener output") 28 28 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) 46 206 47 207 … … 51 211 ((input-stream :reader cocoa-listener-process-input-stream) 52 212 (output-stream :reader cocoa-listener-process-output-stream) 53 (input-peer-stream :reader cocoa-listener-process-input-peer-stream)54 213 (backtrace-contexts :initform nil 55 214 :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))) 58 216 59 217 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 82 223 (proc 83 224 (ccl::make-mcl-listener-process … … 85 226 input-stream 86 227 output-stream 228 ;; cleanup function 87 229 #'(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*)) 98 241 :initial-function 99 242 #'(lambda () 100 243 (setq ccl::*listener-autorelease-pool* (create-autorelease-pool)) 101 244 (ccl::listener-function)) 245 :echoing nil 102 246 :class 'cocoa-listener-process))) 103 247 (setf (slot-value proc 'input-stream) input-stream) 104 248 (setf (slot-value proc 'output-stream) output-stream) 105 (setf (slot-value proc 'input-peer-stream) peer-stream)106 249 (setf (slot-value proc 'window) window) 107 (setf (slot-value proc 'buffer) buffer)108 250 proc)) 109 110 251 111 252 (defclass hemlock-listener-frame (hemlock-frame) 112 253 () … … 116 257 117 258 (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 () 124 260 (:metaclass ns:+ns-object) 125 261 ) … … 133 269 134 270 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 server140 (let* ((fh (make-instance141 'ns:ns-file-handle142 :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) buffer149 (slot-value new 'bufsize) bufsize150 (slot-value new 'nextra) 0))151 (#/addObserver:selector:name:object:152 (#/defaultCenter ns:ns-notification-center)153 new154 (@selector #/gotData:)155 #&NSFileHandleReadCompletionNotification156 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) self163 (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 xlate187 total188 0)189 (let* ((string (make-string nchars)))190 (funcall (ccl::character-encoding-memory-decode-function encoding)191 xlate192 noctets-used193 0194 string)195 (unless (zerop (setq n (- total noctets-used)))196 ;; By definition, the number of untranslated octets197 ;; 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-operation203 buffer204 #'(lambda ()205 (unwind-protect206 (progn207 (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 218 271 (objc:defmethod #/windowTitleForDocumentDisplayName: ((self hemlock-listener-window-controller) name) 219 272 (let* ((doc (#/document self))) … … 221 274 (not (%null-ptr-p (#/fileURL doc)))) 222 275 (call-next-method name) 223 (let* ((buffer (hemlock- document-buffer doc))276 (let* ((buffer (hemlock-buffer doc)) 224 277 (bufname (if buffer (hi::buffer-name buffer)))) 225 278 (if bufname … … 232 285 233 286 (defclass hemlock-listener-document (hemlock-editor-document) 234 ()287 ((process :reader %hemlock-document-process :writer (setf hemlock-document-process))) 235 288 (:metaclass ns:+ns-object)) 236 289 (declaim (special hemlock-listener-document)) 237 290 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 238 299 (defmethod update-buffer-package ((doc hemlock-listener-document) buffer) 239 300 (declare (ignore buffer))) 240 301 241 (defmethod hi::document-encoding-name ((doc hemlock-listener-document))302 (defmethod document-encoding-name ((doc hemlock-listener-document)) 242 303 "UTF-8") 243 304 … …
