[Openmcl-devel] Hemlock ain't Fred

Gary Byers gb at clozure.com
Tue Oct 30 04:27:51 PDT 2007


You generally have to tell the display system that the buffer's being
changed and tell it when you're through making changes.

HI::BUFFER-DOCUMENT-BEGIN-EDITING and HI::BUFFER-DOCUMENT-END-EDITING
do that (they ultimately invoke #/beginEditing and #/endEditing on
the underlying NSTextStorage object, which is kind of a Hemlock buffer.)

So:

(defmacro editing-buffer ((buf b) &body body)
   `(let* ((,buf ,b)
           ;; Might as well hide this nonsense, too:
           (hi::*buffer-gap-context* (hi::buffer-gap-context ,buf)))
       (unwind-protect
            (progn
              (hi::buffer-document-begin-editing ,buf)
              ;; Safe to make changes in BODY.
              , at body)
         (hi::buffer-document-end-editing ,buf)))))

HI::*BUFFER-LIST* is (usually, mostly) a list of alternating echo-area
buffers and primary "document" buffers; if you open a new editor
window via cmd-n, that "document"'s buffer is in the CADR of that
list:

? (editing-buffer (b (cadr hi::*buffer-list*))
     (let* ((point ((hi::buffer-point b))))
       (hi::insert-string point "This is almost too much funk")
       ;; Whoops.  A typo ... or maybe not.
       (hi::delete-characters point -1) ; delete 1 char preceding point
       (hi::insert-character point #\!)))

I don't remember (if I ever knew) what the issues were with synchronizing
redisplay with buffer changes in FRED.  The issues here include the
fact that the redisplay code runs on a different thread than the listener
you're typing things into; it's a real (native) thread and can therefore
run concurrently with any thread that's making modifications to the
buffer.  It might be good if there was a layer that hid this from you
a bit better (and the plan is to introduce such a layer), and it might
also be good to have something like the EDITING-BUFFER above (so that
redisplay can be deferred until a set of editing changes is complete.)

Consider:

(defun mark-buffer (mark)
   "Return the buffer that contains MARK.  A mark might not have
    a containing line and a line might not have a containing buffer;
    error in either of those cases, to keep the example simple."
    (let* ((line (hi::mark-line mark)))
      (or (and line (hi::line-%buffer line))
          (error "~s is disembodied ..." mark))))

(defun insert-string-at-mark (mark string)
    (editing-buffer (b (mark-buffer mark))
      (hi::insert-string mark string)))

(defun delete-characters-at-mark (mark &optional (n 1))
    (editing-buffer (b (mark-buffer mark))
      (hi::delete-characters mark n)))

(defun insert-character-at-mark (mark char)
    (editing-buffer (b (mark-buffer mark))
      (hi::insert-character mark char)))

(defun too-much-fun (buffer)
   (let* ((point (hi::buffer-point buffer)))
     (insert-string-at-mark point "Hello, ")
     (sleep 1)
     (insert-string-at-mark point "ween!")))



On Tue, 30 Oct 2007, Ron Garret wrote:

> Aw geez, don't mind me.  Classes.  Structs.  Blarg.
>
> So I got all that squared away.  I can insert characters into a buffer
> now.  But when I try to delete them I get some, er, "interesting"
> results.  :-)
>
> rg
>
> On Oct 30, 2007, at 1:27 AM, Ron Garret wrote:
>
>> Guess I ought to RTFM.  This is explained in http://trac.clozure.com/openmcl/wiki/CocoaIdeInternals
>>
>> But now I'm stuck on this:
>>
>> ? (describe b)
>> #<Hemlock Buffer "Untitled 2">
>> Type: HEMLOCK-INTERNALS:BUFFER
>> Class: #<STRUCTURE-CLASS HEMLOCK-INTERNALS:BUFFER>
>> %NAME: "Untitled 2"
>> %REGION: #<Hemlock Region "">
>> %PATHNAME: NIL
>> MODES: ("Lisp" "Editor")
>> MODE-OBJECTS: (#<Hemlock Mode "Editor"> #<Hemlock Mode "Lisp">)
>> BINDINGS: #<HASH-TABLE :TEST EQL size 0/60 #x3000418D2E3D>
>> POINT: #<Hemlock Mark "^">
>> %MARK: #<Hemlock Mark "^">
>> REGION-ACTIVE: NIL
>> %WRITABLE: T
>> MODIFIED-TICK: -2
>> UNMODIFIED-TICK: -1
>> DOCUMENT: #<HEMLOCK-EDITOR-DOCUMENT <HemlockEditorDocument: 0xa6b3e70>
>> (#xA6B3E70)>
>> VAR-VALUES: #((#<Hemlock Variable-Object #1="Buffer Mark Ring">)
>>               #<Hemlock Variable-Object #1#>
>>               #((#<Hemlock Variable-Object #2="Current Package">)
>>                 #<Hemlock Variable-Object #2#> NIL HEMLOCK::CURRENT-
>> PACKAGE)
>>               HEMLOCK::BUFFER-MARK-RING)
>> VARIABLES: #<String Table>
>> WRITE-DATE: NIL
>> DISPLAY-START: #<Hemlock Mark "^">
>> %MODELINE-FIELDS: (#<Hemlock Modeline-field-info :MODIFIEDP>
>>                    #<Hemlock Modeline-field-info :EXTERNAL-FORMAT>
>>                    #<Hemlock Modeline-field-info :PACKAGE>
>>                    #<Hemlock Modeline-field-info :MODES>)
>> DELETE-HOOK: NIL
>> LINE-TERMINATION: :UNIX
>> PROCESS: NIL
>> GAP-CONTEXT: #S(HEMLOCK-INTERNALS::BUFFER-GAP-CONTEXT :LOCK
>> #<RECURSIVE-LOCK [ptr @ #xA6D6140] #x3000418D22DD>
>>                                                       :LEFT-OPEN-POS 0
>>                                                       :RIGHT-OPEN-
>> POS 0
>>                                                       :LINE-CACHE-
>> LENGTH 200
>>                                                       :OPEN-LINE NIL
>>                                                       :OPEN-CHARS
>> "
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>> PROTECTED-REGION: NIL
>> FONT-REGIONS: #<DLL-HEADER  #x3000418D2C7D>
>> ACTIVE-FONT-REGION: NIL
>> ? (slot-value b 'gap-context)
>>> Error: #<Hemlock Buffer "Untitled 2"> has no slot named GAP-CONTEXT.
>>> While executing: #<CCL::STANDARD-KERNEL-METHOD SLOT-MISSING (T T T
>> T)>, in process Listener(75).
>>> Type :POP to abort, :R for a list of available restarts.
>>> Type :? for other options.
>> 1 >
>>
>> On Oct 29, 2007, at 11:56 PM, Ron Garret wrote:
>>
>>> I'm trying to manipulate Hemlock windows in the new IDE the way I
>>> used
>>> to be able to manipulate Fred windows.  Turns out I can't just do
>>> e.g.
>>>
>>> (insert-string mark string)
>>>
>>> Instead I have to do this:
>>>
>>> (let ((HEMLOCK-INTERNALS::*BUFFER-GAP-CONTEXT* (hi::buffer-gap-
>>> context
>>> (line-buffer (mark-line mark)))))
>>> (insert-string mark "foo"))
>>>
>>> which is not a show stopper, but it's damned annoying.  What is this
>>> *BUFFER-GAP-CONTEXT* thing and why isn't it bound automatically?
>>>
>>> rg
>>>
>>> _______________________________________________
>>> Openmcl-devel mailing list
>>> Openmcl-devel at clozure.com
>>> http://clozure.com/mailman/listinfo/openmcl-devel
>>
>>
>> _______________________________________________
>> Openmcl-devel mailing list
>> Openmcl-devel at clozure.com
>> http://clozure.com/mailman/listinfo/openmcl-devel
>
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://clozure.com/mailman/listinfo/openmcl-devel
>
>



More information about the Openmcl-devel mailing list