Package: emacs;
Reported by: Keith David Bershatsky <esq <at> lawlist.com>
Date: Mon, 26 Aug 2013 00:52:02 UTC
Severity: normal
Found in version 24.3.50
Done: Glenn Morris <rgm <at> gnu.org>
Bug is archived. No further changes may be made.
To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 15189 in the body.
You can then email your comments to 15189 AT debbugs.gnu.org in the normal way.
Toggle the display of automated, internal messages from the tracker.
View this report as an mbox folder, status mbox, maintainer mbox
bug-gnu-emacs <at> gnu.org
:bug#15189
; Package emacs
.
(Mon, 26 Aug 2013 00:52:02 GMT) Full text and rfc822 format available.Keith David Bershatsky <esq <at> lawlist.com>
:bug-gnu-emacs <at> gnu.org
.
(Mon, 26 Aug 2013 00:52:02 GMT) Full text and rfc822 format available.Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Keith David Bershatsky <esq <at> lawlist.com> To: bug-gnu-emacs <at> gnu.org Subject: 24.3.50; display-buffer does not work well with custom frames. Date: Sun, 25 Aug 2013 17:50:43 -0700
The documentation for (display-buffer) uses an example with (get-buffer-create "*foo*"): http://www.gnu.org/software/emacs/manual/html_node/elisp/Display-Action-Functions.html This does not work well with find-file in conjunction with several frames because find-file is executed BEFORE custom frame functions are run. The result is that the buffer that initially had focus ends up getting buried even though the file being opened is in a new frame. The only reliable workaround appears to be calling the find-file command AFTER the custom frame functions are run, which (in my lay opinion) defeats the purpose of using display-buffer. If the display-buffer function was never intended by the developers to be used with find-file and custom frames, then perhaps this email could be treated as a feature request "wish-list" instead of being treated as a bug report. Below is a detailed example that demonstrates what I am experiencing -- just plug it in and run the function "example". Here is a link to a working example that does not use display-buffer: http://stackoverflow.com/questions/18346785/how-to-intercept-a-file-before-it-opens-and-decide-which-frame ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun example () (interactive) (custom-find-file "*bar*") (set-frame-position (selected-frame) 0 0) (mark-whole-buffer) (delete-region (region-beginning) (region-end)) (insert "\*bar\* is about to be buried.") (message "\*bar\* is about to be buried.") (sit-for 3) (custom-find-file "foo.txt") (set-frame-position (selected-frame) 100 100) (mark-whole-buffer) (delete-region (region-beginning) (region-end)) (insert "\"foo.txt\" is about to be buried.") (message "\"foo.txt\" is about to be buried.") (sit-for 3) (custom-find-file "doe.org") (set-frame-position (selected-frame) 200 200) (mark-whole-buffer) (delete-region (region-beginning) (region-end)) (insert "\"doe.org\" is about to be buried.") (message "\"doe.org\" is about to be buried.") (sit-for 3) (custom-find-file "*undefined*") (set-frame-position (selected-frame) 300 300) (mark-whole-buffer) (delete-region (region-beginning) (region-end)) (insert "\*undefined\* is now visible in two (2) frames.") (message "\*undefined\* is now visible in two (2) frames.") ) (defvar lawlist-system-buffer-regexp nil "Regexps matching `buffer-filename` for frame name `SYSTEM`.") (setq lawlist-system-buffer-regexp '("*scratch*" "*bar*")) (defvar lawlist-main-buffer-regexp nil "Regexps matching `buffer-filename` for frame name `MAIN`.") (setq lawlist-main-buffer-regexp '("\\.txt" "\\.tex" "\\.el" "\\.yasnippet")) (defvar lawlist-org-buffer-regexp nil "Regexps matching `buffer-filename` for frame name `ORG`.") (setq lawlist-org-buffer-regexp '("[*]todo-list[*]" "\\.org_archive" "\\.org")) (defun lawlist-regexps-match-p (regexps string) (catch 'matched (dolist (regexp regexps) (if (string-match regexp string) (throw 'matched t))))) (defvar buffer-filename nil) (defun custom-find-file (&optional buffer-filename) "Locate or create a specific frame, and then open the file." (interactive) (unless buffer-filename (setq buffer-filename (read-file-name "Select File: "))) (if buffer-filename (display-buffer (find-file buffer-filename)))) (defun lawlist-display-buffer-function (&optional buffer flag) (if buffer-filename (progn (when (lawlist-regexps-match-p lawlist-org-buffer-regexp buffer-filename) (if (frame-exists "ORG") (switch-to-frame "ORG") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (and (not (equal "MAIN" (frame-parameter frame 'name))) (not (equal "SYSTEM" (frame-parameter frame 'name))) (not (equal "ORG" (frame-parameter frame 'name))) (not (equal "WANDERLUST" (frame-parameter frame 'name))) (not (equal "MISCELLANEOUS" (frame-parameter frame 'name))) ) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "ORG")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "ORG")) (progn (make-frame) (set-frame-name "ORG"))) )) (when (lawlist-regexps-match-p lawlist-main-buffer-regexp buffer-filename) (if (frame-exists "MAIN") (switch-to-frame "MAIN") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (and (not (equal "MAIN" (frame-parameter frame 'name))) (not (equal "SYSTEM" (frame-parameter frame 'name))) (not (equal "ORG" (frame-parameter frame 'name))) (not (equal "WANDERLUST" (frame-parameter frame 'name))) (not (equal "MISCELLANEOUS" (frame-parameter frame 'name))) ) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "MAIN")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "MAIN")) (progn (make-frame) (set-frame-name "MAIN"))) )) (when (lawlist-regexps-match-p lawlist-system-buffer-regexp buffer-filename) (if (frame-exists "SYSTEM") (switch-to-frame "SYSTEM") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (and (not (equal "MAIN" (frame-parameter frame 'name))) (not (equal "SYSTEM" (frame-parameter frame 'name))) (not (equal "ORG" (frame-parameter frame 'name))) (not (equal "WANDERLUST" (frame-parameter frame 'name))) (not (equal "MISCELLANEOUS" (frame-parameter frame 'name))) ) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "SYSTEM")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "SYSTEM")) (progn (make-frame) (set-frame-name "SYSTEM"))) )) (when (and (not (lawlist-regexps-match-p lawlist-org-buffer-regexp buffer-filename)) (not (lawlist-regexps-match-p lawlist-main-buffer-regexp buffer-filename)) (not (lawlist-regexps-match-p lawlist-system-buffer-regexp buffer-filename)) ) (if (frame-exists "MISCELLAENOUS") (switch-to-frame "MISCELLAENOUS") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (and (not (equal "MAIN" (frame-parameter frame 'name))) (not (equal "SYSTEM" (frame-parameter frame 'name))) (not (equal "ORG" (frame-parameter frame 'name))) (not (equal "WANDERLUST" (frame-parameter frame 'name))) (not (equal "MISCELLANEOUS" (frame-parameter frame 'name))) ) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "MISCELLAENEOUS")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "MISCELLAENEOUS")) (progn (make-frame) (set-frame-name "MISCELLAENEOUS")))))))) (setq display-buffer-function 'lawlist-display-buffer-function) (defun frame-exists (frame-name) (not (eq nil (get-frame frame-name)))) (defun get-frame-name (&optional frame) "Return the string that names FRAME (a frame). Default is selected frame." (unless frame (setq frame (selected-frame))) (if (framep frame) (cdr (assq 'name (frame-parameters frame))) (error "Function `get-frame-name': Argument not a frame: `%s'" frame))) (defun get-frame (frame) "Return a frame, if any, named FRAME (a frame or a string). If none, return nil. If FRAME is a frame, it is returned." (cond ((framep frame) frame) ((stringp frame) (catch 'get-a-frame-found (dolist (fr (frame-list)) (when (string= frame (get-frame-name fr)) (throw 'get-a-frame-found fr))) nil)) (t (error "Function `get-frame-name': Arg neither a string nor a frame: `%s'" frame)))) (defun switch-to-frame (frame-name) (let ((frames (frame-list))) (catch 'break (while frames (let ((frame (car frames))) (if (equal (frame-parameter frame 'name) frame-name) (throw 'break (select-frame-set-input-focus frame)) (setq frames (cdr frames)))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; In GNU Emacs 24.3.50.1 (x86_64-apple-darwin10.8.0, NS apple-appkit-1038.36) of 2013-08-22 on MP.local Bzr revision: 113971 monnier <at> iro.umontreal.ca-20130822040645-0fc4fi87eir72jnb Windowing system distributor `Apple', version 10.3.1038 Configured using: `configure --with-ns' Important settings: locale-coding-system: nil default enable-multibyte-characters: t Major mode: Text Minor modes in effect: whitespace-mode: t yas-global-mode: t yas-minor-mode: t global-highlight-parentheses-mode: t global-linum-mode: t linum-mode: t delete-selection-mode: t flyspell-mode: t frame-bufs-mode: t tabbar-mode: t highlight-parentheses-mode: t osx-key-mode: t tooltip-mode: t mouse-wheel-mode: t menu-bar-mode: t file-name-shadow-mode: t global-font-lock-mode: t font-lock-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t line-number-mode: t global-visual-line-mode: t visual-line-mode: t transient-mark-mode: t Recent input: <escape> x e x a m p l e <return> s-w s-w s-w s-w s-w s-w s-w y s-w s-w s-w y s-w s-w s-w s-w s-w s-w s-o <menu-bar> <help-menu> <send-emacs-bug-report> Recent messages: Word wrapping enabled *beep* Beginning of buffer *beep* Beginning of buffer Load-path shadows: ~/.0.data/.0.emacs/elpa/flim/md4 hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/md4 ~/.0.data/.0.emacs/elpa/flim/hex-util hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/hex-util ~/.0.data/.0.emacs/elpa/flim/sasl hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/net/sasl ~/.0.data/.0.emacs/elpa/flim/sasl-ntlm hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/net/sasl-ntlm ~/.0.data/.0.emacs/elpa/flim/sasl-digest hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/net/sasl-digest ~/.0.data/.0.emacs/elpa/flim/sasl-cram hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/net/sasl-cram ~/.0.data/.0.emacs/elpa/flim/ntlm hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/net/ntlm ~/.0.data/.0.emacs/elpa/flim/hmac-md5 hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/net/hmac-md5 ~/.0.data/.0.emacs/elpa/flim/hmac-def hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/net/hmac-def ~/.0.data/.0.emacs/elpa/wanderlust/rfc2368 hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/mail/rfc2368 ~/.0.data/.0.emacs/elpa/wanderlust/utf7 hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/gnus/utf7 ~/.0.data/.0.emacs/elpa/semi/smime hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/gnus/smime ~/.0.data/.0.emacs/elpa/el-get/.dir-locals hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/gnus/.dir-locals ~/.0.data/.0.emacs/elpa/semi/pgg hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/obsolete/pgg ~/.0.data/.0.emacs/elpa/semi/pgg-pgp5 hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/obsolete/pgg-pgp5 ~/.0.data/.0.emacs/elpa/semi/pgg-pgp hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/obsolete/pgg-pgp ~/.0.data/.0.emacs/elpa/semi/pgg-parse hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/obsolete/pgg-parse ~/.0.data/.0.emacs/elpa/semi/pgg-gpg hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/obsolete/pgg-gpg ~/.0.data/.0.emacs/elpa/semi/pgg-def hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/obsolete/pgg-def ~/.0.data/.0.emacs/elpa/utilities/longlines hides /Users/HOME/.0.data/.0.emacs/Emacs.app/Contents/Resources/lisp/obsolete/longlines Features: (shadow wl-mime mime-edit pgg-parse pccl pccl-20 signature mime-setup mail-mime-setup semi-setup mime-pgp pgg-def mime-play filename mime-image modb-standard elmo-imap4 time-stamp emacsbug message rfc822 mml mml-sec mm-decode mm-bodies mm-encode mailabbrev gmm-utils mailheader org-wl org-w3m org-vm org-rmail org-mhe org-mew org-irc org-jsinfo org-infojs org-html org-exp ob-exp org-exp-blocks org-agenda org-info org-gnus org-docview org-bibtex bibtex org-bbdb disp-table whitespace yasnippet wl-demo wl-draft eword-encode wl-template sendmail mail-utils elmo-net elmo-cache elmo-map elmo-dop wl-news wl-address wl-thread wl-folder wl wl-e21 bbdb-autoloads bbdb el-get el-get-autoloads el-get-list-packages el-get-notify help-mode el-get-dependencies el-get-build el-get-status el-get-recipes el-get-byte-compile el-get-methods el-get-fossil el-get-svn el-get-pacman el-get-github-zip el-get-github-tar el-get-http-zip el-get-http-tar el-get-hg el-get-git-svn el-get-fink el-get-emacswiki el-get-http el-get-emacsmirror el-get-github el-get-git el-get-elpa el-get-darcs el-get-cvs el-get-bzr el-get-brew el-get-builtin el-get-apt-get el-get-custom el-get-core autoload lisp-mnt savehist itunes osx-osascript linum delsel server multiple-cursors mc-separate-operations rectangular-region-mode mc-mark-more thingatpt mc-cycle-cursors mc-edit-lines multiple-cursors-core rect flyspell ispell saveplace auto-save-buffers-enhanced auctex-autoloads tex-site info multiple-cursors-autoloads yasnippet-autoloads package desktop frameset init-tabbar init-frames tabbar frame-cmds frame-fns avoid calendar-lawlist lawlist-calendar init-org derived cl-macs gv edmacro kmacro org-toodledo mailcap-toodledo http-post-simple cl url-http tls url-auth mail-parse rfc2231 rfc2047 rfc2045 ietf-drums url-gw url url-proxy url-privacy url-expand url-methods url-history url-cookie url-domsuf url-util url-parse auth-source eieio eieio-core gnus-util mm-util mail-prsvr password-cache url-vars mailcap json xml org ob-tangle ob-ref ob-lob ob-table org-footnote org-src ob-comint ob-keys org-pcomplete pcomplete comint ansi-color ring org-list org-faces org-entities noutline outline org-version ob-emacs-lisp ob org-compat org-macs ob-eval org-loaddefs format-spec find-func cal-menu calendar cal-loaddefs init-yas init-wl lawlist-tls wl-spam wl-action wl-summary byte-opt ps-print ps-def lpr wl-refile wl-util pp elmo-flag elmo-localdir bytecomp byte-compile cconv wl-message elmo-mime mmelmo-buffer mmelmo-imap mime-view mime-conf calist semi-def mmimap mime-parse mmbuffer mmgeneric wl-highlight wl-vars wl-version epg-config elmo-multi elmo-spam elsp-header elsp-generic elmo elmo-signal elmo-msgdb modb modb-generic modb-entity mime elmo-util emu invisible inv-23 poem poem-e20 poem-e20_3 utf7 eword-decode mel mime-def alist std11 mcharset mcs-20 mcs-e20 pces pces-e20 pces-20 broken pcustom elmo-date elmo-vars elmo-version path-util poe pym static apel-ver product luna mime-w3m w3m-load w3m browse-url doc-view jka-compr dired image-mode timezone w3m-hist w3m-fb bookmark-w3m w3m-ems wid-edit cl-loaddefs cl-lib w3m-ccl ccl w3m-favicon w3m-image w3m-proc w3m-util hideshow easymenu highlight-parentheses init-osxkeys easy-mmode redo advice help-fns time-date tooltip ediff-hook vc-hooks lisp-float-type mwheel ns-win tool-bar dnd fontset image regexp-opt fringe tabulated-list newcomment lisp-mode prog-mode register page menu-bar rfn-eshadow timer select scroll-bar mouse jit-lock font-lock syntax facemenu font-core frame cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese case-table epa-hook jka-cmpr-hook help simple abbrev minibuffer nadvice loaddefs button faces cus-face macroexp files text-properties overlay sha1 md5 base64 format env code-pages mule custom widget hashtable-print-readable backquote make-network-process ns multi-tty emacs)
bug-gnu-emacs <at> gnu.org
:bug#15189
; Package emacs
.
(Mon, 26 Aug 2013 13:07:04 GMT) Full text and rfc822 format available.Message #8 received at 15189 <at> debbugs.gnu.org (full text, mbox):
From: martin rudalics <rudalics <at> gmx.at> To: Keith David Bershatsky <esq <at> lawlist.com> Cc: 15189 <at> debbugs.gnu.org Subject: Re: bug#15189: 24.3.50; display-buffer does not work well with custom frames. Date: Mon, 26 Aug 2013 15:06:48 +0200
> This does not work well with find-file in conjunction with several > frames because find-file is executed BEFORE custom frame functions are > run. The result is that the buffer that initially had focus ends up > getting buried even though the file being opened is in a new frame. > The only reliable workaround appears to be calling the find-file > command AFTER the custom frame functions are run, which (in my lay > opinion) defeats the purpose of using display-buffer. IIUC you want to make `find-file' behave like `find-file-other-frame' by default. Is that correct? Or what am I missing? martin
bug-gnu-emacs <at> gnu.org
:bug#15189
; Package emacs
.
(Mon, 26 Aug 2013 15:02:02 GMT) Full text and rfc822 format available.Message #11 received at 15189 <at> debbugs.gnu.org (full text, mbox):
From: martin rudalics <rudalics <at> gmx.at> To: 15189 <at> debbugs.gnu.org Subject: Re: bug#15189: 24.3.50; display-buffer does not work well with custom frames. Date: Mon, 26 Aug 2013 17:01:24 +0200
> Yes, that is correct -- with the additional magic of > lawlist-display-buffer-function. My workaround is simply calling > find-file at the very end of the lawlist-display-buffer-function, > which defeats the purpose of using display-buffer. You mean here? (display-buffer (find-file buffer-filename)) Why can't you use (display-buffer (find-file-noselect buffer-filename)) instead? martin
bug-gnu-emacs <at> gnu.org
:bug#15189
; Package emacs
.
(Mon, 26 Aug 2013 16:35:01 GMT) Full text and rfc822 format available.Message #14 received at 15189 <at> debbugs.gnu.org (full text, mbox):
From: martin rudalics <rudalics <at> gmx.at> To: Keith David Bershatsky <esq <at> lawlist.com> Cc: 15189 <at> debbugs.gnu.org Subject: Re: bug#15189: 24.3.50; display-buffer does not work well with custom frames. Date: Mon, 26 Aug 2013 18:34:33 +0200
Please keep 15189 <at> debbugs.gnu.org CCed so others can read your mails too. > Yes, that works now if we also add the following line to the end of > lawlist-display-buffer-function: (switch-to-buffer (get-file-buffer > buffer-filename)) I'm still not quite sure whether I understand what you want to do. An idiom like (display-buffer (find-file buffer-filename)) is practically always wrong because it usually will (1) display the buffer via `find-file' which calls `switch-to-buffer' which bypasses `display-buffer' by calling `set-window-buffer' directly and (2) display the buffer a second time which might result in reusing the window used in (1) but may also use another window according to your buffer display settings. In any case, a doc-string like "Locate or create a specific frame, and then open the file." is inappropriate because the function nowhere does what you say here. > I expected display-buffer to execute the display-buffer-function first > in time (e.g., before executing find-file), but that is not the case. I'm afraid you're confusing things here. `display-buffer' does execute `display-buffer-function' first but its arguments get evaluated before its body. This is something you certainly want too because how would `display-buffer' otherwise know the buffer it is supposed to display? > If the purpose of display-buffer is not to execute the > display-buffer-function first in time (e.g., before executing > find-file), then I made an erroneous assumption regarding the reason > for using display-buffer. I suppose you made the erroneous assumption that `find-file' does not display the file's buffer. That's why I suggested to use `find-file-noselect' instead. Anyway, using `display-buffer-function' is deprecated since Emacs 24.3 and was hardly used in previous versions. What you probably want to do is to customize `display-buffer-alist' instead. martin
bug-gnu-emacs <at> gnu.org
:bug#15189
; Package emacs
.
(Mon, 26 Aug 2013 20:16:02 GMT) Full text and rfc822 format available.Message #17 received at 15189 <at> debbugs.gnu.org (full text, mbox):
From: Keith David Bershatsky <esq <at> lawlist.com> To: martin rudalics <rudalics <at> gmx.at> Cc: 15189 <at> debbugs.gnu.org Subject: Re: bug#15189: 24.3.50; display-buffer does not work well with custom frames. Date: Mon, 26 Aug 2013 13:15:09 -0700
Thank you for the clarification. My goal is to cover the two common types of situations: * File is opened -- creating a new one, or opening one that already exists. * Buffer is created without opening a specific file. It appears that display-buffer-alist ONLY works for some of the no-file buffers, like *Help*. Files that are opened get ignored by the display-buffer-alist. Using your suggestion of find-file-noselect works well with the initial example, and then just adding (switch-to-buffer (get-file-buffer buffer-filename)) to the tail end of the lawlist-display-buffer-function. So, correct please if I wrong, it appears that a different solution is needed for each of the two scenarios. Here is the code that works for display-buffer-alist, but not for actual files being opened. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defvar system-nofile-regexp nil "Regexps matching `buffer-filename` for frame name `SYSTEM`.") (setq system-nofile-regexp '("\\(\\*Metahelp\\*\\|\\*Help\\*\\)")) (defvar main-nofile-regexp nil "Regexps matching `buffer-filename` for frame name `MAIN`.") (setq main-nofile-regexp '("\\.pdf")) (defvar org-nofile-regexp nil "Regexps matching `buffer-filename` for frame name `ORG`.") (setq org-nofile-regexp '("\\*Org Agenda\\*")) (setq display-buffer-alist `((lawlist-p . (nofile-display-buffer-pop-up-frame)))) (defun lawlist-p (buffer action) (declare (ignore action)) (let ((buffer (get-buffer buffer))) (or (lawlist-regexps-match-p org-nofile-regexp (buffer-name buffer)) (lawlist-regexps-match-p main-nofile-regexp (buffer-name buffer)) (lawlist-regexps-match-p system-nofile-regexp (buffer-name buffer)) ))) (defun nofile-display-buffer-pop-up-frame (buffer alist) (when (lawlist-regexps-match-p org-nofile-regexp (buffer-name buffer)) (if (frame-exists "ORG") (switch-to-frame "ORG") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (and (not (equal "MAIN" (frame-parameter frame 'name))) (not (equal "SYSTEM" (frame-parameter frame 'name))) (not (equal "ORG" (frame-parameter frame 'name))) (not (equal "WANDERLUST" (frame-parameter frame 'name))) (not (equal "MISCELLANEOUS" (frame-parameter frame 'name))) ) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "ORG") (toggle-frame-maximized)))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "ORG")) (progn (make-frame) (set-frame-name "ORG") (toggle-frame-maximized))) )) (when (lawlist-regexps-match-p main-nofile-regexp (buffer-name buffer)) (if (frame-exists "MAIN") (switch-to-frame "MAIN") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (and (not (equal "MAIN" (frame-parameter frame 'name))) (not (equal "SYSTEM" (frame-parameter frame 'name))) (not (equal "ORG" (frame-parameter frame 'name))) (not (equal "WANDERLUST" (frame-parameter frame 'name))) (not (equal "MISCELLANEOUS" (frame-parameter frame 'name))) ) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "MAIN") (toggle-frame-maximized)))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "MAIN")) (progn (make-frame) (set-frame-name "MAIN") (toggle-frame-maximized))) )) (when (lawlist-regexps-match-p system-nofile-regexp (buffer-name buffer)) (if (frame-exists "SYSTEM") (switch-to-frame "SYSTEM") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (and (not (equal "MAIN" (frame-parameter frame 'name))) (not (equal "SYSTEM" (frame-parameter frame 'name))) (not (equal "ORG" (frame-parameter frame 'name))) (not (equal "WANDERLUST" (frame-parameter frame 'name))) (not (equal "MISCELLANEOUS" (frame-parameter frame 'name))) ) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "SYSTEM") (toggle-frame-maximized)))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "SYSTEM")) (progn (make-frame) (set-frame-name "SYSTEM") (toggle-frame-maximized))) )) (when (and (not (lawlist-regexps-match-p org-nofile-regexp (buffer-name buffer))) (not (lawlist-regexps-match-p main-nofile-regexp (buffer-name buffer))) (not (lawlist-regexps-match-p system-nofile-regexp (buffer-name buffer))) ) (if (frame-exists "MISCELLAENOUS") (switch-to-frame "MISCELLAENOUS") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (and (not (equal "MAIN" (frame-parameter frame 'name))) (not (equal "SYSTEM" (frame-parameter frame 'name))) (not (equal "ORG" (frame-parameter frame 'name))) (not (equal "WANDERLUST" (frame-parameter frame 'name))) (not (equal "MISCELLANEOUS" (frame-parameter frame 'name))) ) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "MISCELLAENEOUS") (toggle-frame-maximized)))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "MISCELLAENEOUS")) (progn (make-frame) (set-frame-name "MISCELLAENEOUS") (toggle-frame-maximized))))) (if (and (featurep 'init-frames) frame-bufs-mode) (frame-bufs-add-buffer buffer (selected-frame))) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GENERIC FRAME UTILITIES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun frame-exists (frame-name) (not (eq nil (get-frame frame-name)))) (defun get-frame-name (&optional frame) "Return the string that names FRAME (a frame). Default is selected frame." (unless frame (setq frame (selected-frame))) (if (framep frame) (cdr (assq 'name (frame-parameters frame))) (error "Function `get-frame-name': Argument not a frame: `%s'" frame))) (defun get-frame (frame) "Return a frame, if any, named FRAME (a frame or a string). If none, return nil. If FRAME is a frame, it is returned." (cond ((framep frame) frame) ((stringp frame) (catch 'get-a-frame-found (dolist (fr (frame-list)) (when (string= frame (get-frame-name fr)) (throw 'get-a-frame-found fr))) nil)) (t (error "Function `get-frame-name': Arg neither a string nor a frame: `%s'" frame)))) (defun switch-to-frame (frame-name) (let ((frames (frame-list))) (catch 'break (while frames (let ((frame (car frames))) (if (equal (frame-parameter frame 'name) frame-name) (throw 'break (select-frame-set-input-focus frame)) (setq frames (cdr frames)))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; At Mon, 26 Aug 2013 18:34:33 +0200, martin rudalics wrote: > > Please keep 15189 <at> debbugs.gnu.org CCed so others can read your mails > too. > > > Yes, that works now if we also add the following line to the end of > > lawlist-display-buffer-function: (switch-to-buffer (get-file-buffer > > buffer-filename)) > > I'm still not quite sure whether I understand what you want to do. > An idiom like > > (display-buffer > (find-file buffer-filename)) > > is practically always wrong because it usually will (1) display the > buffer via `find-file' which calls `switch-to-buffer' which bypasses > `display-buffer' by calling `set-window-buffer' directly and (2) display > the buffer a second time which might result in reusing the window used > in (1) but may also use another window according to your buffer display > settings. In any case, a doc-string like > > "Locate or create a specific frame, and then open the file." > > is inappropriate because the function nowhere does what you say here. > > > I expected display-buffer to execute the display-buffer-function first > > in time (e.g., before executing find-file), but that is not the case. > > I'm afraid you're confusing things here. `display-buffer' does execute > `display-buffer-function' first but its arguments get evaluated before > its body. This is something you certainly want too because how would > `display-buffer' otherwise know the buffer it is supposed to display? > > > If the purpose of display-buffer is not to execute the > > display-buffer-function first in time (e.g., before executing > > find-file), then I made an erroneous assumption regarding the reason > > for using display-buffer. > > I suppose you made the erroneous assumption that `find-file' does not > display the file's buffer. That's why I suggested to use > `find-file-noselect' instead. Anyway, using `display-buffer-function' > is deprecated since Emacs 24.3 and was hardly used in previous versions. > What you probably want to do is to customize `display-buffer-alist' > instead. > > martin
bug-gnu-emacs <at> gnu.org
:bug#15189
; Package emacs
.
(Tue, 27 Aug 2013 06:48:02 GMT) Full text and rfc822 format available.Message #20 received at 15189 <at> debbugs.gnu.org (full text, mbox):
From: martin rudalics <rudalics <at> gmx.at> To: Keith David Bershatsky <esq <at> lawlist.com> Cc: 15189 <at> debbugs.gnu.org Subject: Re: bug#15189: 24.3.50; display-buffer does not work well with custom frames. Date: Tue, 27 Aug 2013 08:47:19 +0200
> Using your suggestion of find-file-noselect works well with the initial example, and then just adding (switch-to-buffer (get-file-buffer buffer-filename)) to the tail end of the lawlist-display-buffer-function. If you want to show a file-visiting buffer in the selected window, yes. I'd rather add a rule that calls `display-buffer-same-window' and rewrite the code (when (lawlist-regexps-match-p ...) ...) (when (lawlist-regexps-match-p ...) ...) as (cond ((lawlist-regexps-match-p ...) ...) ((lawlist-regexps-match-p ...) ...) (t (display-buffer-same-window ...))) BTW you should also make code like (if (and (not (equal "MAIN" (frame-parameter frame 'name))) (not (equal "SYSTEM" (frame-parameter frame 'name))) (not (equal "ORG" (frame-parameter frame 'name))) (not (equal "WANDERLUST" (frame-parameter frame 'name))) (not (equal "MISCELLANEOUS" (frame-parameter frame 'name))) ) more readable by defining a variable like (defvar my-regexp "^\\(?:MAIN\\|SYSTEM\\|ORG\\|WANDERLUST\\| MISCELLANEOUS\\)$" "My doc-string.") and using (not (string-match my-regexp (frame-parameter frame 'name))) instead. martin
bug-gnu-emacs <at> gnu.org
:bug#15189
; Package emacs
.
(Tue, 27 Aug 2013 22:31:02 GMT) Full text and rfc822 format available.Message #23 received at 15189 <at> debbugs.gnu.org (full text, mbox):
From: Keith David Bershatsky <esq <at> lawlist.com> To: martin rudalics <rudalics <at> gmx.at> Cc: 15189 <at> debbugs.gnu.org Subject: Re: bug#15189: 24.3.50; display-buffer does not work well with custom frames. Date: Tue, 27 Aug 2013 15:30:09 -0700
Thank you for the suggestions and examples -- greatly appreciated !!! Here is the revised code that appears to be working correctly for both types of situations -- i.e., file-visiting buffers, and nofile-visiting buffers. Keith ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; EXAMPLE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun example () (interactive) (custom-find-file "*bar*") (set-frame-position (selected-frame) 0 0) (minibuffer-message "\*bar\* appears in frame name SYSTEM.") (sit-for 3) (custom-find-file "foo.txt") (set-frame-position (selected-frame) 100 100) (minibuffer-message "\"foo.txt\" appears in frame name MAIN.") (sit-for 3) (custom-find-file "doe.org") (set-frame-position (selected-frame) 200 200) (minibuffer-message "\"doe.org\" appears in frame name ORG.") (sit-for 3) (custom-find-file "*undefined*") (set-frame-position (selected-frame) 300 300) (minibuffer-message "\*undefined\* appears in frame name MISCELLANEOUS.") (sit-for 3) (display-buffer (get-buffer-create "*example*")) (other-window 1) (minibuffer-message "display-buffer-alist controls where \*example\* is displayed.") (sit-for 3) (kill-buffer "*bar*") (kill-buffer "foo.txt") (kill-buffer "doe.org") (kill-buffer "*undefined*") (kill-buffer "*example*") (make-frame) (delete-frame (get-frame "SYSTEM")) (delete-frame (get-frame "MAIN")) (delete-frame (get-frame "ORG")) (delete-frame (get-frame "MISCELLANEOUS"))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; FILE-VISITING BUFFER ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defvar lawlist-regexp-frame-names "^\\(?:MAIN\\|SYSTEM\\|ORG\\|MISCELLANEOUS\\)$" "Regexp matching frames with specific names.") (defvar lawlist-system-buffer-regexp nil "Regexps matching `buffer-filename` for frame name `SYSTEM`.") (setq lawlist-system-buffer-regexp '("*scratch*" "*bar*")) (defvar lawlist-main-buffer-regexp nil "Regexps matching `buffer-filename` for frame name `MAIN`.") (setq lawlist-main-buffer-regexp '("\\.txt" "\\.tex" "\\.el" "\\.yasnippet")) (defvar lawlist-org-buffer-regexp nil "Regexps matching `buffer-filename` for frame name `ORG`.") (setq lawlist-org-buffer-regexp '("[*]todo-list[*]" "\\.org_archive" "\\.org")) (defvar buffer-filename nil) (defun custom-find-file (&optional buffer-filename) "Locate or create a specific frame, and then open the file." (interactive) (unless buffer-filename (setq buffer-filename (read-file-name "Select File: "))) (if buffer-filename (progn (setq display-buffer-function 'lawlist-display-buffer-function) (display-buffer (find-file-noselect buffer-filename)) (setq display-buffer-function nil) ))) (defun lawlist-display-buffer-function (&optional buffer flag) (if buffer-filename (progn (cond ((lawlist-regexp-match-p lawlist-org-buffer-regexp buffer-filename) (if (frame-exists "ORG") (switch-to-frame "ORG") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "ORG")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "ORG")) (progn (make-frame) (set-frame-name "ORG"))) )) ((lawlist-regexp-match-p lawlist-main-buffer-regexp buffer-filename) (if (frame-exists "MAIN") (switch-to-frame "MAIN") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "MAIN")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "MAIN")) (progn (make-frame) (set-frame-name "MAIN"))) )) ((lawlist-regexp-match-p lawlist-system-buffer-regexp buffer-filename) (if (frame-exists "SYSTEM") (switch-to-frame "SYSTEM") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "SYSTEM")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "SYSTEM")) (progn (make-frame) (set-frame-name "SYSTEM"))) )) ((and (not (lawlist-regexp-match-p lawlist-org-buffer-regexp buffer-filename)) (not (lawlist-regexp-match-p lawlist-main-buffer-regexp buffer-filename)) (not (lawlist-regexp-match-p lawlist-system-buffer-regexp buffer-filename)) ) (if (frame-exists "MISCELLANEOUS") (switch-to-frame "MISCELLANEOUS") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "MISCELLANEOUS")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "MISCELLANEOUS")) (progn (make-frame) (set-frame-name "MISCELLANEOUS"))))) (t (display-buffer-same-window))) (switch-to-buffer (get-file-buffer buffer-filename)) ))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DISPLAY BUFFER NO FILE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defvar system-nofile-regexp nil "Regexps matching `buffer-name buffer` for frame name `SYSTEM`.") (setq system-nofile-regexp '("\\(\\*Metahelp\\*\\|\\*Help\\*\\)")) (defvar main-nofile-regexp nil "Regexps matching `buffer-name buffer` for frame name `MAIN`.") (setq main-nofile-regexp '("\\*example\\*")) (defvar org-nofile-regexp nil "Regexps matching `buffer-name buffer` for frame name `ORG`.") (setq org-nofile-regexp '("\\*Org Agenda\\*")) (setq display-buffer-alist '((lawlist-p . (nofile-display-buffer-pop-up-frame)))) (defun lawlist-p (buffer action) (let ((buffer (get-buffer buffer))) (or (lawlist-regexp-match-p org-nofile-regexp (buffer-name buffer)) (lawlist-regexp-match-p main-nofile-regexp (buffer-name buffer)) (lawlist-regexp-match-p system-nofile-regexp (buffer-name buffer)) ))) (defun nofile-display-buffer-pop-up-frame (buffer alist) (cond ((lawlist-regexp-match-p org-nofile-regexp (buffer-name buffer)) (if (frame-exists "ORG") (switch-to-frame "ORG") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "ORG")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "ORG")) (progn (make-frame) (set-frame-name "ORG"))) )) ((lawlist-regexp-match-p main-nofile-regexp (buffer-name buffer)) (if (frame-exists "MAIN") (switch-to-frame "MAIN") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "MAIN")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "MAIN")) (progn (make-frame) (set-frame-name "MAIN"))) )) ((lawlist-regexp-match-p system-nofile-regexp (buffer-name buffer)) (if (frame-exists "SYSTEM") (switch-to-frame "SYSTEM") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "SYSTEM")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "SYSTEM")) (progn (make-frame) (set-frame-name "SYSTEM"))) )) ((and (not (lawlist-regexp-match-p org-nofile-regexp (buffer-name buffer))) (not (lawlist-regexp-match-p main-nofile-regexp (buffer-name buffer))) (not (lawlist-regexp-match-p system-nofile-regexp (buffer-name buffer))) ) (if (frame-exists "MISCELLANEOUS") (switch-to-frame "MISCELLANEOUS") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "MISCELLANEOUS")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "MISCELLANEOUS")) (progn (make-frame) (set-frame-name "MISCELLANEOUS"))))) (t (display-buffer-same-window))) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GENERIC REGEXP FUNCTION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun lawlist-regexp-match-p (regexps string) (catch 'matched (dolist (regexp regexps) (if (string-match regexp string) (throw 'matched t))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;; GENERIC BUFFER / FRAME UTILITIES ;;;;;;;;;;;;;;;;;;;;;;;; (defun frame-exists (frame-name) (not (eq nil (get-frame frame-name)))) (defun get-frame-name (&optional frame) "Return the string that names FRAME (a frame). Default is selected frame." (unless frame (setq frame (selected-frame))) (if (framep frame) (cdr (assq 'name (frame-parameters frame))) (error "Function `get-frame-name': Argument not a frame: `%s'" frame))) (defun get-frame (frame) "Return a frame, if any, named FRAME (a frame or a string). If none, return nil. If FRAME is a frame, it is returned." (cond ((framep frame) frame) ((stringp frame) (catch 'get-a-frame-found (dolist (fr (frame-list)) (when (string= frame (get-frame-name fr)) (throw 'get-a-frame-found fr))) nil)) (t (error "Function `get-frame-name': Arg neither a string nor a frame: `%s'" frame)))) (defun switch-to-frame (frame-name) (let ((frames (frame-list))) (catch 'break (while frames (let ((frame (car frames))) (if (equal (frame-parameter frame 'name) frame-name) (throw 'break (select-frame-set-input-focus frame)) (setq frames (cdr frames)))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; At Tue, 27 Aug 2013 08:47:19 +0200, martin rudalics wrote: > > > Using your suggestion of find-file-noselect works well with the initial example, and then just adding (switch-to-buffer (get-file-buffer buffer-filename)) to the tail end of the lawlist-display-buffer-function. > > If you want to show a file-visiting buffer in the selected window, yes. > I'd rather add a rule that calls `display-buffer-same-window' and rewrite > the code > > (when (lawlist-regexps-match-p ...) > ...) > (when (lawlist-regexps-match-p ...) > ...) > > as > > (cond > ((lawlist-regexps-match-p ...) > ...) > ((lawlist-regexps-match-p ...) > ...) > (t > (display-buffer-same-window ...))) > > BTW you should also make code like > > (if (and > (not (equal "MAIN" (frame-parameter frame 'name))) > (not (equal "SYSTEM" (frame-parameter frame 'name))) > (not (equal "ORG" (frame-parameter frame 'name))) > (not (equal "WANDERLUST" (frame-parameter frame 'name))) > (not (equal "MISCELLANEOUS" (frame-parameter frame 'name))) ) > > more readable by defining a variable like > > (defvar my-regexp "^\\(?:MAIN\\|SYSTEM\\|ORG\\|WANDERLUST\\| MISCELLANEOUS\\)$" > "My doc-string.") > > and using > (not (string-match my-regexp (frame-parameter frame 'name))) > > instead. > > martin
bug-gnu-emacs <at> gnu.org
:bug#15189
; Package emacs
.
(Wed, 28 Aug 2013 04:00:03 GMT) Full text and rfc822 format available.Message #26 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Kevin Rodgers <kevin.d.rodgers <at> gmail.com> To: bug-gnu-emacs <at> gnu.org Subject: Re: bug#15189: 24.3.50; display-buffer does not work well with custom frames. Date: Tue, 27 Aug 2013 21:59:31 -0600
On 8/27/13 12:47 AM, martin rudalics wrote: > BTW you should also make code like > > (if (and > (not (equal "MAIN" (frame-parameter frame 'name))) > (not (equal "SYSTEM" (frame-parameter frame 'name))) > (not (equal "ORG" (frame-parameter frame 'name))) > (not (equal "WANDERLUST" (frame-parameter frame 'name))) > (not (equal "MISCELLANEOUS" (frame-parameter frame 'name))) ) > > more readable by defining a variable like > > (defvar my-regexp "^\\(?:MAIN\\|SYSTEM\\|ORG\\|WANDERLUST\\| MISCELLANEOUS\\)$" > "My doc-string.") > > and using > (not (string-match my-regexp (frame-parameter frame 'name))) > > instead. Or: (defvar my-list '("MAIN" "SYSTEM" "ORG" "WANDERLUST" "MISCELLANEOUS") "My doc string.") ... (not (member (frame-parameter frame 'name) my-string)) -- Kevin Rodgers Denver, Colorado, USA
bug-gnu-emacs <at> gnu.org
:bug#15189
; Package emacs
.
(Wed, 28 Aug 2013 16:36:01 GMT) Full text and rfc822 format available.Message #29 received at 15189 <at> debbugs.gnu.org (full text, mbox):
From: Keith David Bershatsky <esq <at> lawlist.com> To: martin rudalics <rudalics <at> gmx.at> Cc: 15189 <at> debbugs.gnu.org Subject: Re: bug#15189: 24.3.50; display-buffer does not work well with custom frames. Date: Wed, 28 Aug 2013 09:35:12 -0700
I have consolidated all of the magic into the display-buffer-alist, so that it can be used for both types of situations -- i.e., file-visiting, and non-file-visiting buffers. This revision longer relies upon the display-buffer-function, which is slated to be discontinued. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; EXAMPLE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun example () (interactive) (lawlist-find-file "*bar*") (set-frame-height (selected-frame) 15) (set-frame-width (selected-frame) 80) (set-frame-position (selected-frame) 0 0) (message "\*bar\* appears in frame name SYSTEM.") (sit-for 3) (lawlist-find-file "foo.txt") (set-frame-height (selected-frame) 15) (set-frame-width (selected-frame) 80) (set-frame-position (selected-frame) 100 100) (message "\"foo.txt\" appears in frame name MAIN.") (sit-for 3) (lawlist-find-file "doe.org") (set-frame-height (selected-frame) 15) (set-frame-width (selected-frame) 80) (set-frame-position (selected-frame) 200 200) (message "\"doe.org\" appears in frame name ORG.") (sit-for 3) (lawlist-find-file "*buffer-filename-non-regexp*") (set-frame-height (selected-frame) 15) (set-frame-width (selected-frame) 80) (set-frame-position (selected-frame) 300 300) (message "\*IS\* buffer-filename. \*NOT\* defined by any special regexp.") (sit-for 8) (display-buffer (get-buffer-create "*get-buffer-create-example*")) (set-frame-height (selected-frame) 15) (set-frame-width (selected-frame) 80) (set-frame-position (selected-frame) 400 400) (message "\*NOT\* buffer-filename. \*\*IS\*\* defined by main-buffer-regexp.") (sit-for 8) (display-buffer (get-buffer-create "*get-buffer-create-UNDEFINED*")) (message "\*NOT\* buffer-filename. \*NOT\* defined by any special regexp.") (sit-for 8) (kill-buffer "*bar*") (kill-buffer "foo.txt") (kill-buffer "doe.org") (kill-buffer "*buffer-filename-non-regexp*") (kill-buffer "*get-buffer-create-example*") (kill-buffer "*get-buffer-create-UNDEFINED*") (make-frame) (delete-frame (get-frame "SYSTEM")) (delete-frame (get-frame "MAIN")) (delete-frame (get-frame "ORG")) (delete-frame (get-frame "MISCELLANEOUS")) (message "THE END.")) ;;;;;;;;;;;;;;;;; DISPLAY-BUFFER-ALIST and DISPLAY-BUFFER ;;;;;;;;;;;;;;;;;;;;;;;;;;; (defvar regexp-frame-names "^\\(?:MAIN\\|SYSTEM\\|ORG\\|MISCELLANEOUS\\)$" "Regexp matching frames with specific names.") (defvar system-buffer-regexp nil "Regexps matching `buffer-filename` for frame name `SYSTEM`.") (setq system-buffer-regexp '("*scratch*" "*bar*")) (defvar main-buffer-regexp nil "Regexps matching `buffer-filename` for frame name `MAIN`.") (setq main-buffer-regexp '("\\.txt" "\\.tex" "\\.el" "\\.yasnippet" "\\*get-buffer-create-example\\*")) (defvar org-buffer-regexp nil "Regexps matching `buffer-filename` for frame name `ORG`.") (setq org-buffer-regexp '("[*]todo-list[*]" "\\.org_archive" "\\.org")) (defvar buffer-filename nil) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun lawlist-find-file (&optional buffer-filename) "With assistance from the display-buffer-alist, locate or create a specific frame, and then open the file." (interactive) (unless buffer-filename (setq buffer-filename (read-file-name "Select File: "))) ;; If using a version of Emacs built `--with-ns`, then user may substitute: ;; (unless buffer-filename (setq buffer-filename ;; (ns-read-file-name "Select File:" "~/" t nil))) (if buffer-filename (display-buffer (find-file-noselect buffer-filename)))) (setq display-buffer-alist '((".*" . (lawlist-display-buffer-pop-up-frame)))) (defun lawlist-display-buffer-pop-up-frame (buffer alist) (cond ((regexp-match-p org-buffer-regexp (buffer-name buffer)) (if (frame-exists "ORG") (switch-to-frame "ORG") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "ORG")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "ORG")) (progn (make-frame) (set-frame-name "ORG"))) ) (set-window-buffer (frame-selected-window) (buffer-name buffer))) ((regexp-match-p main-buffer-regexp (buffer-name buffer)) (if (frame-exists "MAIN") (switch-to-frame "MAIN") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "MAIN")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "MAIN")) (progn (make-frame) (set-frame-name "MAIN"))) ) (set-window-buffer (frame-selected-window) (buffer-name buffer))) ((regexp-match-p system-buffer-regexp (buffer-name buffer)) (if (frame-exists "SYSTEM") (switch-to-frame "SYSTEM") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "SYSTEM")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "SYSTEM")) (progn (make-frame) (set-frame-name "SYSTEM"))) ) (set-window-buffer (frame-selected-window) (buffer-name buffer))) ((and (not (regexp-match-p org-buffer-regexp (buffer-name buffer))) (not (regexp-match-p main-buffer-regexp (buffer-name buffer))) (not (regexp-match-p system-buffer-regexp (buffer-name buffer))) buffer-filename ) (if (frame-exists "MISCELLANEOUS") (switch-to-frame "MISCELLANEOUS") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "MISCELLANEOUS")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "MISCELLANEOUS")) (progn (make-frame) (set-frame-name "MISCELLANEOUS")))) (set-window-buffer (frame-selected-window) (buffer-name buffer))) (t (set-window-buffer (split-window-horizontally) (buffer-name buffer))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GENERIC REGEXP FUNCTION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun regexp-match-p (regexps string) (catch 'matched (dolist (regexp regexps) (if (string-match regexp string) (throw 'matched t))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;; GENERIC BUFFER / FRAME UTILITIES ;;;;;;;;;;;;;;;;;;;;;;;; (defun frame-exists (frame-name) (not (eq nil (get-frame frame-name)))) (defun get-frame-name (&optional frame) "Return the string that names FRAME (a frame). Default is selected frame." (unless frame (setq frame (selected-frame))) (if (framep frame) (cdr (assq 'name (frame-parameters frame))) (error "Function `get-frame-name': Argument not a frame: `%s'" frame))) (defun get-frame (frame) "Return a frame, if any, named FRAME (a frame or a string). If none, return nil. If FRAME is a frame, it is returned." (cond ((framep frame) frame) ((stringp frame) (catch 'get-a-frame-found (dolist (fr (frame-list)) (when (string= frame (get-frame-name fr)) (throw 'get-a-frame-found fr))) nil)) (t (error "Function `get-frame-name': Arg neither a string nor a frame: `%s'" frame)))) (defun switch-to-frame (frame-name) (let ((frames (frame-list))) (catch 'break (while frames (let ((frame (car frames))) (if (equal (frame-parameter frame 'name) frame-name) (throw 'break (select-frame-set-input-focus frame)) (setq frames (cdr frames)))))))) ;;;;;;;;;;;;;;;;;;;;;;;; IF BUILT --with-ns, THEN ALSO USE ;;;;;;;;;;;;;;;;;;;;;;;;;; (defalias 'ns-find-file 'lawlist-ns-find-file) (defun lawlist-ns-find-file () "Do a `find-file' with the `ns-input-file' as argument." (interactive) (let* ((f (file-truename (expand-file-name (pop ns-input-file) command-line-default-directory))) (file (find-file-noselect f)) (bufwin1 (get-buffer-window file 'visible)) (bufwin2 (get-buffer-window "*scratch*" 'visible))) (cond (bufwin1 (select-frame (window-frame bufwin1)) (raise-frame (window-frame bufwin1)) (select-window bufwin1)) ((and (eq ns-pop-up-frames 'fresh) bufwin2) (ns-hide-emacs 'activate) (select-frame (window-frame bufwin2)) (raise-frame (window-frame bufwin2)) (select-window bufwin2) (lawlist-find-file f)) (t (ns-hide-emacs 'activate) (lawlist-find-file f))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
bug-gnu-emacs <at> gnu.org
:bug#15189
; Package emacs
.
(Thu, 29 Aug 2013 00:22:02 GMT) Full text and rfc822 format available.Message #32 received at 15189 <at> debbugs.gnu.org (full text, mbox):
From: Keith David Bershatsky <esq <at> lawlist.com> To: martin rudalics <rudalics <at> gmx.at> Cc: 15189 <at> debbugs.gnu.org Subject: Re: bug#15189: 24.3.50; display-buffer does not work well with custom frames. Date: Wed, 28 Aug 2013 17:21:52 -0700
Okay, I think I have a better understanding now of how display-buffer works in conjunction with the display-buffer-alist. There just weren't any really good examples on the internet or in the official documentation from which to work from. I've updated my post on stackoverflow.com, and that should help other novice programmers (like myself) in the future who Google some of the relevant keywords. I noticed quite a few comments on the internet about the display-buffer family of functions being worthy of a doctoral thesis due to the level of complexity. And with my legal background, I was beginning to think that this project was similar to understanding the rule against perpetuities -- something that all law school students fear will be tested: http://en.wikipedia.org/wiki/Rule_against_perpetuities I recommend that the documentation be updated to include several working examples of the display-buffer family of functions, which would help to remove the mysticism surrounding the usage. The level of "perceived" complexity would be significantly reduced once those working examples become available. Thank you so much for teaching me a few new things about programming and the display-buffer family. In case you or anyone else who has been reading these e-mail exchanges is interested in the project I've been working on, I am resurrecting Frame-Bufs written by Al Parker a few years ago and marrying it with Tabbar. It's far from done, but it is working already and is coming along quite nicely thanks to all the wonderful help from people like you :) https://github.com/lawlist/tabbar-lawlist Thanks again, Keith ;;;;;;;;;;;;;;;;; DISPLAY-BUFFER-ALIST and DISPLAY-BUFFER ;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun example () (interactive) ;; condition # 3 | file-visiting buffer (lawlist-find-file "*bar*") (set-frame-height (selected-frame) 20) (set-frame-width (selected-frame) 80) (set-frame-position (selected-frame) 0 0) (message "\*bar\* appears in frame name SYSTEM.") (sit-for 3) ;; condition # 4(a) | no-file-visiting buffer (display-buffer (get-buffer-create "*NO-FILE-special-buffer-regexp*")) (message "NO-FILE buffer existing frame, without other windows.") (sit-for 3) ;; condition # 2(a) | file-visiting buffer (lawlist-find-file "foo.txt") (set-frame-height (selected-frame) 20) (set-frame-width (selected-frame) 80) (set-frame-position (selected-frame) 100 100) (message "\"foo.txt\" appears in frame name MAIN.") (sit-for 3) ;; condition # 1 | file-visiting buffer (lawlist-find-file "doe.org") (set-frame-height (selected-frame) 20) (set-frame-width (selected-frame) 80) (set-frame-position (selected-frame) 200 200) (message "\"doe.org\" appears in frame name ORG.") (sit-for 3) ;; condition # 4(b) | file-visiting buffer (lawlist-find-file "*FILE-special-buffer-regexp*") (message "FILE buffer existing frame, without other windows.") (sit-for 3) ;; condition # 6 | no-file-visiting buffer default display (calendar) (message "Default for no-file-visiting-buffers.") (sit-for 3) ;; condition # 5 | file-visiting buffer with no pre-defined regexp. (lawlist-find-file "*FILE-undefined-regexp*") (set-frame-height (selected-frame) 20) (set-frame-width (selected-frame) 80) (set-frame-position (selected-frame) 300 300) (message "\*IS\* buffer-filename. \*NOT\* defined by any particular regexp.") (sit-for 3) ;; condition # 2(b) | no-file-visiting buffer (display-buffer (get-buffer-create "*NO-FILE-main-buffer-regexp*")) (set-frame-height (selected-frame) 20) (set-frame-width (selected-frame) 80) (set-frame-position (selected-frame) 400 400) (message "\*NOT\* buffer-filename. \*IS\* defined by main-buffer-regexp.") (sit-for 3) (kill-buffer "*bar*") (kill-buffer "foo.txt") (kill-buffer "doe.org") (kill-buffer "*FILE-undefined-regexp*") (kill-buffer "*NO-FILE-main-buffer-regexp*") (kill-buffer "*Calendar*") (kill-buffer "*FILE-special-buffer-regexp*") (kill-buffer "*NO-FILE-special-buffer-regexp*") (make-frame) (delete-frame (get-frame "SYSTEM")) (delete-frame (get-frame "MAIN")) (delete-frame (get-frame "ORG")) (delete-frame (get-frame "MISCELLANEOUS")) (message "THE END.")) (defvar regexp-frame-names "^\\(?:MAIN\\|SYSTEM\\|ORG\\|MISCELLANEOUS\\)$" "Regexp matching frames with specific names.") (defvar system-buffer-regexp nil "Regexp of file / buffer names displayed in frame `SYSTEM`.") (setq system-buffer-regexp '("*scratch*" "*bbdb*" "*bar*")) (defvar main-buffer-regexp nil "Regexp of file / buffer names displayed in frame `MAIN`.") (setq main-buffer-regexp '("\\.txt" "\\.tex" "\\.el" "\\.yasnippet" "\\*NO-FILE-main-buffer-regexp\\*")) (defvar org-buffer-regexp nil "Regexp of file / buffer names displayed in frame `ORG`.") (setq org-buffer-regexp '("[*]TODO[*]" "[*]Org Agenda[*]" "\\.org_archive" "\\.org")) (defvar special-buffer-regexp nil "Regexp of file / buffer names that will .") (setq special-buffer-regexp '("[*]NO-FILE-special-buffer-regexp[*]" "*FILE-special-buffer-regexp*")) (defvar buffer-filename nil) (defun lawlist-find-file (&optional buffer-filename) "With assistance from the display-buffer-alist, locate or create a specific frame, and then open the file." (interactive) (unless buffer-filename (setq buffer-filename (read-file-name "Select File: " "~/" nil nil nil nil))) ;; If using a version of Emacs built `--with-ns`, then user may substitute: ;; (unless buffer-filename (setq buffer-filename ;; (ns-read-file-name "Select File:" "~/" t nil nil))) (if buffer-filename (display-buffer (find-file-noselect buffer-filename)))) (setq display-buffer-alist '((".*" . (lawlist-display-buffer-pop-up-frame)))) (defun lawlist-display-buffer-pop-up-frame (buffer alist) (cond ;; condition # 1 -- either file-visiting or no-file buffers ((regexp-match-p org-buffer-regexp (buffer-name buffer)) (if (frame-exists "ORG") (switch-to-frame "ORG") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "ORG")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "ORG")) (progn (make-frame) (set-frame-name "ORG"))) ) (if (and (featurep 'init-frames) frame-bufs-mode) (frame-bufs-add-buffer (get-buffer buffer) (selected-frame))) (set-window-buffer (frame-selected-window) (buffer-name buffer))) ;; condition # 2 -- either file-visiting or no-file buffers ((regexp-match-p main-buffer-regexp (buffer-name buffer)) (if (frame-exists "MAIN") (switch-to-frame "MAIN") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "MAIN")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "MAIN")) (progn (make-frame) (set-frame-name "MAIN"))) ) (if (and (featurep 'init-frames) frame-bufs-mode) (frame-bufs-add-buffer (get-buffer buffer) (selected-frame))) (set-window-buffer (frame-selected-window) (buffer-name buffer))) ;; condition # 3 -- either file-visiting or no-file buffers ((regexp-match-p system-buffer-regexp (buffer-name buffer)) (if (frame-exists "SYSTEM") (switch-to-frame "SYSTEM") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "SYSTEM")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "SYSTEM")) (progn (make-frame) (set-frame-name "SYSTEM"))) ) (if (and (featurep 'init-frames) frame-bufs-mode) (frame-bufs-add-buffer (get-buffer buffer) (selected-frame))) (set-window-buffer (frame-selected-window) (buffer-name buffer))) ;; condition # 4 ;; display buffer in the existing frame, without other windows ((regexp-match-p special-buffer-regexp (buffer-name buffer)) (if (and (featurep 'init-frames) frame-bufs-mode) (frame-bufs-add-buffer (get-buffer buffer) (selected-frame))) (set-window-buffer (frame-selected-window) (buffer-name buffer))) ;; condition # 5 ;; file-visiting buffers that do NOT match any pre-defined regexp ((and (not (regexp-match-p org-buffer-regexp (buffer-name buffer))) (not (regexp-match-p main-buffer-regexp (buffer-name buffer))) (not (regexp-match-p system-buffer-regexp (buffer-name buffer))) (not (regexp-match-p special-buffer-regexp (buffer-name buffer))) buffer-filename ) (if (frame-exists "MISCELLANEOUS") (switch-to-frame "MISCELLANEOUS") ;; If unnamed frame exists, then take control of it. (catch 'break (dolist (frame (frame-list)) (if (not (string-match regexp-frame-names (frame-parameter frame 'name))) (throw 'break (progn (switch-to-frame (frame-parameter frame 'name)) (set-frame-name "MISCELLANEOUS")))))) ;; If dolist found no unnamed frame, then create / name it. (if (not (frame-exists "MISCELLANEOUS")) (progn (make-frame) (set-frame-name "MISCELLANEOUS")))) (if (and (featurep 'init-frames) frame-bufs-mode) (frame-bufs-add-buffer (get-buffer buffer) (selected-frame))) (set-window-buffer (frame-selected-window) (buffer-name buffer))) ;; condition # 6 ;; default display for no-file-visiting buffers (t nil) )) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GENERIC REGEXP FUNCTION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun regexp-match-p (regexps string) "Before the lisp function, define the variable like this:\n (defvar example-regexp nil \"Regexps matching `buffer-name buffer` for frame name `SYSTEM`.\") (setq example-regexp '(\"\\(\\*foo\\*\\|\\*bar\\*\\)\")) \nWithin the lisp function, use something like this:\n (regexp-match-p example-regexp (buffer-name buffer)) \nOr, this:\n (regexp-match-p example-regexp buffer-filename)" (catch 'matched (dolist (regexp regexps) (if (string-match regexp string) (throw 'matched t))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GENERIC FRAME UTILITIES ;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun frame-exists (frame-name) (not (eq nil (get-frame frame-name)))) (defun get-frame-name (&optional frame) "Return the string that names FRAME (a frame). Default is selected frame." (unless frame (setq frame (selected-frame))) (if (framep frame) (cdr (assq 'name (frame-parameters frame))) (error "Function `get-frame-name': Argument not a frame: `%s'" frame))) (defun get-frame (frame) "Return a frame, if any, named FRAME (a frame or a string). If none, return nil. If FRAME is a frame, it is returned." (cond ((framep frame) frame) ((stringp frame) (catch 'get-a-frame-found (dolist (fr (frame-list)) (when (string= frame (get-frame-name fr)) (throw 'get-a-frame-found fr))) nil)) (t (error "Function `get-frame-name': Arg neither a string nor a frame: `%s'" frame)))) (defun switch-to-frame (frame-name) (let ((frames (frame-list))) (catch 'break (while frames (let ((frame (car frames))) (if (equal (frame-parameter frame 'name) frame-name) (throw 'break (select-frame-set-input-focus frame)) (setq frames (cdr frames)))))))) ;;;;;;;;;;;;;;;;;;;;;;;; IF BUILT --with-ns, THEN ALSO USE ;;;;;;;;;;;;;;;;;;;;;;;;;; (defalias 'ns-find-file 'lawlist-ns-find-file) (defun lawlist-ns-find-file () "Do a `find-file' with the `ns-input-file' as argument." (interactive) (let* ((f (file-truename (expand-file-name (pop ns-input-file) command-line-default-directory))) (file (find-file-noselect f)) (bufwin1 (get-buffer-window file 'visible)) (bufwin2 (get-buffer-window "*scratch*" 'visible))) (cond (bufwin1 (select-frame (window-frame bufwin1)) (raise-frame (window-frame bufwin1)) (select-window bufwin1)) ((and (eq ns-pop-up-frames 'fresh) bufwin2) (ns-hide-emacs 'activate) (select-frame (window-frame bufwin2)) (raise-frame (window-frame bufwin2)) (select-window bufwin2) (lawlist-find-file f)) (t (ns-hide-emacs 'activate) (lawlist-find-file f)))))
Glenn Morris <rgm <at> gnu.org>
to control <at> debbugs.gnu.org
.
(Mon, 10 Feb 2014 21:35:03 GMT) Full text and rfc822 format available.Debbugs Internal Request <help-debbugs <at> gnu.org>
to internal_control <at> debbugs.gnu.org
.
(Tue, 11 Mar 2014 11:24:07 GMT) Full text and rfc822 format available.
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.