[OS X Emacs] Removing the *scratch* buffer in Aquamacs

Adrian adrian.down at gmail.com
Mon Oct 13 13:40:12 EDT 2008


Well, I spent a weekend with Aquamacs and I got the opening of new files to
behave about as well as I can hope for.  I was interested primarily in three
issues, which are closely tied together: removing the scratch buffer,
automatically tiling new windows, and closing unmodified untitled windows
when they are overwritten by other buffers.  As a caveat before all of this,
I should mention that I operate in one-buffer-one-frame mode, and most of my
modifications will probably fail miserably outside of this mode.  I should
also confess that I am not very confident in these modifications, as they
seem like kludges operating on arcane Emacs numerology, but they seem to
work as far as I can tell on my Aquamacs distribution on my particular
computer.  There is a bit of window strobing as Emacs tries desperately to
misbehave and the hooks kill the undesired buffers, but everything seems to
work out after the dust settles.  I did all my modifications in tags that
are in my .emacs file, which I included at the end of this email.

Before I delve too deeply into this, there is one question that I still
have.  I have not been able to figure out how to affect the cursor focus
between Aquamacs frames.  When I open a new frame, I want the cursor to move
to that frame always, even if the frame was opened by invoking Aquamacs from
the command line.  Neither select-frame nor select-frame-set-focus seem to
have any effect.  I can access the desired buffer with set-buffer, and even
modify that buffer, but I can't put the actual cursor in that buffer.  Any
suggestions here?  Does Aquamacs have some other mechanism for handling
cursor position?

It turned out that the code path as buffers and frames are created and
destroyed is about as intuitive as riding a bicycle... going backwards,
blindfolded, and with no hands.  Okay, maybe not that bad, but still, not
very clear.  There is also some anomalous behaviour here and there.  Emacs
requires that a frame always be open.  If you try to kill all frames, Emacs
refuses.  The visibiliy of a frame "on the screen" does not seem to
correspond to the "visibility bit" that Emacs maintains for each frame.  In
particular, there is one frame that is not visible until selected by the
user (it usually appears as the last frame on the list).  This frame doesn't
inherit any of the default window properties.  For some reason, Emacs seems
to think that this is the only visible frame and will not allow me to close
it.

One of the biggest challenges in getting the behaviour I wanted was to
prevent Emacs from making this frame visible on the screen.  To do so, I
sometimes had to create dummy frames and then delete them later so that
Emacs was never left with only one frame (the unkillable default frame with
bad window properties) to choose from.

As for the scratch buffer, I agree that if the behaviour of Aquamacs with
regards to the scratch buffer should be an option.  If the user wants to
maintain the default scratch buffer just as it has always been, that option
should be available.  For those who never want to see the thing again, see
my code below.

I also implimented a feature that I've been wanting for a while, and which
also helps with window management: if an unmodified untitled buffer is open
and a user opens another file, the untitled buffer is closed.

Lastly, I moved the window tiling feature to the end of the whole
frame-creation routine.  I ended up killing and moving so many frames during
frame creation that it made much more sense to clean everything up at the
end.

Below is the relevant text from my .emacs file.  If there are any questions
about it or why I implimented things the way I did (believe me, I tried
many, many other methods), please feel free to comment.  Improvements are
definitely welcome!

Adrian

;; DEFAULT WINDOW CONFIG
;; set default window size and position, and tiling parameters

(setq width_in_chars 80)
(setq height_in_chars 77)
(setq initial_frame_left 997)
(setq n_tiles 2)
(setq frame_left_offset 400)

(setq initial-frame-alist
       `((left . ,initial_frame_left)
     (top . 0)
     (width . ,width_in_chars)
     (height . ,height_in_chars))
)
(setq default-frame-alist
       `((left . ,initial_frame_left)
     (top . 0)
     (width . ,width_in_chars)
     (height . ,height_in_chars))
)


;; HOOKS
;; all hook declarations at end of hooks section

;; initialization hook
;;    closes the scratch buffer and creates a blank buffer
(defun my-close-scratch ()
  (kill-buffer "*scratch*")
  (new-empty-buffer)
  (if (< 6 (length (buffer-list)))
      (kill-buffer "untitled")
  )
)

(defun my-emacs-startup-hook ()
  (my-close-scratch)
)

;; after-make-frame hook
;;   if any goofy system buffers have popped, close them
;;   then tile remaining windows

;; if the frame just made does not contain an emacs-owned buffer,
;; close any emacs-owned buffers
(setq first_frame t)
(defun my-close-system-frames (frame)
  (setq real_buff_count (- (length (buffer-list)) 6))
  (setq real_frame_count (- (length (frame-list)) 1))
  (setq real_count_diff (- real_frame_count real_buff_count))
  (setq i 0)
  (if (and (= real_count_diff 2)  (not first_frame))
    (delete-frame (nth 1 (frame-list)))
  )
  (setq first_frame nil)
)

(defun my-shift-frame (frame)
  (setq prev_frame (nth 1 (visible-frame-list)))
  (setq prev_frame_params (frame-parameters prev_frame))
  (setq prev_frame_left (cdr (nth 6 prev_frame_params)))
  (setq prev_shift_count (/ (- initial_frame_left prev_frame_left)
frame_left_offset))
  (setq new_shift_count (mod (1+ prev_shift_count) n_tiles))
  (setq new_frame_left (- initial_frame_left (* frame_left_offset
new_shift_count)))
  (set-frame-position frame new_frame_left 0)
)

;; checks to see if there are enough user-owned buffers to warrant tiling
;; called by after-make-frame hook launcher
(defun my-tile-windows (frame)
  (setq real_frame_count (- (length (visible-frame-list)) 1))
  (if (> real_frame_count 0)
      (my-shift-frame frame)
  )
)

(defun my-after-make-frame-functions (frame)
  (my-close-system-frames frame)
  (my-tile-windows frame)
)

;; find-file hook
;;    closes unused "untitled" buffers

;; if buffer with name buff_name has no unsaved changes, close it
;; called by my-close-untitled
(defun my-close-if-clean (buff_name)
  (setq buff (get-buffer buff_name))
  (if (not (buffer-modified-p buff))
     (kill-buffer buff)
  )
)
;; if there is an untitled buffer with no unsaved changes, close it
;; called by my-clean-untitled
(defun my-close-untitled ()
  (if (get-buffer "untitled")
    (my-close-if-clean "untitled")
  )
)

(defun my-find-file-hook ()
  (my-close-untitled)
)

; hook declarations
;    add functions in hook launch functions
(add-hook 'emacs-startup-hook 'my-emacs-startup-hook)
(add-hook 'after-make-frame-functions 'my-after-make-frame-functions)
(add-hook 'find-file-hook 'my-find-file-hook)

2008/10/11 David Reitter <david.reitter at gmail.com>

> On 11 Oct 2008, at 01:21, Adrian wrote:
>
>>
>> me to try to learn a bit of a new language and wade through source code to
>> try to achieve customized window positioning that probably wouldn't apply to
>> any other user, but for the sake of removing the scratch buffer, I'm more
>> game.
>>
>
> Make sure you know where to find documentation: the Emacs Lisp Reference,
> the internal docs (C-h f functionname RET, and C-h v variablename RET).
>
>  much agreement.  I've already made some of my case against the *scratch*
>> buffer, but I also feel that the *messages* buffer is better accessed in a
>> separate way than the other, user-created, buffers.  In particular, when I'm
>> switching between the active buffers, I almost never want to see the
>> *messages* buffer in a large frame window; it just gives me an extra key
>> press on my way to buffers I actually want to see.  Maybe others can correct
>> me on this?
>>
>
> Good idea.  Perhaps we can ensure that *Messages* is always moved to the
> end of the buffer list so that the cycling commands will not usually bring
> up a *Messages* buffer.  The same could be done for *scratch*.
>
>>
>>  However, the *scratch* buffer is sneakier than I anticipated: creating a
>> new frame containing the *scratch* buffer does not call the make-frame
>> hooks.
>>
>
> It shouldn't matter what the frame contains.  Works for me.
> Don't forget that the last frame is not deleted, but only hidden, so
> bringing it back up does not CREATE a frame - it merely makes is visible.
>
>  Even when the initial *scratch* frame is created, these hooks are not
>> invoked.
>>
>
> Where do you add to the hook?  Have you considered the order of execution?
>
>
> _____________________________________________________________
> MacOSX-Emacs mailing list
> MacOSX-Emacs at email.esm.psu.edu
> http://email.esm.psu.edu/mailman/listinfo/macosx-emacs
> List Archives: http://dir.gmane.org/gmane.emacs.macintosh.osx
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://email.esm.psu.edu/pipermail/macosx-emacs/attachments/20081013/90d39c14/attachment.html>


More information about the MacOSX-Emacs mailing list