emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Using Org for browsing and managing buffers
@ 2010-04-09  1:17 Dan Davison
  2010-04-09  3:43 ` Austin Frank
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Dan Davison @ 2010-04-09  1:17 UTC (permalink / raw)
  To: emacs org-mode mailing list

[-- Attachment #1: Type: text/plain, Size: 789 bytes --]

I've been working on an Org tool to browse Emacs buffers. Emacs has the
function list-buffers (C-x C-b), where you can view a list of buffers,
delete buffers, etc. This is intended to be a replacement for
list-buffers, implemented in Org-mode.

The code is attached, and there's a git repo at
http://github.com/dandavison/org-buffers

After putting the code in your load-path and doing 
(require 'org-buffers), use the function `org-buffers-list' to create
the listing buffer. This is a read-only Org-mode buffer populated with
links to open buffers. Information is stored for each buffer using
properties. By default, the buffers are grouped by major mode. Here's a
screenshot.

http://www.princeton.edu/~ddavison/org-buffers/by-major-mode.png

The buffer has some special key-bindings:


[-- Attachment #2.1: Type: text/plain, Size: 780 bytes --]

| ?   | Show all keybindings                                   |
| g   | Update buffer (prefix arg does hard reset)             |
| b   | Select a different property to group by                |
| RET | follow link to buffer on this line                     |
| d   | Mark buffer for deletion                               |
| u   | Remove mark                                            |
| x   | Delete marked buffers                                  |
| o   | Like RET (see variable org-buffers-follow-link-method) |
| .   | Like RET but switch to buffer in same window           |
| h   | toggle between headings and plain entries for buffers  |
| p   | toggle in-buffer properties on/off                     |
| c   | Switch to column-view                                  |

[-- Attachment #2.2: Type: text/html, Size: 938 bytes --]

[-- Attachment #3: Type: text/plain, Size: 650 bytes --]


If there's an active region, d and u operate on all buffers in the
region.

Some variables that can be configured:
- org-buffers-buffer-properties
- org-buffers-excluded-modes
- org-buffers-excluded-buffers
- org-buffers-follow-link-method
- org-buffers-mode-hook
- org-buffers-buffer-name

Some possible extensions:
- Browse recent files using recentf
- Allow several buffers to be marked for side-by-side display
- Maintain folding configuration across buffer updates
- Make faster

As always, any feedback, suggestions and patches will be very welcome!

Dan

p.s. The column-view mode works for following links, but does need
further attention.


[-- Attachment #4: org-buffers.el --]
[-- Type: text/plain, Size: 17807 bytes --]

;;; org-buffers.el --- An Org-mode tool for buffer management

;; Copyright (C) 2010  Dan Davison

;; Author: Dan Davison <dandavison0 at gmail dot com>
;; Keywords: outlines, hypermedia, calendar, wp
;; Homepage: http://orgmode.org

;;; License:

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

;;; Commentary:

;;; Code:

(require 'org)
(require 'cl)

;;; Variables
(defvar org-buffers-buffer-name
  "*Buffers*"
  "Name of buffer in which buffer list is displayed")

(defvar org-buffers-state
  '((:by . "major-mode") (:atom . heading) (:properties . nil))
  "Association list specifiying the current state of org-buffers.")

(defvar org-buffers-follow-link-method 'org-open-at-point
  "Method used to follow link with RET. Must be one of

'org-open-at-point :: use `org-open-at-point' to follow link.
'current-window    :: use switch-to-buffer
'other-window      :: use switch-to-buffer-other-window

Setting this variable to 'current-window makes the behaviour more
consistent with that of `Buffer-menu-mode' and `dired-mode'")

(defvar org-buffers-buffer-properties
  '(("buffer-name" . (buffer-name))
    ("major-mode" . (let ((mode (symbol-name major-mode)))
		      (if (string-match "-mode$" mode)
			  (replace-match "" nil t mode) mode)))
    ("buffer-file-name" . (buffer-file-name))
    ("default-directory" . default-directory)
    ("buffer-modified-p" . (format "%s" (buffer-modified-p))))
  "Association list specifying properties to be stored for each
buffer. The car of each element is the name of the property, and
the cdr is an expression which, when evaluated in the buffer,
yields the property value.")

(defcustom org-buffers-excluded-buffers
  `("*Completions*" ,org-buffers-buffer-name)
  "List of names of buffers that should not be listed by
  org-buffers-list."
  :group 'org-buffers)

(defcustom org-buffers-excluded-modes nil
  "List of names of major-modes (strings) that should not be listed
  by org-buffers-list."
  :group 'org-buffers)

;;; Mode
(defvar org-buffers-mode-map (make-sparse-keymap))

(defvar org-buffers-mode-hook nil
  "Hook for functions to be called after buffer listing is
  created. Note that the buffer is read-only, so if the hook
  function is to modify the buffer it should use a let binding to
  temporarily bind buffer-read-only to nil.")

(define-minor-mode org-buffers-mode
  "An Org-mode tool for buffer management.
\\{org-buffers-mode-map}"
  nil " buffers" nil
  (org-set-local 'org-tag-alist '(("delete" . ?d)))
  (org-set-local'org-tags-column -50)
  (org-set-local 'org-columns-default-format "%25buffer-name(Buffer) %25major-mode(Mode) %25default-directory(Dir) %5buffer-modified-p(Modified)")
  (add-hook 'kill-buffer-hook 'org-buffers-reset-state nil 'local))

(defun org-buffers-help ()
  (interactive)
  (describe-function 'org-buffers-mode))

;;; Keys
(define-key org-buffers-mode-map [(return)] 'org-buffers-follow-link)
(define-key org-buffers-mode-map "b" 'org-buffers-list:by)
(define-key org-buffers-mode-map "c" 'org-buffers-columns-view)
(define-key org-buffers-mode-map "d" 'org-buffers-tag-for-deletion)
(define-key org-buffers-mode-map "g" 'org-buffers-list:refresh)
(define-key org-buffers-mode-map "." 'org-buffers-switch-to-buffer)
(define-key org-buffers-mode-map "h" 'org-buffers-toggle-headings)
(define-key org-buffers-mode-map "o" 'org-buffers-switch-to-buffer-other-window)
(define-key org-buffers-mode-map "p" 'org-buffers-toggle-properties)
(define-key org-buffers-mode-map "u" 'org-buffers-remove-tags)
(define-key org-buffers-mode-map "x" 'org-buffers-execute-pending-operations)
(define-key org-buffers-mode-map "?" 'org-buffers-help)
;;; Listing and view cycling

(defun org-buffers-list (&optional refresh frame)
  "Create an Org-mode listing of Emacs buffers.
By default, buffers are grouped by major mode. Optional
argument FRAME specifies the frame whose buffers should be
listed."
  (interactive)
  (pop-to-buffer
   (or
    (and (not refresh) (get-buffer org-buffers-buffer-name))
    (let ((org-buffers-p (equal (buffer-name) org-buffers-buffer-name))
	  (by (or (org-buffers-state-get :by) "major-mode"))
	  (atom (org-buffers-state-get :atom)) target)
      (when org-buffers-p
	(if (and (org-before-first-heading-p) (not (org-on-heading-p)))
	    (outline-next-heading))
	(setq target
	      (condition-case nil (org-make-org-heading-search-string) (error nil))))
      (with-current-buffer (get-buffer-create org-buffers-buffer-name)
	(setq buffer-read-only nil)
	(erase-buffer)
	(org-mode)
	(dolist
	    (buffer
	     (sort (remove-if 'org-buffers-exclude-p
			      (mapcar 'buffer-name (buffer-list frame))) 'string<))
	  (org-insert-heading t)
	  (insert
	   (org-make-link-string (concat "buffer:" buffer) buffer) "\n")
	  (dolist (pair (org-buffers-get-buffer-props buffer))
	    (org-set-property (car pair) (cdr pair))))
	(org-buffers-set-state '((:atom . heading)))
	(goto-char (point-min))
	(unless (equal by "NONE") (org-buffers-group-by by))
	(if target (condition-case nil (org-link-search target) (error nil)))
	(beginning-of-line)
	(if (equal by "NONE")
	    (org-overview)
	  (case atom
	    ('heading (progn (org-overview) (org-content)))
	    ('line (progn (show-all) (org-buffers-toggle-headings)))))
	(save-excursion
	  (mark-whole-buffer)
	  (indent-region (point-min) (point-max)))
	(org-buffers-mode)
	(setq buffer-read-only t)
	(current-buffer))))))

(defun org-buffers-list:refresh (&optional arg)
  "Refresh org-buffers listing."
  (interactive "P")
  (if arg (org-buffers-reset-state))
  (org-buffers-list 'refresh))

(defun org-buffers-list:by (&optional prop)
  "Group buffers according to value of property PROP."
  (interactive)
  (let ((buffer-read-only nil)
	(headings-p (org-buffers-state-eq :atom 'heading)))
    (unless (org-buffers-state-get :properties)
      (org-buffers-toggle-properties))
    (org-buffers-set-state
     `((:by .
	    ,(or prop
		 (org-completing-read
		  "Property to group by: "
		  (cons "NONE" (mapcar 'car org-buffers-buffer-properties)))))))
    (org-buffers-list 'refresh)
    (unless headings-p (org-buffers-toggle-headings))))

(defun org-buffers-toggle-properties ()
  "Toggle entry properties in org-buffers listing buffer.
Removing properties may provide a less cluttered appearance for
browsing. However, in-buffer properties will be restored during
certain operations, such as `org-buffers-list:by'."
  (interactive)
  (if (org-buffers-state-get :properties)
      (progn (org-buffers-delete-properties)
	     (show-all)
	     (org-buffers-set-state '((:properties . nil))))
    (org-buffers-set-state
     '((:atom . heading) (:properties . t)))
    (org-buffers-list 'refresh)))

(defun org-buffers-toggle-headings ()
  "Toggle viewing of buffers as org headings.
Headings will be automatically restored during certain
operations, such as setting deletion tags."
  (interactive)
  (let ((buffer-read-only nil)
	(headings-p (org-buffers-state-eq :atom 'heading))
	(flat-p (org-buffers-state-eq :by "NONE")))
    (if (and headings-p (org-buffers-state-get :properties))
	(org-buffers-toggle-properties))
    (save-excursion
      (goto-char (point-min))
      (if (and (or headings-p (not flat-p))
	       (not (outline-on-heading-p)))
	  (outline-next-heading))
      (if flat-p
	  (progn 
	    (push-mark (point) 'nomsg 'activate)
	    (end-of-buffer)
	    (org-ctrl-c-star)
	    (pop-mark))
	(while (not (eobp))
	  (push-mark
	   (save-excursion (forward-line 1) (point)) 'nomsg 'activate)
	  (org-forward-same-level 1)	
	  (org-ctrl-c-star)
	  (pop-mark)))
      (mark-whole-buffer)
      (indent-region (point-min) (point-max)))
    (org-buffers-set-state
     `((:atom . ,(if headings-p 'line 'heading))))))

(defun org-buffers-delete-properties ()
  (let ((buffer-read-only nil))
    (save-excursion
      (goto-char (point-min))
      (org-buffers-delete-regions
       (nreverse
	(org-buffers-map-entries 'org-buffers-get-property-block))))))

(defun org-buffers-get-property-block ()
  "Return the (beg . end) range of the property drawer.
Unlike the org version the limits include the keywords delimiting
the drawer."
  (let ((beg (point))
	(end (progn (outline-next-heading) (point))))
    (goto-char beg)
    (if (re-search-forward org-property-drawer-re end t)
	(cons (match-beginning 1) (match-end 0)))))

(defun org-buffers-group-by (property)
  "Group top level headings according to the value of PROPERTY."
  (let ((atom (org-buffers-state-get :atom)))
    (save-excursion
      (goto-char (point-min))
      (mapc (lambda (subtree) ;; Create subtree for each value of `property'
	      (org-insert-heading t)
	      (if (> (org-buffers-outline-level) 1)
		  (org-promote))
	      (insert (car subtree) "\n")
	      (org-insert-subheading t)
	      (mapc 'org-buffers-insert-parsed-entry (cdr subtree)))
	    (prog1
		(mapcar (lambda (val) ;; Form list of parsed entries for each unique value of `property'
			  (cons val (org-buffers-parse-selected-entries property val)))
			(sort
			 (delete-dups (org-buffers-map-entries (lambda () (org-entry-get nil property nil))))
			 'string<))
	      (erase-buffer))))))

(defun org-buffers-exclude-p (buffer)
  "Return non-nil if BUFFER should not be listed."
  (or (member (with-current-buffer buffer major-mode)
	      org-buffers-excluded-modes)
      (member buffer org-buffers-excluded-buffers)
      (string= (substring buffer 0 1) " ")))

(defun org-buffers-reset-state ()
  (org-buffers-set-state
   '((:by . "major-mode") (:atom . heading) (:properties . nil))))

(defun org-buffers-columns-view ()
  "View buffers in Org-mode columns view.
This is currently experimental. RET can be used to follow links
in the first column, but certain other org-buffers keys conflict
with column-view or otherwise do not work correctly."
  (interactive)
  (let ((by (org-buffers-state-get :by))
	(buffer-read-only nil))
    (unless (equal by "NONE") (org-buffers-list:by "NONE"))
    (unless (org-buffers-state-get :properties)
      (org-buffers-toggle-properties))
    (unless (equal by "NONE")
      (goto-char (point-min))
      (org-sort-entries-or-items nil ?r nil nil by)
      (org-overview))
    (mark-whole-buffer)
    (org-columns)))

;;; Parsing and inserting entries
(defun org-buffers-parse-selected-entries (prop val)
  "Parse all entries with property PROP value VAL."
  (delq nil
	(org-buffers-map-entries
	 (lambda () (when (equal (org-entry-get nil prop) val)
		      (cons (org-get-heading) (org-get-entry)))))))

(defun org-buffers-insert-parsed-entry (entry)
  "Insert a parsed entry"
  (unless (org-at-heading-p) (org-insert-heading))
  (insert (car entry) "\n")
  (if (org-buffers-state-get :properties)
      (insert (cdr entry))))

(defun org-buffers-get-buffer-props (buffer)
  "Create alist of properties of BUFFER, as strings."
  (with-current-buffer buffer
    (mapcar 
     (lambda (pair) (cons (car pair) (eval (cdr pair))))
     org-buffers-buffer-properties)))

;;; Follow-link behaviour

(defun org-buffers-follow-link ()
  "Follow link to buffer on this line.
The buffer-switching behaviour of this function is determined by
the variable `org-buffers-follow-link-method'. See also
`org-buffers-switch-to-buffer' and
`org-buffers-switch-to-buffer-other-window', whose behaviour is
hard-wired."
  (interactive)
  (org-buffers-switch-to-buffer-generic org-buffers-follow-link-method))

(defun org-buffers-switch-to-buffer ()
"Switch to this entry's buffer in current window."
  (interactive)
  (org-buffers-switch-to-buffer-generic 'current-window))

(defun org-buffers-switch-to-buffer-other-window ()
  "Switch to this entry's buffer in other window."
  (interactive)
  (org-buffers-switch-to-buffer-generic 'other-window))

(defun org-buffers-switch-to-buffer-generic (method)
  (save-excursion
    (let ((atom (org-buffers-state-get :atom)) buffer)
      (cond
       ((eq atom 'heading) (org-back-to-heading))
       (t (beginning-of-line)))
      (setq buffer (org-buffers-get-buffer-name))
      (if (get-buffer buffer)
	  (case method
	    ('org-open-at-point (org-open-at-point))
	    ('current-window (switch-to-buffer buffer))
	    ('other-window (switch-to-buffer-other-window buffer)))
	(error "No such buffer: %s" buffer)))))

(defun org-buffers-get-buffer-name ()
  "Get buffer-name for current entry."
  (let ((headings-p (org-buffers-state-eq :atom 'heading)))
    (or (and headings-p (org-entry-get nil "buffer-name"))
	(and (save-excursion
	       (if headings-p (org-back-to-heading))
	       (re-search-forward "\\[\\[buffer:\\([^\]]*\\)" (point-at-eol) t))
	     (org-link-unescape (match-string 1))))))

;;; Setting tags and executing operations

(defun org-buffers-tag-for-deletion ()
  "Mark buffer for deletion.
If a region is selected, all buffers in the region are marked for
deletion. Buffers marked for deletion can be deleted using
`org-buffers-execute-pending-operations'."
  (interactive)
  (org-buffers-set-tags '("delete")))

(defun org-buffers-remove-tags ()
  "Remove deletion marks from buffers.
If a region is selected, marks are removed from all buffers in
the region."
  (interactive)
  (org-buffers-set-tags nil))

(defun org-buffers-set-tags (data)
  "Set tags to DATA at all non top-level headings in region.
DATA should be a list of strings. If DATA is nil, remove all tags
at such headings."
  (let* ((buffer-read-only nil)
	 (region-p (org-region-active-p))
	 (beg (if region-p (region-beginning) (point)))
	 (end (if region-p (region-end) (point)))
	 (headings-p (org-buffers-state-eq :atom 'heading))beg-line end-line)
    (save-excursion
      (setq beg-line (progn (goto-char beg) (org-current-line))
	    end-line (progn (goto-char end) (org-current-line)))
      (if headings-p
	  (setq
	   end (if (and region-p (not (eq end-line beg-line)) (not (eobp)))
		   (progn (goto-char end) (org-back-to-heading) (point))
		 (progn (outline-end-of-heading) (point)))
	   beg (progn (goto-char beg) (point-at-bol)))
	(org-buffers-toggle-headings) ;; doesn't alter line numbers
	(setq beg (progn (org-goto-line beg-line) (point-at-bol))
	      end (if (eq end-line beg-line) (point-at-eol)
		    (progn (org-goto-line end-line) (point-at-bol)))))
      (narrow-to-region beg end)
      (goto-char (point-min))
      (org-buffers-map-entries
       (lambda ()
	 (when (or (org-buffers-state-eq :by "NONE")
		   (> (org-outline-level) 1))
	   (org-set-tags-to
	    (if data (delete-duplicates (append data (org-get-tags)) :test 'string-equal))))))
      (widen)
      (org-content))
    (unless region-p
      (outline-next-heading)
      (unless (or (> (org-outline-level) 1) (org-buffers-state-eq :by "NONE"))
	(outline-next-heading)))
        (unless headings-p (org-buffers-toggle-headings))))

(defun org-buffers-execute-pending-operations ()
  "Execute all pending operations.
Currently the only type of operation supported is
deletion. Buffers are tagged for deletion using
`org-buffers-tag-for-deletion'. Remove such tags from buffers
using `org-buffers-remove-tags'."
  (interactive)
  (let ((buffer-read-only nil)
	(headings-p (org-buffers-state-eq :atom 'heading)) buffer)
    (unless headings-p (org-buffers-toggle-headings))
    (org-buffers-delete-regions
     (nreverse
      (org-buffers-map-entries
       (lambda ()
	 (if (setq buffer (org-buffers-get-buffer-name))
	     (if (not (kill-buffer buffer))
		 (error "Failed to kill buffer %s" buffer)
	       (if (and (org-first-sibling-p)
			(not (save-excursion (org-goto-sibling))))
		   (org-up-heading-safe)) ;; Only child so delete parent also
	       (cons (point) (1+ (org-end-of-subtree))))))
       "+delete")))
    (unless headings-p (org-buffers-toggle-headings))))

;;; Utilities

(defun org-buffers-map-entries (func &optional match)
  (org-scan-tags
   func (if match (cdr (org-make-tags-matcher match)) t)))
  
(defun org-buffers-set-state (state)
  "Add STATE to global state list.
New settings have precedence over existing ones."
  (mapc
   (lambda (pair) (unless (assoc (car pair) state)
		    (add-to-list 'state pair)))
   org-buffers-state)
  (setq org-buffers-state state))

(defmacro org-buffers-delete-regions (regions)
  "Delete regions in list.
REGIONS is a list of (beg . end) cons cells specifying buffer
regions."
  `(mapc (lambda (pair) (if pair (delete-region (car pair) (cdr pair))))
	 ,regions))

(defmacro org-buffers-state-get (key)
  `(cdr (assoc ,key org-buffers-state)))

(defmacro org-buffers-state-eq (key val)
  `(equal (org-buffers-state-get ,key) ,val))

(defmacro org-buffers-outline-level ()
  '(save-excursion (beginning-of-line) (org-outline-level)))

;;; Links to buffers

(org-add-link-type "buffer" 'display-buffer)
(add-hook 'org-store-link-functions 'org-buffers-store-link)

(defun org-buffers-store-link (&optional force)
  "Store a link to an Emacs buffer.
Returns nil by default, to avoid hijacking other link types."
  (if force
      (let* ((target (buffer-name))
	     (desc target) link)
	(org-store-link-props :type "buffer")
	(setq link (org-make-link "buffer:" target))
	(org-add-link-props :link link :description desc)
	link)))

(provide 'org-buffers)
;;; org-buffers.el ends here

[-- Attachment #5: Type: text/plain, Size: 201 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Please use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using Org for browsing and managing buffers
  2010-04-09  1:17 Using Org for browsing and managing buffers Dan Davison
@ 2010-04-09  3:43 ` Austin Frank
  2010-04-09 14:49   ` Dan Davison
  2010-04-14 20:23 ` Eric S Fraga
  2010-04-15 10:11 ` Livin Stephen Sharma
  2 siblings, 1 reply; 13+ messages in thread
From: Austin Frank @ 2010-04-09  3:43 UTC (permalink / raw)
  To: emacs-orgmode


[-- Attachment #1.1: Type: text/plain, Size: 511 bytes --]

Dan--

Very nice.  I will say, though, that the very first thing I did was

  (define-key org-buffers-mode-map "q" 'bury-buffer)

I would request that something like this be included in the default
keybindings.  A smarter version might try to restore the window config
From before org-buffers-list was called.  See ibuffer-quit for an
example.

Will report back after more testing!

Thanks!
/au

-- 
Austin Frank
http://aufrank.net
GPG Public Key (D7398C2F): http://aufrank.net/personal.asc

[-- Attachment #1.2: Type: application/pgp-signature, Size: 194 bytes --]

[-- Attachment #2: Type: text/plain, Size: 201 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Please use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Re: Using Org for browsing and managing buffers
  2010-04-09  3:43 ` Austin Frank
@ 2010-04-09 14:49   ` Dan Davison
  0 siblings, 0 replies; 13+ messages in thread
From: Dan Davison @ 2010-04-09 14:49 UTC (permalink / raw)
  To: Austin Frank; +Cc: emacs-orgmode

Austin Frank <austin.frank@gmail.com> writes:

> Dan--
>
> Very nice.  I will say, though, that the very first thing I did was
>
>   (define-key org-buffers-mode-map "q" 'bury-buffer)

Thanks Austin, I've added that.

> I would request that something like this be included in the default
> keybindings.  A smarter version might try to restore the window config
> From before org-buffers-list was called.  See ibuffer-quit for an
> example.

Will do. ibuffer does lots of nice things and I think a version using
org-mode, with org's hierarchical structuring, would be even better. If
anyone wanted to help out that would be great.

Maybe the correct approach is to make use of the existing ibuffer
machinery and build the org version on top of ibuffer?

Dan

>
> Will report back after more testing!
>
> Thanks!
> /au

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using Org for browsing and managing buffers
  2010-04-09  1:17 Using Org for browsing and managing buffers Dan Davison
  2010-04-09  3:43 ` Austin Frank
@ 2010-04-14 20:23 ` Eric S Fraga
  2010-04-15  4:20   ` Dan Davison
  2010-04-15 10:11 ` Livin Stephen Sharma
  2 siblings, 1 reply; 13+ messages in thread
From: Eric S Fraga @ 2010-04-14 20:23 UTC (permalink / raw)
  To: Dan Davison; +Cc: emacs org-mode mailing list

On Thu, 08 Apr 2010 21:17:20 -0400, Dan Davison <davison@stats.ox.ac.uk> wrote:

> I've been working on an Org tool to browse Emacs buffers. Emacs has the
> function list-buffers (C-x C-b), where you can view a list of buffers,
> delete buffers, etc. This is intended to be a replacement for
> list-buffers, implemented in Org-mode.

Excellent!  I really like this.  I currently use both bs-show and ido
for buffer selection but I could easily be convinced to use this
instead of bs-show.  Some comments:

> The buffer has some special key-bindings:

I have a problem with the current bindings: you are (I guess) trying
to emulate dired to some degree (cf. bindings for RET, 'd', 'o' [1] and
'x').  It would be nice therefore to have movement bindings as well
('n' and 'p').  I can obviously bind these myself but 'p' is already
taken and it would be nice to be as consistent with the defaults as
possible.  Maybe 'P' for properties on/off?

When I tried column view, the default widths are much too wide for my
netbook.  Can these be changed?  More importantly, when I left column
view, the buffer view was now different than the original view.
Originally, I had two levels (mode + buffer) and now it was a single
level (buffer).  How do I get back to mode+buffer two level view?

Thanks again!

eric

Footnotes: 
[1]  I found 'o' initially annoying as knowing that I was in org, I
expected it to behave like 'o' in agenda (hide other window)...

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using Org for browsing and managing buffers
  2010-04-14 20:23 ` Eric S Fraga
@ 2010-04-15  4:20   ` Dan Davison
  2010-04-15 12:18     ` Eric S Fraga
  0 siblings, 1 reply; 13+ messages in thread
From: Dan Davison @ 2010-04-15  4:20 UTC (permalink / raw)
  To: e.fraga; +Cc: emacs org-mode mailing list

[-- Attachment #1: Type: text/plain, Size: 3479 bytes --]

Eric S Fraga <ucecesf@ucl.ac.uk> writes:

> On Thu, 08 Apr 2010 21:17:20 -0400, Dan Davison <davison@stats.ox.ac.uk> wrote:
>
>> I've been working on an Org tool to browse Emacs buffers. Emacs has the
>> function list-buffers (C-x C-b), where you can view a list of buffers,
>> delete buffers, etc. This is intended to be a replacement for
>> list-buffers, implemented in Org-mode.
>
> Excellent!  I really like this.  I currently use both bs-show and ido
> for buffer selection but I could easily be convinced to use this
> instead of bs-show.

Hi Eric,

>  Some comments:
>
>> The buffer has some special key-bindings:
>
> I have a problem with the current bindings: you are (I guess) trying
> to emulate dired to some degree (cf. bindings for RET, 'd', 'o' [1] and
> 'x').  It would be nice therefore to have movement bindings as well
> ('n' and 'p').  I can obviously bind these myself but 'p' is already
> taken and it would be nice to be as consistent with the defaults as
> possible.  

Yes, I think I'm trying to emulate dired while still staying true to
Org. But I hadn't thought carefully about the keybindings yet and your
comments are very helpful.

As an experiment at least, I've now changed things so that Org speed
commands are turned on everywhere in the buffer. That means that we gain
all the commands listed in `org-speed-commands-default', including n, p,
f, b, u for movement. Another one I notice is useful is '.' for
outline-mark-subtree, so that '. d x' deletes a group of buffers

This does also mean that various inappropriate speed commands become
exposed (but then pressing random keys is a strategy that should be
confined to gnus).

> Maybe 'P' for properties on/off?

Done.

> When I tried column view, the default widths are much too wide for my
> netbook.  Can these be changed?

I've made them narrower by default, and introduced a customizable
variable org-buffers-columns-format.

>  More importantly, when I left column
> view, the buffer view was now different than the original view.

Thanks. I've fixed that.

> Originally, I had two levels (mode + buffer) and now it was a single
> level (buffer).  How do I get back to mode+buffer two level view?

org-buffers-list:by, which is now bound to B (used to be b). It brings
up minibuffer completion for the property you want to group by, so

B maj RET

would be enough to regroup by major-mode (should you need to).

>
> Thanks again!
>
> eric
>
> Footnotes: 
> [1]  I found 'o' initially annoying as knowing that I was in org, I
> expected it to behave like 'o' in agenda (hide other window)...

Noted. On the other hand o in Org speed commands is bound to
org-open-at-point. I've got rid of my binding and am allowing it to fall
through to the speed command default but I'd welcome any further
suggestions. Note that the variable org-buffers-follow-link-method can
be used so specify the behaviour of RET on a line with a buffer link.

Thanks a lot for the comments. The columns view thing is a bit
experimental still; I'm not sure what to do about the key bindings, or
indeed quite what the purpose of it is in this context, but it did seem
like a natural buffer to allow it in.

I haven't used bs-show. It might be interesting to try to get some of
the power of ibuffer in this mode. But Org is better than the
alternatives at hierarchical grouping and tree navigation. And also, the
alternatives are very ugly.

Current code below and at http://github.com/dandavison/org-buffers.

Dan


[-- Attachment #2: org-buffers.el --]
[-- Type: text/plain, Size: 18244 bytes --]

;;; org-buffers.el --- An Org-mode tool for buffer management

;; Copyright (C) 2010  Dan Davison

;; Author: Dan Davison <dandavison0 at gmail dot com>
;; Keywords: outlines, hypermedia, calendar, wp
;; Homepage: http://orgmode.org

;;; License:

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

;;; Commentary:

;;; Code:

(require 'org)
(require 'cl)

;;; Variables
(defvar org-buffers-buffer-name
  "*Buffers*"
  "Name of buffer in which buffer list is displayed")

(defvar org-buffers-state
  '((:by . "major-mode") (:atom . heading) (:properties . nil))
  "Association list specifying the current state of org-buffers.")

(defvar org-buffers-follow-link-method 'org-open-at-point
  "Method used to follow link with RET. Must be one of

'org-open-at-point :: use `org-open-at-point' to follow link.
'current-window    :: use switch-to-buffer
'other-window      :: use switch-to-buffer-other-window

Setting this variable to 'current-window makes the behaviour more
consistent with that of `Buffer-menu-mode' and `dired-mode'")

(defvar org-buffers-buffer-properties
  '(("buffer-name" . (buffer-name))
    ("major-mode" . (let ((mode (symbol-name major-mode)))
		      (if (string-match "-mode$" mode)
			  (replace-match "" nil t mode) mode)))
    ("buffer-file-name" . (buffer-file-name))
    ("default-directory" . default-directory)
    ("buffer-modified-p" . (format "%s" (buffer-modified-p))))
  "Association list specifying properties to be stored for each
buffer. The car of each element is the name of the property, and
the cdr is an expression which, when evaluated in the buffer,
yields the property value.")

(defgroup org-buffers nil
  "Options for customising `org-buffers-mode'"
  :tag "Org-buffers Mode"
  :group 'org)

(defcustom org-buffers-columns-format
  (mapconcat 'identity
	     '("%15buffer-name(Buffer)"
	       "%15major-mode(Mode)"
	       "%20default-directory(Dir)"
	       "%5buffer-modified-p(Modified)") " ")
  "Format for columns when viewing buffers listing in columns
view. See `org-columns-default-format'."
  :group 'org-buffers)

(defcustom org-buffers-excluded-buffers
  `("*Completions*" ,org-buffers-buffer-name)
  "List of names of buffers that should not be listed by
  org-buffers-list."
  :group 'org-buffers)

(defcustom org-buffers-excluded-modes nil
  "List of names of major-modes (strings) that should not be listed
  by org-buffers-list."
  :group 'org-buffers)

;;; Mode
(defvar org-buffers-mode-map (make-sparse-keymap))

(defvar org-buffers-mode-hook nil
  "Hook for functions to be called after buffer listing is
  created. Note that the buffer is read-only, so if the hook
  function is to modify the buffer it should use a let binding to
  temporarily bind inhibit-read-only to a non-nil value.")

(define-minor-mode org-buffers-mode
  "An Org-mode tool for buffer management.

In addition to the following org-buffers commands, all the
commands listed in `org-speed-commands-default' are available.

\\{org-buffers-mode-map}"
  nil " buffers" nil
  (org-set-local 'org-tag-alist '(("delete" . ?d)))
  (org-set-local'org-tags-column -50)
  (org-set-local 'org-columns-default-format org-buffers-columns-format)
  (org-set-local 'org-use-speed-commands (lambda () t))
  (add-hook 'kill-buffer-hook 'org-buffers-reset-state nil 'local))

(defun org-buffers-help ()
  (interactive)
  (describe-function 'org-buffers-mode))

;;; Keys
(define-key org-buffers-mode-map "B" 'org-buffers-list:by)
(define-key org-buffers-mode-map "c" 'org-buffers-columns-view)
(define-key org-buffers-mode-map "d" 'org-buffers-tag-for-deletion)
(define-key org-buffers-mode-map "g" 'org-buffers-list:refresh)
(define-key org-buffers-mode-map "h" 'org-buffers-toggle-headings)
(define-key org-buffers-mode-map "P" 'org-buffers-toggle-properties)
(define-key org-buffers-mode-map "q" 'bury-buffer)
(define-key org-buffers-mode-map "u" 'org-buffers-remove-tags)
(define-key org-buffers-mode-map "x" 'org-buffers-execute-pending-operations)
(define-key org-buffers-mode-map [(return)] 'org-buffers-follow-link)
(define-key org-buffers-mode-map "?" 'org-buffers-help)
;;; Listing and view cycling

(defun org-buffers-list (&optional refresh frame)
  "Create an Org-mode listing of Emacs buffers.
By default, buffers are grouped by major mode. Optional
argument FRAME specifies the frame whose buffers should be
listed."
  (interactive)
  (pop-to-buffer
   (or
    (and (not refresh) (get-buffer org-buffers-buffer-name))
    (let ((org-buffers-p (equal (buffer-name) org-buffers-buffer-name))
	  (by (or (org-buffers-state-get :by) "major-mode"))
	  (atom (org-buffers-state-get :atom)) target)
      (when org-buffers-p
	(if (and (org-before-first-heading-p) (not (org-on-heading-p)))
	    (outline-next-heading))
	(setq target
	      (condition-case nil (org-make-org-heading-search-string) (error nil))))
      (with-current-buffer (get-buffer-create org-buffers-buffer-name)
	(setq buffer-read-only nil)
	(erase-buffer)
	(org-mode)
	(dolist
	    (buffer
	     (sort (remove-if 'org-buffers-exclude-p
			      (mapcar 'buffer-name (buffer-list frame))) 'string<))
	  (org-insert-heading t)
	  (insert
	   (org-make-link-string (concat "buffer:" buffer) buffer) "\n")
	  (dolist (pair (org-buffers-get-buffer-props buffer))
	    (org-set-property (car pair) (cdr pair))))
	(org-buffers-set-state '((:atom . heading)))
	(goto-char (point-min))
	(unless (equal by "NONE") (org-buffers-group-by by))
	(if target (condition-case nil (org-link-search target) (error nil)))
	(beginning-of-line)
	(if (equal by "NONE")
	    (org-overview)
	  (case atom
	    ('heading (progn (org-overview) (org-content)))
	    ('line (progn (show-all) (org-buffers-toggle-headings)))))
	(save-excursion
	  (mark-whole-buffer)
	  (indent-region (point-min) (point-max)))
	(org-buffers-mode)
	(setq buffer-read-only t)
	(current-buffer))))))

(defun org-buffers-list:refresh (&optional arg)
  "Refresh org-buffers listing."
  (interactive "P")
  (if arg (org-buffers-reset-state))
  (org-buffers-list 'refresh))

(defun org-buffers-list:by (&optional prop)
  "Group buffers according to value of property PROP."
  (interactive)
  (let ((inhibit-read-only t)
	(headings-p (org-buffers-state-eq :atom 'heading)))
    (unless (org-buffers-state-get :properties)
      (org-buffers-toggle-properties))
    (org-buffers-set-state
     `((:by .
	    ,(or prop
		 (org-completing-read
		  "Property to group by: "
		  (cons "NONE" (mapcar 'car org-buffers-buffer-properties)))))))
    (org-buffers-list 'refresh)
    (unless headings-p (org-buffers-toggle-headings))))

(defun org-buffers-toggle-properties ()
  "Toggle entry properties in org-buffers listing buffer.
Removing properties may provide a less cluttered appearance for
browsing. However, in-buffer properties will be restored during
certain operations, such as `org-buffers-list:by'."
  (interactive)
  (if (org-buffers-state-get :properties)
      (progn (org-buffers-delete-properties)
	     (show-all)
	     (org-buffers-set-state '((:properties . nil))))
    (org-buffers-set-state
     '((:atom . heading) (:properties . t)))
    (org-buffers-list 'refresh)))

(defun org-buffers-toggle-headings ()
  "Toggle viewing of buffers as org headings.
Headings will be automatically restored during certain
operations, such as setting deletion tags."
  (interactive)
  (let ((inhibit-read-only t)
	(headings-p (org-buffers-state-eq :atom 'heading))
	(flat-p (org-buffers-state-eq :by "NONE")))
    (if (and headings-p (org-buffers-state-get :properties))
	(org-buffers-toggle-properties))
    (save-excursion
      (goto-char (point-min))
      (if (and (or headings-p (not flat-p))
	       (not (outline-on-heading-p)))
	  (outline-next-heading))
      (if flat-p
	  (progn 
	    (push-mark (point) 'nomsg 'activate)
	    (goto-char (point-max))
	    (org-ctrl-c-star)
	    (pop-mark))
	(while (not (eobp))
	  (push-mark
	   (save-excursion (forward-line 1) (point)) 'nomsg 'activate)
	  (org-forward-same-level 1)	
	  (org-ctrl-c-star)
	  (pop-mark)))
      (mark-whole-buffer)
      (indent-region (point-min) (point-max)))
    (org-buffers-set-state
     `((:atom . ,(if headings-p 'line 'heading))))))

(defun org-buffers-delete-properties ()
  (let ((inhibit-read-only t))
    (save-excursion
      (goto-char (point-min))
      (org-buffers-delete-regions
       (nreverse
	(org-buffers-map-entries 'org-buffers-get-property-block))))))

(defun org-buffers-get-property-block ()
  "Return the (beg . end) range of the property drawer.
Unlike the org version the limits include the keywords delimiting
the drawer."
  (let ((beg (point))
	(end (progn (outline-next-heading) (point))))
    (goto-char beg)
    (if (re-search-forward org-property-drawer-re end t)
	(cons (match-beginning 1) (match-end 0)))))

(defun org-buffers-group-by (property)
  "Group top level headings according to the value of PROPERTY."
  (let ((atom (org-buffers-state-get :atom)))
    (save-excursion
      (goto-char (point-min))
      (mapc (lambda (subtree) ;; Create subtree for each value of `property'
	      (org-insert-heading t)
	      (if (> (org-buffers-outline-level) 1)
		  (org-promote))
	      (insert (car subtree) "\n")
	      (org-insert-subheading t)
	      (mapc 'org-buffers-insert-parsed-entry (cdr subtree)))
	    (prog1
		(mapcar (lambda (val) ;; Form list of parsed entries for each unique value of `property'
			  (cons val (org-buffers-parse-selected-entries property val)))
			(sort
			 (delete-dups (org-buffers-map-entries (lambda () (org-entry-get nil property nil))))
			 'string<))
	      (erase-buffer))))))

(defun org-buffers-exclude-p (buffer)
  "Return non-nil if BUFFER should not be listed."
  (or (member (with-current-buffer buffer major-mode)
	      org-buffers-excluded-modes)
      (member buffer org-buffers-excluded-buffers)
      (string= (substring buffer 0 1) " ")))

(defun org-buffers-reset-state ()
  (org-buffers-set-state
   '((:by . "major-mode") (:atom . heading) (:properties . nil))))

(defun org-buffers-columns-view ()
  "View buffers in Org-mode columns view.
This is currently experimental. RET can be used to follow links
in the first column, but certain other org-buffers keys conflict
with column-view or otherwise do not work correctly."
  (interactive)
  (let ((inhibit-read-only t))
    (unless (org-buffers-state-get :properties)
      (org-buffers-toggle-properties))
    (save-excursion
      (goto-char (point-min))
      (org-columns))))

;;; Parsing and inserting entries
(defun org-buffers-parse-selected-entries (prop val)
  "Parse all entries with property PROP value VAL."
  (delq nil
	(org-buffers-map-entries
	 (lambda () (when (equal (org-entry-get nil prop) val)
		      (cons (org-get-heading) (org-get-entry)))))))

(defun org-buffers-insert-parsed-entry (entry)
  "Insert a parsed entry"
  (unless (org-at-heading-p) (org-insert-heading))
  (insert (car entry) "\n")
  (if (org-buffers-state-get :properties)
      (insert (cdr entry))))

(defun org-buffers-get-buffer-props (buffer)
  "Create alist of properties of BUFFER, as strings."
  (with-current-buffer buffer
    (mapcar 
     (lambda (pair) (cons (car pair) (eval (cdr pair))))
     org-buffers-buffer-properties)))

;;; Follow-link behaviour

(defun org-buffers-follow-link ()
  "Follow link to buffer on this line.
The buffer-switching behaviour of this function is determined by
the variable `org-buffers-follow-link-method'. See also
`org-buffers-switch-to-buffer' and
`org-buffers-switch-to-buffer-other-window', whose behaviour is
hard-wired."
  (interactive)
  (org-buffers-switch-to-buffer-generic org-buffers-follow-link-method))

(defun org-buffers-switch-to-buffer ()
"Switch to this entry's buffer in current window."
  (interactive)
  (org-buffers-switch-to-buffer-generic 'current-window))

(defun org-buffers-switch-to-buffer-other-window ()
  "Switch to this entry's buffer in other window."
  (interactive)
  (org-buffers-switch-to-buffer-generic 'other-window))

(defun org-buffers-switch-to-buffer-generic (method)
  (save-excursion
    (let ((atom (org-buffers-state-get :atom)) buffer)
      (cond
       ((eq atom 'heading) (org-back-to-heading))
       (t (beginning-of-line)))
      (setq buffer (org-buffers-get-buffer-name))
      (if (get-buffer buffer)
	  (case method
	    ('org-open-at-point (org-open-at-point))
	    ('current-window (switch-to-buffer buffer))
	    ('other-window (switch-to-buffer-other-window buffer)))
	(error "No such buffer: %s" buffer)))))

(defun org-buffers-get-buffer-name ()
  "Get buffer-name for current entry."
  (let ((headings-p (org-buffers-state-eq :atom 'heading)))
    (or (and headings-p (org-entry-get nil "buffer-name"))
	(and (save-excursion
	       (if headings-p (org-back-to-heading))
	       (re-search-forward "\\[\\[buffer:\\([^\]]*\\)" (point-at-eol) t))
	     (org-link-unescape (match-string 1))))))

;;; Setting tags and executing operations

(defun org-buffers-tag-for-deletion ()
  "Mark buffer for deletion.
If a region is selected, all buffers in the region are marked for
deletion. Buffers marked for deletion can be deleted using
`org-buffers-execute-pending-operations'."
  (interactive)
  (org-buffers-set-tags '("delete")))

(defun org-buffers-remove-tags ()
  "Remove deletion marks from buffers.
If a region is selected, marks are removed from all buffers in
the region."
  (interactive)
  (org-buffers-set-tags nil))

(defun org-buffers-set-tags (data)
  "Set tags to DATA at all non top-level headings in region.
DATA should be a list of strings. If DATA is nil, remove all tags
at such headings."
  (let* ((inhibit-read-only t)
	 (region-p (org-region-active-p))
	 (beg (if region-p (region-beginning) (point)))
	 (end (if region-p (region-end) (point)))
	 (headings-p (org-buffers-state-eq :atom 'heading))
	 beg-line end-line end-of-last-heading)
    (save-excursion
      (setq beg-line (progn (goto-char beg) (org-current-line))
	    end-line (progn (goto-char end) (org-current-line))
	    end-of-last-heading (progn (outline-end-of-heading) (point)))
      (if headings-p
	  (setq end (if (and region-p (not (eq end-line beg-line)) (not (eq end end-of-last-heading)))
			(progn (goto-char end) (org-back-to-heading) (point))
		      end-of-last-heading)
		beg (progn (goto-char beg) (point-at-bol)))
	(org-buffers-toggle-headings) ;; doesn't alter line numbers
	(setq beg (progn (org-goto-line beg-line) (point-at-bol))
	      end (if (eq end-line beg-line) (point-at-eol)
		    (progn (org-goto-line end-line) (point-at-bol)))))
      (narrow-to-region beg end)
      (goto-char (point-min))
      (org-buffers-map-entries
       (lambda ()
	 (when (or (org-buffers-state-eq :by "NONE")
		   (> (org-outline-level) 1))
	   (org-set-tags-to
	    (if data (delete-duplicates (append data (org-get-tags)) :test 'string-equal))))))
      (widen)
      (org-content))
    (unless region-p
      (outline-next-heading)
      (unless (or (> (org-outline-level) 1) (org-buffers-state-eq :by "NONE"))
	(outline-next-heading)))
        (unless headings-p (org-buffers-toggle-headings))))

(defun org-buffers-execute-pending-operations ()
  "Execute all pending operations.
Currently the only type of operation supported is
deletion. Buffers are tagged for deletion using
`org-buffers-tag-for-deletion'. Remove such tags from buffers
using `org-buffers-remove-tags'."
  (interactive)
  (let ((inhibit-read-only t)
	(headings-p (org-buffers-state-eq :atom 'heading)) buffer)
    (unless headings-p (org-buffers-toggle-headings))
    (org-buffers-delete-regions
     (nreverse
      (org-buffers-map-entries
       (lambda ()
	 (if (setq buffer (org-buffers-get-buffer-name))
	     (if (not (kill-buffer buffer))
		 (error "Failed to kill buffer %s" buffer)
	       (cons (point) (1+ (org-end-of-subtree))))))
       "+delete")))
    (org-buffers-delete-regions
     (nreverse
      (org-buffers-map-entries
       (lambda () (if (and (eq (org-outline-level) 1)
			   (eq (point-at-eol) (org-end-of-subtree)))
		      (cons (point-at-bol) (1+ (point))))))))
    (unless headings-p (org-buffers-toggle-headings))))

;;; Utilities

(defun org-buffers-map-entries (func &optional match)
  (org-scan-tags
   func (if match (cdr (org-make-tags-matcher match)) t)))
  
(defun org-buffers-set-state (state)
  "Add STATE to global state list.
New settings have precedence over existing ones."
  (mapc
   (lambda (pair) (unless (assoc (car pair) state)
		    (add-to-list 'state pair)))
   org-buffers-state)
  (setq org-buffers-state state))

(defmacro org-buffers-delete-regions (regions)
  "Delete regions in list.
REGIONS is a list of (beg . end) cons cells specifying buffer
regions."
  `(mapc (lambda (pair) (if pair (delete-region (car pair) (cdr pair))))
	 ,regions))

(defmacro org-buffers-state-get (key)
  `(cdr (assoc ,key org-buffers-state)))

(defmacro org-buffers-state-eq (key val)
  `(equal (org-buffers-state-get ,key) ,val))

(defmacro org-buffers-outline-level ()
  '(save-excursion (beginning-of-line) (org-outline-level)))

;;; Links to buffers

(org-add-link-type "buffer" 'display-buffer)
(add-hook 'org-store-link-functions 'org-buffers-store-link)

(defun org-buffers-store-link (&optional force)
  "Store a link to an Emacs buffer.
Returns nil by default, to avoid hijacking other link types."
  (if force
      (let* ((target (buffer-name))
	     (desc target) link)
	(org-store-link-props :type "buffer")
	(setq link (org-make-link "buffer:" target))
	(org-add-link-props :link link :description desc)
	link)))

(provide 'org-buffers)
;;; org-buffers.el ends here

[-- Attachment #3: Type: text/plain, Size: 201 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Please use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using Org for browsing and managing buffers
  2010-04-09  1:17 Using Org for browsing and managing buffers Dan Davison
  2010-04-09  3:43 ` Austin Frank
  2010-04-14 20:23 ` Eric S Fraga
@ 2010-04-15 10:11 ` Livin Stephen Sharma
  2010-04-15 21:21   ` Dan Davison
  2 siblings, 1 reply; 13+ messages in thread
From: Livin Stephen Sharma @ 2010-04-15 10:11 UTC (permalink / raw)
  To: emacs-org-mode-help gnu; +Cc: Dan Davison


[-- Attachment #1.1: Type: text/plain, Size: 21582 bytes --]

Am I the only one encountering:
> org-buffers-list: Invalid function: org-buffers-state-get


I do see many people are using this successfully
:)

Livin Stephen



On Apr 09, 2010, at 06:47:20 , Dan Davison wrote:

> I've been working on an Org tool to browse Emacs buffers. Emacs has the
> function list-buffers (C-x C-b), where you can view a list of buffers,
> delete buffers, etc. This is intended to be a replacement for
> list-buffers, implemented in Org-mode.
> 
> The code is attached, and there's a git repo at
> http://github.com/dandavison/org-buffers
> 
> After putting the code in your load-path and doing 
> (require 'org-buffers), use the function `org-buffers-list' to create
> the listing buffer. This is a read-only Org-mode buffer populated with
> links to open buffers. Information is stored for each buffer using
> properties. By default, the buffers are grouped by major mode. Here's a
> screenshot.
> 
> http://www.princeton.edu/~ddavison/org-buffers/by-major-mode.png
> 
> The buffer has some special key-bindings:
> 
> ?	Show all keybindings
> g	Update buffer (prefix arg does hard reset)
> b	Select a different property to group by
> RET	follow link to buffer on this line
> d	Mark buffer for deletion
> u	Remove mark
> x	Delete marked buffers
> o	Like RET (see variable org-buffers-follow-link-method)
> .	Like RET but switch to buffer in same window
> h	toggle between headings and plain entries for buffers
> p	toggle in-buffer properties on/off
> c	Switch to column-view
> 
> If there's an active region, d and u operate on all buffers in the
> region.
> 
> Some variables that can be configured:
> - org-buffers-buffer-properties
> - org-buffers-excluded-modes
> - org-buffers-excluded-buffers
> - org-buffers-follow-link-method
> - org-buffers-mode-hook
> - org-buffers-buffer-name
> 
> Some possible extensions:
> - Browse recent files using recentf
> - Allow several buffers to be marked for side-by-side display
> - Maintain folding configuration across buffer updates
> - Make faster
> 
> As always, any feedback, suggestions and patches will be very welcome!
> 
> Dan
> 
> p.s. The column-view mode works for following links, but does need
> further attention.
> 
> ;;; org-buffers.el --- An Org-mode tool for buffer management
> 
> ;; Copyright (C) 2010  Dan Davison
> 
> ;; Author: Dan Davison <dandavison0 at gmail dot com>
> ;; Keywords: outlines, hypermedia, calendar, wp
> ;; Homepage: http://orgmode.org
> 
> ;;; License:
> 
> ;; This program is free software; you can redistribute it and/or modify
> ;; it under the terms of the GNU General Public License as published by
> ;; the Free Software Foundation; either version 3, or (at your option)
> ;; any later version.
> ;;
> ;; This program is distributed in the hope that it will be useful,
> ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> ;; GNU General Public License for more details.
> ;;
> ;; You should have received a copy of the GNU General Public License
> ;; along with GNU Emacs; see the file COPYING.  If not, write to the
> ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
> ;; Boston, MA 02110-1301, USA.
> 
> ;;; Commentary:
> 
> ;;; Code:
> 
> (require 'org)
> (require 'cl)
> 
> ;;; Variables
> (defvar org-buffers-buffer-name
>  "*Buffers*"
>  "Name of buffer in which buffer list is displayed")
> 
> (defvar org-buffers-state
>  '((:by . "major-mode") (:atom . heading) (:properties . nil))
>  "Association list specifiying the current state of org-buffers.")
> 
> (defvar org-buffers-follow-link-method 'org-open-at-point
>  "Method used to follow link with RET. Must be one of
> 
> 'org-open-at-point :: use `org-open-at-point' to follow link.
> 'current-window    :: use switch-to-buffer
> 'other-window      :: use switch-to-buffer-other-window
> 
> Setting this variable to 'current-window makes the behaviour more
> consistent with that of `Buffer-menu-mode' and `dired-mode'")
> 
> (defvar org-buffers-buffer-properties
>  '(("buffer-name" . (buffer-name))
>    ("major-mode" . (let ((mode (symbol-name major-mode)))
> 		      (if (string-match "-mode$" mode)
> 			  (replace-match "" nil t mode) mode)))
>    ("buffer-file-name" . (buffer-file-name))
>    ("default-directory" . default-directory)
>    ("buffer-modified-p" . (format "%s" (buffer-modified-p))))
>  "Association list specifying properties to be stored for each
> buffer. The car of each element is the name of the property, and
> the cdr is an expression which, when evaluated in the buffer,
> yields the property value.")
> 
> (defcustom org-buffers-excluded-buffers
>  `("*Completions*" ,org-buffers-buffer-name)
>  "List of names of buffers that should not be listed by
>  org-buffers-list."
>  :group 'org-buffers)
> 
> (defcustom org-buffers-excluded-modes nil
>  "List of names of major-modes (strings) that should not be listed
>  by org-buffers-list."
>  :group 'org-buffers)
> 
> ;;; Mode
> (defvar org-buffers-mode-map (make-sparse-keymap))
> 
> (defvar org-buffers-mode-hook nil
>  "Hook for functions to be called after buffer listing is
>  created. Note that the buffer is read-only, so if the hook
>  function is to modify the buffer it should use a let binding to
>  temporarily bind buffer-read-only to nil.")
> 
> (define-minor-mode org-buffers-mode
>  "An Org-mode tool for buffer management.
> \\{org-buffers-mode-map}"
>  nil " buffers" nil
>  (org-set-local 'org-tag-alist '(("delete" . ?d)))
>  (org-set-local'org-tags-column -50)
>  (org-set-local 'org-columns-default-format "%25buffer-name(Buffer) %25major-mode(Mode) %25default-directory(Dir) %5buffer-modified-p(Modified)")
>  (add-hook 'kill-buffer-hook 'org-buffers-reset-state nil 'local))
> 
> (defun org-buffers-help ()
>  (interactive)
>  (describe-function 'org-buffers-mode))
> 
> ;;; Keys
> (define-key org-buffers-mode-map [(return)] 'org-buffers-follow-link)
> (define-key org-buffers-mode-map "b" 'org-buffers-list:by)
> (define-key org-buffers-mode-map "c" 'org-buffers-columns-view)
> (define-key org-buffers-mode-map "d" 'org-buffers-tag-for-deletion)
> (define-key org-buffers-mode-map "g" 'org-buffers-list:refresh)
> (define-key org-buffers-mode-map "." 'org-buffers-switch-to-buffer)
> (define-key org-buffers-mode-map "h" 'org-buffers-toggle-headings)
> (define-key org-buffers-mode-map "o" 'org-buffers-switch-to-buffer-other-window)
> (define-key org-buffers-mode-map "p" 'org-buffers-toggle-properties)
> (define-key org-buffers-mode-map "u" 'org-buffers-remove-tags)
> (define-key org-buffers-mode-map "x" 'org-buffers-execute-pending-operations)
> (define-key org-buffers-mode-map "?" 'org-buffers-help)
> ;;; Listing and view cycling
> 
> (defun org-buffers-list (&optional refresh frame)
>  "Create an Org-mode listing of Emacs buffers.
> By default, buffers are grouped by major mode. Optional
> argument FRAME specifies the frame whose buffers should be
> listed."
>  (interactive)
>  (pop-to-buffer
>   (or
>    (and (not refresh) (get-buffer org-buffers-buffer-name))
>    (let ((org-buffers-p (equal (buffer-name) org-buffers-buffer-name))
> 	  (by (or (org-buffers-state-get :by) "major-mode"))
> 	  (atom (org-buffers-state-get :atom)) target)
>      (when org-buffers-p
> 	(if (and (org-before-first-heading-p) (not (org-on-heading-p)))
> 	    (outline-next-heading))
> 	(setq target
> 	      (condition-case nil (org-make-org-heading-search-string) (error nil))))
>      (with-current-buffer (get-buffer-create org-buffers-buffer-name)
> 	(setq buffer-read-only nil)
> 	(erase-buffer)
> 	(org-mode)
> 	(dolist
> 	    (buffer
> 	     (sort (remove-if 'org-buffers-exclude-p
> 			      (mapcar 'buffer-name (buffer-list frame))) 'string<))
> 	  (org-insert-heading t)
> 	  (insert
> 	   (org-make-link-string (concat "buffer:" buffer) buffer) "\n")
> 	  (dolist (pair (org-buffers-get-buffer-props buffer))
> 	    (org-set-property (car pair) (cdr pair))))
> 	(org-buffers-set-state '((:atom . heading)))
> 	(goto-char (point-min))
> 	(unless (equal by "NONE") (org-buffers-group-by by))
> 	(if target (condition-case nil (org-link-search target) (error nil)))
> 	(beginning-of-line)
> 	(if (equal by "NONE")
> 	    (org-overview)
> 	  (case atom
> 	    ('heading (progn (org-overview) (org-content)))
> 	    ('line (progn (show-all) (org-buffers-toggle-headings)))))
> 	(save-excursion
> 	  (mark-whole-buffer)
> 	  (indent-region (point-min) (point-max)))
> 	(org-buffers-mode)
> 	(setq buffer-read-only t)
> 	(current-buffer))))))
> 
> (defun org-buffers-list:refresh (&optional arg)
>  "Refresh org-buffers listing."
>  (interactive "P")
>  (if arg (org-buffers-reset-state))
>  (org-buffers-list 'refresh))
> 
> (defun org-buffers-list:by (&optional prop)
>  "Group buffers according to value of property PROP."
>  (interactive)
>  (let ((buffer-read-only nil)
> 	(headings-p (org-buffers-state-eq :atom 'heading)))
>    (unless (org-buffers-state-get :properties)
>      (org-buffers-toggle-properties))
>    (org-buffers-set-state
>     `((:by .
> 	    ,(or prop
> 		 (org-completing-read
> 		  "Property to group by: "
> 		  (cons "NONE" (mapcar 'car org-buffers-buffer-properties)))))))
>    (org-buffers-list 'refresh)
>    (unless headings-p (org-buffers-toggle-headings))))
> 
> (defun org-buffers-toggle-properties ()
>  "Toggle entry properties in org-buffers listing buffer.
> Removing properties may provide a less cluttered appearance for
> browsing. However, in-buffer properties will be restored during
> certain operations, such as `org-buffers-list:by'."
>  (interactive)
>  (if (org-buffers-state-get :properties)
>      (progn (org-buffers-delete-properties)
> 	     (show-all)
> 	     (org-buffers-set-state '((:properties . nil))))
>    (org-buffers-set-state
>     '((:atom . heading) (:properties . t)))
>    (org-buffers-list 'refresh)))
> 
> (defun org-buffers-toggle-headings ()
>  "Toggle viewing of buffers as org headings.
> Headings will be automatically restored during certain
> operations, such as setting deletion tags."
>  (interactive)
>  (let ((buffer-read-only nil)
> 	(headings-p (org-buffers-state-eq :atom 'heading))
> 	(flat-p (org-buffers-state-eq :by "NONE")))
>    (if (and headings-p (org-buffers-state-get :properties))
> 	(org-buffers-toggle-properties))
>    (save-excursion
>      (goto-char (point-min))
>      (if (and (or headings-p (not flat-p))
> 	       (not (outline-on-heading-p)))
> 	  (outline-next-heading))
>      (if flat-p
> 	  (progn 
> 	    (push-mark (point) 'nomsg 'activate)
> 	    (end-of-buffer)
> 	    (org-ctrl-c-star)
> 	    (pop-mark))
> 	(while (not (eobp))
> 	  (push-mark
> 	   (save-excursion (forward-line 1) (point)) 'nomsg 'activate)
> 	  (org-forward-same-level 1)	
> 	  (org-ctrl-c-star)
> 	  (pop-mark)))
>      (mark-whole-buffer)
>      (indent-region (point-min) (point-max)))
>    (org-buffers-set-state
>     `((:atom . ,(if headings-p 'line 'heading))))))
> 
> (defun org-buffers-delete-properties ()
>  (let ((buffer-read-only nil))
>    (save-excursion
>      (goto-char (point-min))
>      (org-buffers-delete-regions
>       (nreverse
> 	(org-buffers-map-entries 'org-buffers-get-property-block))))))
> 
> (defun org-buffers-get-property-block ()
>  "Return the (beg . end) range of the property drawer.
> Unlike the org version the limits include the keywords delimiting
> the drawer."
>  (let ((beg (point))
> 	(end (progn (outline-next-heading) (point))))
>    (goto-char beg)
>    (if (re-search-forward org-property-drawer-re end t)
> 	(cons (match-beginning 1) (match-end 0)))))
> 
> (defun org-buffers-group-by (property)
>  "Group top level headings according to the value of PROPERTY."
>  (let ((atom (org-buffers-state-get :atom)))
>    (save-excursion
>      (goto-char (point-min))
>      (mapc (lambda (subtree) ;; Create subtree for each value of `property'
> 	      (org-insert-heading t)
> 	      (if (> (org-buffers-outline-level) 1)
> 		  (org-promote))
> 	      (insert (car subtree) "\n")
> 	      (org-insert-subheading t)
> 	      (mapc 'org-buffers-insert-parsed-entry (cdr subtree)))
> 	    (prog1
> 		(mapcar (lambda (val) ;; Form list of parsed entries for each unique value of `property'
> 			  (cons val (org-buffers-parse-selected-entries property val)))
> 			(sort
> 			 (delete-dups (org-buffers-map-entries (lambda () (org-entry-get nil property nil))))
> 			 'string<))
> 	      (erase-buffer))))))
> 
> (defun org-buffers-exclude-p (buffer)
>  "Return non-nil if BUFFER should not be listed."
>  (or (member (with-current-buffer buffer major-mode)
> 	      org-buffers-excluded-modes)
>      (member buffer org-buffers-excluded-buffers)
>      (string= (substring buffer 0 1) " ")))
> 
> (defun org-buffers-reset-state ()
>  (org-buffers-set-state
>   '((:by . "major-mode") (:atom . heading) (:properties . nil))))
> 
> (defun org-buffers-columns-view ()
>  "View buffers in Org-mode columns view.
> This is currently experimental. RET can be used to follow links
> in the first column, but certain other org-buffers keys conflict
> with column-view or otherwise do not work correctly."
>  (interactive)
>  (let ((by (org-buffers-state-get :by))
> 	(buffer-read-only nil))
>    (unless (equal by "NONE") (org-buffers-list:by "NONE"))
>    (unless (org-buffers-state-get :properties)
>      (org-buffers-toggle-properties))
>    (unless (equal by "NONE")
>      (goto-char (point-min))
>      (org-sort-entries-or-items nil ?r nil nil by)
>      (org-overview))
>    (mark-whole-buffer)
>    (org-columns)))
> 
> ;;; Parsing and inserting entries
> (defun org-buffers-parse-selected-entries (prop val)
>  "Parse all entries with property PROP value VAL."
>  (delq nil
> 	(org-buffers-map-entries
> 	 (lambda () (when (equal (org-entry-get nil prop) val)
> 		      (cons (org-get-heading) (org-get-entry)))))))
> 
> (defun org-buffers-insert-parsed-entry (entry)
>  "Insert a parsed entry"
>  (unless (org-at-heading-p) (org-insert-heading))
>  (insert (car entry) "\n")
>  (if (org-buffers-state-get :properties)
>      (insert (cdr entry))))
> 
> (defun org-buffers-get-buffer-props (buffer)
>  "Create alist of properties of BUFFER, as strings."
>  (with-current-buffer buffer
>    (mapcar 
>     (lambda (pair) (cons (car pair) (eval (cdr pair))))
>     org-buffers-buffer-properties)))
> 
> ;;; Follow-link behaviour
> 
> (defun org-buffers-follow-link ()
>  "Follow link to buffer on this line.
> The buffer-switching behaviour of this function is determined by
> the variable `org-buffers-follow-link-method'. See also
> `org-buffers-switch-to-buffer' and
> `org-buffers-switch-to-buffer-other-window', whose behaviour is
> hard-wired."
>  (interactive)
>  (org-buffers-switch-to-buffer-generic org-buffers-follow-link-method))
> 
> (defun org-buffers-switch-to-buffer ()
> "Switch to this entry's buffer in current window."
>  (interactive)
>  (org-buffers-switch-to-buffer-generic 'current-window))
> 
> (defun org-buffers-switch-to-buffer-other-window ()
>  "Switch to this entry's buffer in other window."
>  (interactive)
>  (org-buffers-switch-to-buffer-generic 'other-window))
> 
> (defun org-buffers-switch-to-buffer-generic (method)
>  (save-excursion
>    (let ((atom (org-buffers-state-get :atom)) buffer)
>      (cond
>       ((eq atom 'heading) (org-back-to-heading))
>       (t (beginning-of-line)))
>      (setq buffer (org-buffers-get-buffer-name))
>      (if (get-buffer buffer)
> 	  (case method
> 	    ('org-open-at-point (org-open-at-point))
> 	    ('current-window (switch-to-buffer buffer))
> 	    ('other-window (switch-to-buffer-other-window buffer)))
> 	(error "No such buffer: %s" buffer)))))
> 
> (defun org-buffers-get-buffer-name ()
>  "Get buffer-name for current entry."
>  (let ((headings-p (org-buffers-state-eq :atom 'heading)))
>    (or (and headings-p (org-entry-get nil "buffer-name"))
> 	(and (save-excursion
> 	       (if headings-p (org-back-to-heading))
> 	       (re-search-forward "\\[\\[buffer:\\([^\]]*\\)" (point-at-eol) t))
> 	     (org-link-unescape (match-string 1))))))
> 
> ;;; Setting tags and executing operations
> 
> (defun org-buffers-tag-for-deletion ()
>  "Mark buffer for deletion.
> If a region is selected, all buffers in the region are marked for
> deletion. Buffers marked for deletion can be deleted using
> `org-buffers-execute-pending-operations'."
>  (interactive)
>  (org-buffers-set-tags '("delete")))
> 
> (defun org-buffers-remove-tags ()
>  "Remove deletion marks from buffers.
> If a region is selected, marks are removed from all buffers in
> the region."
>  (interactive)
>  (org-buffers-set-tags nil))
> 
> (defun org-buffers-set-tags (data)
>  "Set tags to DATA at all non top-level headings in region.
> DATA should be a list of strings. If DATA is nil, remove all tags
> at such headings."
>  (let* ((buffer-read-only nil)
> 	 (region-p (org-region-active-p))
> 	 (beg (if region-p (region-beginning) (point)))
> 	 (end (if region-p (region-end) (point)))
> 	 (headings-p (org-buffers-state-eq :atom 'heading))beg-line end-line)
>    (save-excursion
>      (setq beg-line (progn (goto-char beg) (org-current-line))
> 	    end-line (progn (goto-char end) (org-current-line)))
>      (if headings-p
> 	  (setq
> 	   end (if (and region-p (not (eq end-line beg-line)) (not (eobp)))
> 		   (progn (goto-char end) (org-back-to-heading) (point))
> 		 (progn (outline-end-of-heading) (point)))
> 	   beg (progn (goto-char beg) (point-at-bol)))
> 	(org-buffers-toggle-headings) ;; doesn't alter line numbers
> 	(setq beg (progn (org-goto-line beg-line) (point-at-bol))
> 	      end (if (eq end-line beg-line) (point-at-eol)
> 		    (progn (org-goto-line end-line) (point-at-bol)))))
>      (narrow-to-region beg end)
>      (goto-char (point-min))
>      (org-buffers-map-entries
>       (lambda ()
> 	 (when (or (org-buffers-state-eq :by "NONE")
> 		   (> (org-outline-level) 1))
> 	   (org-set-tags-to
> 	    (if data (delete-duplicates (append data (org-get-tags)) :test 'string-equal))))))
>      (widen)
>      (org-content))
>    (unless region-p
>      (outline-next-heading)
>      (unless (or (> (org-outline-level) 1) (org-buffers-state-eq :by "NONE"))
> 	(outline-next-heading)))
>        (unless headings-p (org-buffers-toggle-headings))))
> 
> (defun org-buffers-execute-pending-operations ()
>  "Execute all pending operations.
> Currently the only type of operation supported is
> deletion. Buffers are tagged for deletion using
> `org-buffers-tag-for-deletion'. Remove such tags from buffers
> using `org-buffers-remove-tags'."
>  (interactive)
>  (let ((buffer-read-only nil)
> 	(headings-p (org-buffers-state-eq :atom 'heading)) buffer)
>    (unless headings-p (org-buffers-toggle-headings))
>    (org-buffers-delete-regions
>     (nreverse
>      (org-buffers-map-entries
>       (lambda ()
> 	 (if (setq buffer (org-buffers-get-buffer-name))
> 	     (if (not (kill-buffer buffer))
> 		 (error "Failed to kill buffer %s" buffer)
> 	       (if (and (org-first-sibling-p)
> 			(not (save-excursion (org-goto-sibling))))
> 		   (org-up-heading-safe)) ;; Only child so delete parent also
> 	       (cons (point) (1+ (org-end-of-subtree))))))
>       "+delete")))
>    (unless headings-p (org-buffers-toggle-headings))))
> 
> ;;; Utilities
> 
> (defun org-buffers-map-entries (func &optional match)
>  (org-scan-tags
>   func (if match (cdr (org-make-tags-matcher match)) t)))
> 
> (defun org-buffers-set-state (state)
>  "Add STATE to global state list.
> New settings have precedence over existing ones."
>  (mapc
>   (lambda (pair) (unless (assoc (car pair) state)
> 		    (add-to-list 'state pair)))
>   org-buffers-state)
>  (setq org-buffers-state state))
> 
> (defmacro org-buffers-delete-regions (regions)
>  "Delete regions in list.
> REGIONS is a list of (beg . end) cons cells specifying buffer
> regions."
>  `(mapc (lambda (pair) (if pair (delete-region (car pair) (cdr pair))))
> 	 ,regions))
> 
> (defmacro org-buffers-state-get (key)
>  `(cdr (assoc ,key org-buffers-state)))
> 
> (defmacro org-buffers-state-eq (key val)
>  `(equal (org-buffers-state-get ,key) ,val))
> 
> (defmacro org-buffers-outline-level ()
>  '(save-excursion (beginning-of-line) (org-outline-level)))
> 
> ;;; Links to buffers
> 
> (org-add-link-type "buffer" 'display-buffer)
> (add-hook 'org-store-link-functions 'org-buffers-store-link)
> 
> (defun org-buffers-store-link (&optional force)
>  "Store a link to an Emacs buffer.
> Returns nil by default, to avoid hijacking other link types."
>  (if force
>      (let* ((target (buffer-name))
> 	     (desc target) link)
> 	(org-store-link-props :type "buffer")
> 	(setq link (org-make-link "buffer:" target))
> 	(org-add-link-props :link link :description desc)
> 	link)))
> 
> (provide 'org-buffers)
> ;;; org-buffers.el ends here
> _______________________________________________
> Emacs-orgmode mailing list
> Please use `Reply All' to send replies to the list.
> Emacs-orgmode@gnu.org
> http://lists.gnu.org/mailman/listinfo/emacs-orgmode


[-- Attachment #1.2: Type: text/html, Size: 35200 bytes --]

[-- Attachment #2: Type: text/plain, Size: 201 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Please use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using Org for browsing and managing buffers
  2010-04-15  4:20   ` Dan Davison
@ 2010-04-15 12:18     ` Eric S Fraga
  2010-04-19  3:47       ` Dan Davison
  0 siblings, 1 reply; 13+ messages in thread
From: Eric S Fraga @ 2010-04-15 12:18 UTC (permalink / raw)
  To: Dan Davison; +Cc: emacs org-mode mailing list

On Thu, 15 Apr 2010 00:20:31 -0400, Dan Davison <davison@stats.ox.ac.uk> wrote:

[...]

> This does also mean that various inappropriate speed commands become
> exposed (but then pressing random keys is a strategy that should be
> confined to gnus).

;-)

> I've made them narrower by default, and introduced a customizable
> variable org-buffers-columns-format.

Excellent.

> Noted. On the other hand o in Org speed commands is bound to
> org-open-at-point. I've got rid of my binding and am allowing it to fall
> through to the speed command default but I'd welcome any further
> suggestions. Note that the variable org-buffers-follow-link-method can
> be used so specify the behaviour of RET on a line with a buffer link.

Some more comments:

- I like the fact I can customise RET or, more to the point, that it
  be consistent with the rest of org-mode.  I personally would set
  org-buffers-follow-link-method to 'current-window but then it would
  be nice to have SPC, say, open the buffer in another window, to
  behave consistently with org-agenda?

- I would prefer some consistency or symmetry in the creation and
  burying of the buffer: given that (by default) org-buffers-list
  brings up a new window in the current frame, quitting that buffer
  should also delete the window;  otherwise, I would like it to not
  split the frame.  Does that make sense?

- what's the point of orb-buffers-toggle-heading?  I ask because I
  don't understand what functionality it adds and the default binding
  (h) conflicts with my speed keys (I use vi-like bindings for speed
  motion keys).

- In column view mode (which I also have not figured out why it would
  be used...), the heading uses a different font size than the normal
  entries so the headings don't line up at all.  This may be my fault,
  however.

- if I bring up the buffers list a second time, having created a new
  buffer in the meantime, the new buffer does not appear until I hit
  'g'.  I think any invocation of org-buffers-list should do an
  automatic update of the list.

- Lastly, it would be nice to either avoid the single blank line at
  the start of the buffer or have point be at the first heading.
  Having point at the first (empty) line seems to cause some problems
  with speed motion keys sometimes...  it also wastes a line!

  Actually, I think it might be useful to have point be placed at the
  heading that corresponds to the buffer currently being visited when
  the org-buffers-list command is invoked.  A thought.

In any case, it's almost ready for me to replace my current C-xC-b
binding... :)

> I haven't used bs-show. It might be interesting to try to get some

bs-show has a nice feature which allows different classes of buffers
to be shown and to cycle through the different views easily.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using Org for browsing and managing buffers
  2010-04-15 10:11 ` Livin Stephen Sharma
@ 2010-04-15 21:21   ` Dan Davison
  2010-04-16  7:11     ` Livin Stephen Sharma
  0 siblings, 1 reply; 13+ messages in thread
From: Dan Davison @ 2010-04-15 21:21 UTC (permalink / raw)
  To: Livin Stephen Sharma; +Cc: emacs-org-mode-help gnu

Livin Stephen Sharma <livin.stephen@gmail.com> writes:

> Am I the only one encountering:
>
>     org-buffers-list: Invalid function: org-buffers-state-get

I haven't seen that error, but I may have been doing something incorrect
(with macros). I've got rid of them now; let me know if you still get
the error.

Code file: http://github.com/dandavison/org-buffers/raw/master/org-buffers.el
Git repo:  http://github.com/dandavison/org-buffers

Thanks,

Dan


>
>
>
> I do see many people are using this successfully
> :)
>
> Livin Stephen
>
>
>
> On Apr 09, 2010, at 06:47:20 , Dan Davison wrote:
>
>
>     I've been working on an Org tool to browse Emacs buffers. Emacs has the
>     function list-buffers (C-x C-b), where you can view a list of buffers,
>     delete buffers, etc. This is intended to be a replacement for
>     list-buffers, implemented in Org-mode.
>
>     The code is attached, and there's a git repo at
>     http://github.com/dandavison/org-buffers
>
>     After putting the code in your load-path and doing
>     (require 'org-buffers), use the function `org-buffers-list' to create
>     the listing buffer. This is a read-only Org-mode buffer populated with
>     links to open buffers. Information is stored for each buffer using
>     properties. By default, the buffers are grouped by major mode. Here's a
>     screenshot.
>
>     http://www.princeton.edu/~ddavison/org-buffers/by-major-mode.png
>
>     The buffer has some special key-bindings:
>
>     +--------------------------------------------------------------+
>     | ?   | Show all keybindings                                   |
>     |-----+--------------------------------------------------------|
>     | g   | Update buffer (prefix arg does hard reset)             |
>     |-----+--------------------------------------------------------|
>     | b   | Select a different property to group by                |
>     |-----+--------------------------------------------------------|
>     | RET | follow link to buffer on this line                     |
>     |-----+--------------------------------------------------------|
>     | d   | Mark buffer for deletion                               |
>     |-----+--------------------------------------------------------|
>     | u   | Remove mark                                            |
>     |-----+--------------------------------------------------------|
>     | x   | Delete marked buffers                                  |
>     |-----+--------------------------------------------------------|
>     | o   | Like RET (see variable org-buffers-follow-link-method) |
>     |-----+--------------------------------------------------------|
>     | .   | Like RET but switch to buffer in same window           |
>     |-----+--------------------------------------------------------|
>     | h   | toggle between headings and plain entries for buffers  |
>     |-----+--------------------------------------------------------|
>     | p   | toggle in-buffer properties on/off                     |
>     |-----+--------------------------------------------------------|
>     | c   | Switch to column-view                                  |
>     +--------------------------------------------------------------+
>
>     If there's an active region, d and u operate on all buffers in the
>     region.
>
>     Some variables that can be configured:
>     - org-buffers-buffer-properties
>     - org-buffers-excluded-modes
>     - org-buffers-excluded-buffers
>     - org-buffers-follow-link-method
>     - org-buffers-mode-hook
>     - org-buffers-buffer-name
>
>     Some possible extensions:
>     - Browse recent files using recentf
>     - Allow several buffers to be marked for side-by-side display
>     - Maintain folding configuration across buffer updates
>     - Make faster
>
>     As always, any feedback, suggestions and patches will be very welcome!
>
>     Dan
>
>     p.s. The column-view mode works for following links, but does need
>     further attention.
>
>     ;;; org-buffers.el --- An Org-mode tool for buffer management
>
>     ;; Copyright (C) 2010  Dan Davison
>
>     ;; Author: Dan Davison <dandavison0 at gmail dot com>
>     ;; Keywords: outlines, hypermedia, calendar, wp
>     ;; Homepage: http://orgmode.org
>
>     ;;; License:
>
>     ;; This program is free software; you can redistribute it and/or modify
>     ;; it under the terms of the GNU General Public License as published by
>     ;; the Free Software Foundation; either version 3, or (at your option)
>     ;; any later version.
>     ;;
>     ;; This program is distributed in the hope that it will be useful,
>     ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
>     ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>     ;; GNU General Public License for more details.
>     ;;
>     ;; You should have received a copy of the GNU General Public License
>     ;; along with GNU Emacs; see the file COPYING.  If not, write to the
>     ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
>     ;; Boston, MA 02110-1301, USA.
>
>     ;;; Commentary:
>
>     ;;; Code:
>
>     (require 'org)
>     (require 'cl)
>
>     ;;; Variables
>     (defvar org-buffers-buffer-name
>      "*Buffers*"
>      "Name of buffer in which buffer list is displayed")
>
>     (defvar org-buffers-state
>      '((:by . "major-mode") (:atom . heading) (:properties . nil))
>      "Association list specifiying the current state of org-buffers.")
>
>     (defvar org-buffers-follow-link-method 'org-open-at-point
>      "Method used to follow link with RET. Must be one of
>
>     'org-open-at-point :: use `org-open-at-point' to follow link.
>     'current-window    :: use switch-to-buffer
>     'other-window      :: use switch-to-buffer-other-window
>
>     Setting this variable to 'current-window makes the behaviour more
>     consistent with that of `Buffer-menu-mode' and `dired-mode'")
>
>     (defvar org-buffers-buffer-properties
>      '(("buffer-name" . (buffer-name))
>        ("major-mode" . (let ((mode (symbol-name major-mode)))
>          (if (string-match "-mode$" mode)
>      (replace-match "" nil t mode) mode)))
>        ("buffer-file-name" . (buffer-file-name))
>        ("default-directory" . default-directory)
>        ("buffer-modified-p" . (format "%s" (buffer-modified-p))))
>      "Association list specifying properties to be stored for each
>     buffer. The car of each element is the name of the property, and
>     the cdr is an expression which, when evaluated in the buffer,
>     yields the property value.")
>
>     (defcustom org-buffers-excluded-buffers
>      `("*Completions*" ,org-buffers-buffer-name)
>      "List of names of buffers that should not be listed by
>      org-buffers-list."
>      :group 'org-buffers)
>
>     (defcustom org-buffers-excluded-modes nil
>      "List of names of major-modes (strings) that should not be listed
>      by org-buffers-list."
>      :group 'org-buffers)
>
>     ;;; Mode
>     (defvar org-buffers-mode-map (make-sparse-keymap))
>
>     (defvar org-buffers-mode-hook nil
>      "Hook for functions to be called after buffer listing is
>      created. Note that the buffer is read-only, so if the hook
>      function is to modify the buffer it should use a let binding to
>      temporarily bind buffer-read-only to nil.")
>
>     (define-minor-mode org-buffers-mode
>      "An Org-mode tool for buffer management.
>     \\{org-buffers-mode-map}"
>      nil " buffers" nil
>      (org-set-local 'org-tag-alist '(("delete" . ?d)))
>      (org-set-local'org-tags-column -50)
>      (org-set-local 'org-columns-default-format "%25buffer-name(Buffer)
>     %25major-mode(Mode) %25default-directory(Dir) %5buffer-modified-p(Modified)
>     ")
>      (add-hook 'kill-buffer-hook 'org-buffers-reset-state nil 'local))
>
>     (defun org-buffers-help ()
>      (interactive)
>      (describe-function 'org-buffers-mode))
>
>     ;;; Keys
>     (define-key org-buffers-mode-map [(return)] 'org-buffers-follow-link)
>     (define-key org-buffers-mode-map "b" 'org-buffers-list:by)
>     (define-key org-buffers-mode-map "c" 'org-buffers-columns-view)
>     (define-key org-buffers-mode-map "d" 'org-buffers-tag-for-deletion)
>     (define-key org-buffers-mode-map "g" 'org-buffers-list:refresh)
>     (define-key org-buffers-mode-map "." 'org-buffers-switch-to-buffer)
>     (define-key org-buffers-mode-map "h" 'org-buffers-toggle-headings)
>     (define-key org-buffers-mode-map "o"
>     'org-buffers-switch-to-buffer-other-window)
>     (define-key org-buffers-mode-map "p" 'org-buffers-toggle-properties)
>     (define-key org-buffers-mode-map "u" 'org-buffers-remove-tags)
>     (define-key org-buffers-mode-map "x"
>     'org-buffers-execute-pending-operations)
>     (define-key org-buffers-mode-map "?" 'org-buffers-help)
>     ;;; Listing and view cycling
>
>     (defun org-buffers-list (&optional refresh frame)
>      "Create an Org-mode listing of Emacs buffers.
>     By default, buffers are grouped by major mode. Optional
>     argument FRAME specifies the frame whose buffers should be
>     listed."
>      (interactive)
>      (pop-to-buffer
>       (or
>        (and (not refresh) (get-buffer org-buffers-buffer-name))
>        (let ((org-buffers-p (equal (buffer-name) org-buffers-buffer-name))
>      (by (or (org-buffers-state-get :by) "major-mode"))
>      (atom (org-buffers-state-get :atom)) target)
>          (when org-buffers-p
>     (if (and (org-before-first-heading-p) (not (org-on-heading-p)))
>        (outline-next-heading))
>     (setq target
>          (condition-case nil (org-make-org-heading-search-string) (error
>     nil))))
>          (with-current-buffer (get-buffer-create org-buffers-buffer-name)
>     (setq buffer-read-only nil)
>     (erase-buffer)
>     (org-mode)
>     (dolist
>        (buffer
>         (sort (remove-if 'org-buffers-exclude-p
>          (mapcar 'buffer-name (buffer-list frame))) 'string<))
>      (org-insert-heading t)
>      (insert
>       (org-make-link-string (concat "buffer:" buffer) buffer) "\n")
>      (dolist (pair (org-buffers-get-buffer-props buffer))
>        (org-set-property (car pair) (cdr pair))))
>     (org-buffers-set-state '((:atom . heading)))
>     (goto-char (point-min))
>     (unless (equal by "NONE") (org-buffers-group-by by))
>     (if target (condition-case nil (org-link-search target) (error nil)))
>     (beginning-of-line)
>     (if (equal by "NONE")
>        (org-overview)
>      (case atom
>        ('heading (progn (org-overview) (org-content)))
>        ('line (progn (show-all) (org-buffers-toggle-headings)))))
>     (save-excursion
>      (mark-whole-buffer)
>      (indent-region (point-min) (point-max)))
>     (org-buffers-mode)
>     (setq buffer-read-only t)
>     (current-buffer))))))
>
>     (defun org-buffers-list:refresh (&optional arg)
>      "Refresh org-buffers listing."
>      (interactive "P")
>      (if arg (org-buffers-reset-state))
>      (org-buffers-list 'refresh))
>
>     (defun org-buffers-list:by (&optional prop)
>      "Group buffers according to value of property PROP."
>      (interactive)
>      (let ((buffer-read-only nil)
>     (headings-p (org-buffers-state-eq :atom 'heading)))
>        (unless (org-buffers-state-get :properties)
>          (org-buffers-toggle-properties))
>        (org-buffers-set-state
>         `((:by .
>        ,(or prop
>     (org-completing-read
>      "Property to group by: "
>      (cons "NONE" (mapcar 'car org-buffers-buffer-properties)))))))
>        (org-buffers-list 'refresh)
>        (unless headings-p (org-buffers-toggle-headings))))
>
>     (defun org-buffers-toggle-properties ()
>      "Toggle entry properties in org-buffers listing buffer.
>     Removing properties may provide a less cluttered appearance for
>     browsing. However, in-buffer properties will be restored during
>     certain operations, such as `org-buffers-list:by'."
>      (interactive)
>      (if (org-buffers-state-get :properties)
>          (progn (org-buffers-delete-properties)
>         (show-all)
>         (org-buffers-set-state '((:properties . nil))))
>        (org-buffers-set-state
>         '((:atom . heading) (:properties . t)))
>        (org-buffers-list 'refresh)))
>
>     (defun org-buffers-toggle-headings ()
>      "Toggle viewing of buffers as org headings.
>     Headings will be automatically restored during certain
>     operations, such as setting deletion tags."
>      (interactive)
>      (let ((buffer-read-only nil)
>     (headings-p (org-buffers-state-eq :atom 'heading))
>     (flat-p (org-buffers-state-eq :by "NONE")))
>        (if (and headings-p (org-buffers-state-get :properties))
>     (org-buffers-toggle-properties))
>        (save-excursion
>          (goto-char (point-min))
>          (if (and (or headings-p (not flat-p))
>           (not (outline-on-heading-p)))
>      (outline-next-heading))
>          (if flat-p
>      (progn
>        (push-mark (point) 'nomsg 'activate)
>        (end-of-buffer)
>        (org-ctrl-c-star)
>        (pop-mark))
>     (while (not (eobp))
>      (push-mark
>       (save-excursion (forward-line 1) (point)) 'nomsg 'activate)
>      (org-forward-same-level 1)
>      (org-ctrl-c-star)
>      (pop-mark)))
>          (mark-whole-buffer)
>          (indent-region (point-min) (point-max)))
>        (org-buffers-set-state
>         `((:atom . ,(if headings-p 'line 'heading))))))
>
>     (defun org-buffers-delete-properties ()
>      (let ((buffer-read-only nil))
>        (save-excursion
>          (goto-char (point-min))
>          (org-buffers-delete-regions
>           (nreverse
>     (org-buffers-map-entries 'org-buffers-get-property-block))))))
>
>     (defun org-buffers-get-property-block ()
>      "Return the (beg . end) range of the property drawer.
>     Unlike the org version the limits include the keywords delimiting
>     the drawer."
>      (let ((beg (point))
>     (end (progn (outline-next-heading) (point))))
>        (goto-char beg)
>        (if (re-search-forward org-property-drawer-re end t)
>     (cons (match-beginning 1) (match-end 0)))))
>
>     (defun org-buffers-group-by (property)
>      "Group top level headings according to the value of PROPERTY."
>      (let ((atom (org-buffers-state-get :atom)))
>        (save-excursion
>          (goto-char (point-min))
>          (mapc (lambda (subtree) ;; Create subtree for each value of `property'
>          (org-insert-heading t)
>          (if (> (org-buffers-outline-level) 1)
>      (org-promote))
>          (insert (car subtree) "\n")
>          (org-insert-subheading t)
>          (mapc 'org-buffers-insert-parsed-entry (cdr subtree)))
>        (prog1
>     (mapcar (lambda (val) ;; Form list of parsed entries for each unique value
>     of `property'
>      (cons val (org-buffers-parse-selected-entries property val)))
>     (sort
>     (delete-dups (org-buffers-map-entries (lambda () (org-entry-get nil
>     property nil))))
>     'string<))
>          (erase-buffer))))))
>
>     (defun org-buffers-exclude-p (buffer)
>      "Return non-nil if BUFFER should not be listed."
>      (or (member (with-current-buffer buffer major-mode)
>          org-buffers-excluded-modes)
>          (member buffer org-buffers-excluded-buffers)
>          (string= (substring buffer 0 1) " ")))
>
>     (defun org-buffers-reset-state ()
>      (org-buffers-set-state
>       '((:by . "major-mode") (:atom . heading) (:properties . nil))))
>
>     (defun org-buffers-columns-view ()
>      "View buffers in Org-mode columns view.
>     This is currently experimental. RET can be used to follow links
>     in the first column, but certain other org-buffers keys conflict
>     with column-view or otherwise do not work correctly."
>      (interactive)
>      (let ((by (org-buffers-state-get :by))
>     (buffer-read-only nil))
>        (unless (equal by "NONE") (org-buffers-list:by "NONE"))
>        (unless (org-buffers-state-get :properties)
>          (org-buffers-toggle-properties))
>        (unless (equal by "NONE")
>          (goto-char (point-min))
>          (org-sort-entries-or-items nil ?r nil nil by)
>          (org-overview))
>        (mark-whole-buffer)
>        (org-columns)))
>
>     ;;; Parsing and inserting entries
>     (defun org-buffers-parse-selected-entries (prop val)
>      "Parse all entries with property PROP value VAL."
>      (delq nil
>     (org-buffers-map-entries
>     (lambda () (when (equal (org-entry-get nil prop) val)
>          (cons (org-get-heading) (org-get-entry)))))))
>
>     (defun org-buffers-insert-parsed-entry (entry)
>      "Insert a parsed entry"
>      (unless (org-at-heading-p) (org-insert-heading))
>      (insert (car entry) "\n")
>      (if (org-buffers-state-get :properties)
>          (insert (cdr entry))))
>
>     (defun org-buffers-get-buffer-props (buffer)
>      "Create alist of properties of BUFFER, as strings."
>      (with-current-buffer buffer
>        (mapcar
>         (lambda (pair) (cons (car pair) (eval (cdr pair))))
>         org-buffers-buffer-properties)))
>
>     ;;; Follow-link behaviour
>
>     (defun org-buffers-follow-link ()
>      "Follow link to buffer on this line.
>     The buffer-switching behaviour of this function is determined by
>     the variable `org-buffers-follow-link-method'. See also
>     `org-buffers-switch-to-buffer' and
>     `org-buffers-switch-to-buffer-other-window', whose behaviour is
>     hard-wired."
>      (interactive)
>      (org-buffers-switch-to-buffer-generic org-buffers-follow-link-method))
>
>     (defun org-buffers-switch-to-buffer ()
>     "Switch to this entry's buffer in current window."
>      (interactive)
>      (org-buffers-switch-to-buffer-generic 'current-window))
>
>     (defun org-buffers-switch-to-buffer-other-window ()
>      "Switch to this entry's buffer in other window."
>      (interactive)
>      (org-buffers-switch-to-buffer-generic 'other-window))
>
>     (defun org-buffers-switch-to-buffer-generic (method)
>      (save-excursion
>        (let ((atom (org-buffers-state-get :atom)) buffer)
>          (cond
>           ((eq atom 'heading) (org-back-to-heading))
>           (t (beginning-of-line)))
>          (setq buffer (org-buffers-get-buffer-name))
>          (if (get-buffer buffer)
>      (case method
>        ('org-open-at-point (org-open-at-point))
>        ('current-window (switch-to-buffer buffer))
>        ('other-window (switch-to-buffer-other-window buffer)))
>     (error "No such buffer: %s" buffer)))))
>
>     (defun org-buffers-get-buffer-name ()
>      "Get buffer-name for current entry."
>      (let ((headings-p (org-buffers-state-eq :atom 'heading)))
>        (or (and headings-p (org-entry-get nil "buffer-name"))
>     (and (save-excursion
>           (if headings-p (org-back-to-heading))
>           (re-search-forward "\\[\\[buffer:\\([^\]]*\\)" (point-at-eol) t))
>         (org-link-unescape (match-string 1))))))
>
>     ;;; Setting tags and executing operations
>
>     (defun org-buffers-tag-for-deletion ()
>      "Mark buffer for deletion.
>     If a region is selected, all buffers in the region are marked for
>     deletion. Buffers marked for deletion can be deleted using
>     `org-buffers-execute-pending-operations'."
>      (interactive)
>      (org-buffers-set-tags '("delete")))
>
>     (defun org-buffers-remove-tags ()
>      "Remove deletion marks from buffers.
>     If a region is selected, marks are removed from all buffers in
>     the region."
>      (interactive)
>      (org-buffers-set-tags nil))
>
>     (defun org-buffers-set-tags (data)
>      "Set tags to DATA at all non top-level headings in region.
>     DATA should be a list of strings. If DATA is nil, remove all tags
>     at such headings."
>      (let* ((buffer-read-only nil)
>     (region-p (org-region-active-p))
>     (beg (if region-p (region-beginning) (point)))
>     (end (if region-p (region-end) (point)))
>     (headings-p (org-buffers-state-eq :atom 'heading))beg-line end-line)
>        (save-excursion
>          (setq beg-line (progn (goto-char beg) (org-current-line))
>        end-line (progn (goto-char end) (org-current-line)))
>          (if headings-p
>      (setq
>       end (if (and region-p (not (eq end-line beg-line)) (not (eobp)))
>       (progn (goto-char end) (org-back-to-heading) (point))
>     (progn (outline-end-of-heading) (point)))
>       beg (progn (goto-char beg) (point-at-bol)))
>     (org-buffers-toggle-headings) ;; doesn't alter line numbers
>     (setq beg (progn (org-goto-line beg-line) (point-at-bol))
>          end (if (eq end-line beg-line) (point-at-eol)
>        (progn (org-goto-line end-line) (point-at-bol)))))
>          (narrow-to-region beg end)
>          (goto-char (point-min))
>          (org-buffers-map-entries
>           (lambda ()
>     (when (or (org-buffers-state-eq :by "NONE")
>       (> (org-outline-level) 1))
>       (org-set-tags-to
>        (if data (delete-duplicates (append data (org-get-tags)) :test
>     'string-equal))))))
>          (widen)
>          (org-content))
>        (unless region-p
>          (outline-next-heading)
>          (unless (or (> (org-outline-level) 1) (org-buffers-state-eq :by
>     "NONE"))
>     (outline-next-heading)))
>            (unless headings-p (org-buffers-toggle-headings))))
>
>     (defun org-buffers-execute-pending-operations ()
>      "Execute all pending operations.
>     Currently the only type of operation supported is
>     deletion. Buffers are tagged for deletion using
>     `org-buffers-tag-for-deletion'. Remove such tags from buffers
>     using `org-buffers-remove-tags'."
>      (interactive)
>      (let ((buffer-read-only nil)
>     (headings-p (org-buffers-state-eq :atom 'heading)) buffer)
>        (unless headings-p (org-buffers-toggle-headings))
>        (org-buffers-delete-regions
>         (nreverse
>          (org-buffers-map-entries
>           (lambda ()
>     (if (setq buffer (org-buffers-get-buffer-name))
>         (if (not (kill-buffer buffer))
>     (error "Failed to kill buffer %s" buffer)
>           (if (and (org-first-sibling-p)
>     (not (save-excursion (org-goto-sibling))))
>       (org-up-heading-safe)) ;; Only child so delete parent also
>           (cons (point) (1+ (org-end-of-subtree))))))
>           "+delete")))
>        (unless headings-p (org-buffers-toggle-headings))))
>
>     ;;; Utilities
>
>     (defun org-buffers-map-entries (func &optional match)
>      (org-scan-tags
>       func (if match (cdr (org-make-tags-matcher match)) t)))
>
>     (defun org-buffers-set-state (state)
>      "Add STATE to global state list.
>     New settings have precedence over existing ones."
>      (mapc
>       (lambda (pair) (unless (assoc (car pair) state)
>        (add-to-list 'state pair)))
>       org-buffers-state)
>      (setq org-buffers-state state))
>
>     (defmacro org-buffers-delete-regions (regions)
>      "Delete regions in list.
>     REGIONS is a list of (beg . end) cons cells specifying buffer
>     regions."
>      `(mapc (lambda (pair) (if pair (delete-region (car pair) (cdr pair))))
>     ,regions))
>
>     (defmacro org-buffers-state-get (key)
>      `(cdr (assoc ,key org-buffers-state)))
>
>     (defmacro org-buffers-state-eq (key val)
>      `(equal (org-buffers-state-get ,key) ,val))
>
>     (defmacro org-buffers-outline-level ()
>      '(save-excursion (beginning-of-line) (org-outline-level)))
>
>     ;;; Links to buffers
>
>     (org-add-link-type "buffer" 'display-buffer)
>     (add-hook 'org-store-link-functions 'org-buffers-store-link)
>
>     (defun org-buffers-store-link (&optional force)
>      "Store a link to an Emacs buffer.
>     Returns nil by default, to avoid hijacking other link types."
>      (if force
>          (let* ((target (buffer-name))
>         (desc target) link)
>     (org-store-link-props :type "buffer")
>     (setq link (org-make-link "buffer:" target))
>     (org-add-link-props :link link :description desc)
>     link)))
>
>     (provide 'org-buffers)
>     ;;; org-buffers.el ends here
>     _______________________________________________
>     Emacs-orgmode mailing list
>     Please use `Reply All' to send replies to the list.
>     Emacs-orgmode@gnu.org
>     http://lists.gnu.org/mailman/listinfo/emacs-orgmode
>
>
> _______________________________________________
> Emacs-orgmode mailing list
> Please use `Reply All' to send replies to the list.
> Emacs-orgmode@gnu.org
> http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using Org for browsing and managing buffers
  2010-04-15 21:21   ` Dan Davison
@ 2010-04-16  7:11     ` Livin Stephen Sharma
  2010-04-16 14:22       ` Dan Davison
  0 siblings, 1 reply; 13+ messages in thread
From: Livin Stephen Sharma @ 2010-04-16  7:11 UTC (permalink / raw)
  To: Dan Davison; +Cc: emacs-org-mode-help gnu


[-- Attachment #1.1: Type: text/plain, Size: 26755 bytes --]

yep, now it works!
Thanks

About moving up/down:
 I was a bit surprised that 'p' was *not* a counterpart of 'n' (the latter
works exactly like 'n' in Org-Agenda)

Then I saw that in my setup (*no* customizations), there is some duplication
in the functions mapped to 'p' and 'P':



key             binding

---             -------


> SPC org-buffers-display-buffer

. org-buffers-switch-to-buffer

? org-buffers-help

B org-buffers-list:by

H org-buffers-toggle-headings

P org-buffers-toggle-properties

 T org-buffers-columns-view

b org-buffers-list:by

c org-buffers-columns-view

d org-buffers-tag-for-deletion

g org-buffers-list:refresh

h org-buffers-toggle-headings

o org-buffers-switch-to-buffer-other-window

p org-buffers-toggle-properties

 q bury-buffer

u org-buffers-remove-tags

x org-buffers-execute-pending-operations

<return> org-buffers-follow-link




On 16 April 2010 02:51, Dan Davison <davison@stats.ox.ac.uk> wrote:

> Livin Stephen Sharma <livin.stephen@gmail.com> writes:
>
> > Am I the only one encountering:
> >
> >     org-buffers-list: Invalid function: org-buffers-state-get
>
> I haven't seen that error, but I may have been doing something incorrect
> (with macros). I've got rid of them now; let me know if you still get
> the error.
>
> Code file:
> http://github.com/dandavison/org-buffers/raw/master/org-buffers.el
> Git repo:  http://github.com/dandavison/org-buffers
>
> Thanks,
>
> Dan
>
>
> >
> >
> >
> > I do see many people are using this successfully
> > :)
> >
> > Livin Stephen
> >
> >
> >
> > On Apr 09, 2010, at 06:47:20 , Dan Davison wrote:
> >
> >
> >     I've been working on an Org tool to browse Emacs buffers. Emacs has
> the
> >     function list-buffers (C-x C-b), where you can view a list of
> buffers,
> >     delete buffers, etc. This is intended to be a replacement for
> >     list-buffers, implemented in Org-mode.
> >
> >     The code is attached, and there's a git repo at
> >     http://github.com/dandavison/org-buffers
> >
> >     After putting the code in your load-path and doing
> >     (require 'org-buffers), use the function `org-buffers-list' to create
> >     the listing buffer. This is a read-only Org-mode buffer populated
> with
> >     links to open buffers. Information is stored for each buffer using
> >     properties. By default, the buffers are grouped by major mode. Here's
> a
> >     screenshot.
> >
> >     http://www.princeton.edu/~ddavison/org-buffers/by-major-mode.png
> >
> >     The buffer has some special key-bindings:
> >
> >     +--------------------------------------------------------------+
> >     | ?   | Show all keybindings                                   |
> >     |-----+--------------------------------------------------------|
> >     | g   | Update buffer (prefix arg does hard reset)             |
> >     |-----+--------------------------------------------------------|
> >     | b   | Select a different property to group by                |
> >     |-----+--------------------------------------------------------|
> >     | RET | follow link to buffer on this line                     |
> >     |-----+--------------------------------------------------------|
> >     | d   | Mark buffer for deletion                               |
> >     |-----+--------------------------------------------------------|
> >     | u   | Remove mark                                            |
> >     |-----+--------------------------------------------------------|
> >     | x   | Delete marked buffers                                  |
> >     |-----+--------------------------------------------------------|
> >     | o   | Like RET (see variable org-buffers-follow-link-method) |
> >     |-----+--------------------------------------------------------|
> >     | .   | Like RET but switch to buffer in same window           |
> >     |-----+--------------------------------------------------------|
> >     | h   | toggle between headings and plain entries for buffers  |
> >     |-----+--------------------------------------------------------|
> >     | p   | toggle in-buffer properties on/off                     |
> >     |-----+--------------------------------------------------------|
> >     | c   | Switch to column-view                                  |
> >     +--------------------------------------------------------------+
> >
> >     If there's an active region, d and u operate on all buffers in the
> >     region.
> >
> >     Some variables that can be configured:
> >     - org-buffers-buffer-properties
> >     - org-buffers-excluded-modes
> >     - org-buffers-excluded-buffers
> >     - org-buffers-follow-link-method
> >     - org-buffers-mode-hook
> >     - org-buffers-buffer-name
> >
> >     Some possible extensions:
> >     - Browse recent files using recentf
> >     - Allow several buffers to be marked for side-by-side display
> >     - Maintain folding configuration across buffer updates
> >     - Make faster
> >
> >     As always, any feedback, suggestions and patches will be very
> welcome!
> >
> >     Dan
> >
> >     p.s. The column-view mode works for following links, but does need
> >     further attention.
> >
> >     ;;; org-buffers.el --- An Org-mode tool for buffer management
> >
> >     ;; Copyright (C) 2010  Dan Davison
> >
> >     ;; Author: Dan Davison <dandavison0 at gmail dot com>
> >     ;; Keywords: outlines, hypermedia, calendar, wp
> >     ;; Homepage: http://orgmode.org
> >
> >     ;;; License:
> >
> >     ;; This program is free software; you can redistribute it and/or
> modify
> >     ;; it under the terms of the GNU General Public License as published
> by
> >     ;; the Free Software Foundation; either version 3, or (at your
> option)
> >     ;; any later version.
> >     ;;
> >     ;; This program is distributed in the hope that it will be useful,
> >     ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> >     ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >     ;; GNU General Public License for more details.
> >     ;;
> >     ;; You should have received a copy of the GNU General Public License
> >     ;; along with GNU Emacs; see the file COPYING.  If not, write to the
> >     ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
> >     ;; Boston, MA 02110-1301, USA.
> >
> >     ;;; Commentary:
> >
> >     ;;; Code:
> >
> >     (require 'org)
> >     (require 'cl)
> >
> >     ;;; Variables
> >     (defvar org-buffers-buffer-name
> >      "*Buffers*"
> >      "Name of buffer in which buffer list is displayed")
> >
> >     (defvar org-buffers-state
> >      '((:by . "major-mode") (:atom . heading) (:properties . nil))
> >      "Association list specifiying the current state of org-buffers.")
> >
> >     (defvar org-buffers-follow-link-method 'org-open-at-point
> >      "Method used to follow link with RET. Must be one of
> >
> >     'org-open-at-point :: use `org-open-at-point' to follow link.
> >     'current-window    :: use switch-to-buffer
> >     'other-window      :: use switch-to-buffer-other-window
> >
> >     Setting this variable to 'current-window makes the behaviour more
> >     consistent with that of `Buffer-menu-mode' and `dired-mode'")
> >
> >     (defvar org-buffers-buffer-properties
> >      '(("buffer-name" . (buffer-name))
> >        ("major-mode" . (let ((mode (symbol-name major-mode)))
> >          (if (string-match "-mode$" mode)
> >      (replace-match "" nil t mode) mode)))
> >        ("buffer-file-name" . (buffer-file-name))
> >        ("default-directory" . default-directory)
> >        ("buffer-modified-p" . (format "%s" (buffer-modified-p))))
> >      "Association list specifying properties to be stored for each
> >     buffer. The car of each element is the name of the property, and
> >     the cdr is an expression which, when evaluated in the buffer,
> >     yields the property value.")
> >
> >     (defcustom org-buffers-excluded-buffers
> >      `("*Completions*" ,org-buffers-buffer-name)
> >      "List of names of buffers that should not be listed by
> >      org-buffers-list."
> >      :group 'org-buffers)
> >
> >     (defcustom org-buffers-excluded-modes nil
> >      "List of names of major-modes (strings) that should not be listed
> >      by org-buffers-list."
> >      :group 'org-buffers)
> >
> >     ;;; Mode
> >     (defvar org-buffers-mode-map (make-sparse-keymap))
> >
> >     (defvar org-buffers-mode-hook nil
> >      "Hook for functions to be called after buffer listing is
> >      created. Note that the buffer is read-only, so if the hook
> >      function is to modify the buffer it should use a let binding to
> >      temporarily bind buffer-read-only to nil.")
> >
> >     (define-minor-mode org-buffers-mode
> >      "An Org-mode tool for buffer management.
> >     \\{org-buffers-mode-map}"
> >      nil " buffers" nil
> >      (org-set-local 'org-tag-alist '(("delete" . ?d)))
> >      (org-set-local'org-tags-column -50)
> >      (org-set-local 'org-columns-default-format "%25buffer-name(Buffer)
> >     %25major-mode(Mode) %25default-directory(Dir)
> %5buffer-modified-p(Modified)
> >     ")
> >      (add-hook 'kill-buffer-hook 'org-buffers-reset-state nil 'local))
> >
> >     (defun org-buffers-help ()
> >      (interactive)
> >      (describe-function 'org-buffers-mode))
> >
> >     ;;; Keys
> >     (define-key org-buffers-mode-map [(return)] 'org-buffers-follow-link)
> >     (define-key org-buffers-mode-map "b" 'org-buffers-list:by)
> >     (define-key org-buffers-mode-map "c" 'org-buffers-columns-view)
> >     (define-key org-buffers-mode-map "d" 'org-buffers-tag-for-deletion)
> >     (define-key org-buffers-mode-map "g" 'org-buffers-list:refresh)
> >     (define-key org-buffers-mode-map "." 'org-buffers-switch-to-buffer)
> >     (define-key org-buffers-mode-map "h" 'org-buffers-toggle-headings)
> >     (define-key org-buffers-mode-map "o"
> >     'org-buffers-switch-to-buffer-other-window)
> >     (define-key org-buffers-mode-map "p" 'org-buffers-toggle-properties)
> >     (define-key org-buffers-mode-map "u" 'org-buffers-remove-tags)
> >     (define-key org-buffers-mode-map "x"
> >     'org-buffers-execute-pending-operations)
> >     (define-key org-buffers-mode-map "?" 'org-buffers-help)
> >     ;;; Listing and view cycling
> >
> >     (defun org-buffers-list (&optional refresh frame)
> >      "Create an Org-mode listing of Emacs buffers.
> >     By default, buffers are grouped by major mode. Optional
> >     argument FRAME specifies the frame whose buffers should be
> >     listed."
> >      (interactive)
> >      (pop-to-buffer
> >       (or
> >        (and (not refresh) (get-buffer org-buffers-buffer-name))
> >        (let ((org-buffers-p (equal (buffer-name)
> org-buffers-buffer-name))
> >      (by (or (org-buffers-state-get :by) "major-mode"))
> >      (atom (org-buffers-state-get :atom)) target)
> >          (when org-buffers-p
> >     (if (and (org-before-first-heading-p) (not (org-on-heading-p)))
> >        (outline-next-heading))
> >     (setq target
> >          (condition-case nil (org-make-org-heading-search-string) (error
> >     nil))))
> >          (with-current-buffer (get-buffer-create org-buffers-buffer-name)
> >     (setq buffer-read-only nil)
> >     (erase-buffer)
> >     (org-mode)
> >     (dolist
> >        (buffer
> >         (sort (remove-if 'org-buffers-exclude-p
> >          (mapcar 'buffer-name (buffer-list frame))) 'string<))
> >      (org-insert-heading t)
> >      (insert
> >       (org-make-link-string (concat "buffer:" buffer) buffer) "\n")
> >      (dolist (pair (org-buffers-get-buffer-props buffer))
> >        (org-set-property (car pair) (cdr pair))))
> >     (org-buffers-set-state '((:atom . heading)))
> >     (goto-char (point-min))
> >     (unless (equal by "NONE") (org-buffers-group-by by))
> >     (if target (condition-case nil (org-link-search target) (error nil)))
> >     (beginning-of-line)
> >     (if (equal by "NONE")
> >        (org-overview)
> >      (case atom
> >        ('heading (progn (org-overview) (org-content)))
> >        ('line (progn (show-all) (org-buffers-toggle-headings)))))
> >     (save-excursion
> >      (mark-whole-buffer)
> >      (indent-region (point-min) (point-max)))
> >     (org-buffers-mode)
> >     (setq buffer-read-only t)
> >     (current-buffer))))))
> >
> >     (defun org-buffers-list:refresh (&optional arg)
> >      "Refresh org-buffers listing."
> >      (interactive "P")
> >      (if arg (org-buffers-reset-state))
> >      (org-buffers-list 'refresh))
> >
> >     (defun org-buffers-list:by (&optional prop)
> >      "Group buffers according to value of property PROP."
> >      (interactive)
> >      (let ((buffer-read-only nil)
> >     (headings-p (org-buffers-state-eq :atom 'heading)))
> >        (unless (org-buffers-state-get :properties)
> >          (org-buffers-toggle-properties))
> >        (org-buffers-set-state
> >         `((:by .
> >        ,(or prop
> >     (org-completing-read
> >      "Property to group by: "
> >      (cons "NONE" (mapcar 'car org-buffers-buffer-properties)))))))
> >        (org-buffers-list 'refresh)
> >        (unless headings-p (org-buffers-toggle-headings))))
> >
> >     (defun org-buffers-toggle-properties ()
> >      "Toggle entry properties in org-buffers listing buffer.
> >     Removing properties may provide a less cluttered appearance for
> >     browsing. However, in-buffer properties will be restored during
> >     certain operations, such as `org-buffers-list:by'."
> >      (interactive)
> >      (if (org-buffers-state-get :properties)
> >          (progn (org-buffers-delete-properties)
> >         (show-all)
> >         (org-buffers-set-state '((:properties . nil))))
> >        (org-buffers-set-state
> >         '((:atom . heading) (:properties . t)))
> >        (org-buffers-list 'refresh)))
> >
> >     (defun org-buffers-toggle-headings ()
> >      "Toggle viewing of buffers as org headings.
> >     Headings will be automatically restored during certain
> >     operations, such as setting deletion tags."
> >      (interactive)
> >      (let ((buffer-read-only nil)
> >     (headings-p (org-buffers-state-eq :atom 'heading))
> >     (flat-p (org-buffers-state-eq :by "NONE")))
> >        (if (and headings-p (org-buffers-state-get :properties))
> >     (org-buffers-toggle-properties))
> >        (save-excursion
> >          (goto-char (point-min))
> >          (if (and (or headings-p (not flat-p))
> >           (not (outline-on-heading-p)))
> >      (outline-next-heading))
> >          (if flat-p
> >      (progn
> >        (push-mark (point) 'nomsg 'activate)
> >        (end-of-buffer)
> >        (org-ctrl-c-star)
> >        (pop-mark))
> >     (while (not (eobp))
> >      (push-mark
> >       (save-excursion (forward-line 1) (point)) 'nomsg 'activate)
> >      (org-forward-same-level 1)
> >      (org-ctrl-c-star)
> >      (pop-mark)))
> >          (mark-whole-buffer)
> >          (indent-region (point-min) (point-max)))
> >        (org-buffers-set-state
> >         `((:atom . ,(if headings-p 'line 'heading))))))
> >
> >     (defun org-buffers-delete-properties ()
> >      (let ((buffer-read-only nil))
> >        (save-excursion
> >          (goto-char (point-min))
> >          (org-buffers-delete-regions
> >           (nreverse
> >     (org-buffers-map-entries 'org-buffers-get-property-block))))))
> >
> >     (defun org-buffers-get-property-block ()
> >      "Return the (beg . end) range of the property drawer.
> >     Unlike the org version the limits include the keywords delimiting
> >     the drawer."
> >      (let ((beg (point))
> >     (end (progn (outline-next-heading) (point))))
> >        (goto-char beg)
> >        (if (re-search-forward org-property-drawer-re end t)
> >     (cons (match-beginning 1) (match-end 0)))))
> >
> >     (defun org-buffers-group-by (property)
> >      "Group top level headings according to the value of PROPERTY."
> >      (let ((atom (org-buffers-state-get :atom)))
> >        (save-excursion
> >          (goto-char (point-min))
> >          (mapc (lambda (subtree) ;; Create subtree for each value of
> `property'
> >          (org-insert-heading t)
> >          (if (> (org-buffers-outline-level) 1)
> >      (org-promote))
> >          (insert (car subtree) "\n")
> >          (org-insert-subheading t)
> >          (mapc 'org-buffers-insert-parsed-entry (cdr subtree)))
> >        (prog1
> >     (mapcar (lambda (val) ;; Form list of parsed entries for each unique
> value
> >     of `property'
> >      (cons val (org-buffers-parse-selected-entries property val)))
> >     (sort
> >     (delete-dups (org-buffers-map-entries (lambda () (org-entry-get nil
> >     property nil))))
> >     'string<))
> >          (erase-buffer))))))
> >
> >     (defun org-buffers-exclude-p (buffer)
> >      "Return non-nil if BUFFER should not be listed."
> >      (or (member (with-current-buffer buffer major-mode)
> >          org-buffers-excluded-modes)
> >          (member buffer org-buffers-excluded-buffers)
> >          (string= (substring buffer 0 1) " ")))
> >
> >     (defun org-buffers-reset-state ()
> >      (org-buffers-set-state
> >       '((:by . "major-mode") (:atom . heading) (:properties . nil))))
> >
> >     (defun org-buffers-columns-view ()
> >      "View buffers in Org-mode columns view.
> >     This is currently experimental. RET can be used to follow links
> >     in the first column, but certain other org-buffers keys conflict
> >     with column-view or otherwise do not work correctly."
> >      (interactive)
> >      (let ((by (org-buffers-state-get :by))
> >     (buffer-read-only nil))
> >        (unless (equal by "NONE") (org-buffers-list:by "NONE"))
> >        (unless (org-buffers-state-get :properties)
> >          (org-buffers-toggle-properties))
> >        (unless (equal by "NONE")
> >          (goto-char (point-min))
> >          (org-sort-entries-or-items nil ?r nil nil by)
> >          (org-overview))
> >        (mark-whole-buffer)
> >        (org-columns)))
> >
> >     ;;; Parsing and inserting entries
> >     (defun org-buffers-parse-selected-entries (prop val)
> >      "Parse all entries with property PROP value VAL."
> >      (delq nil
> >     (org-buffers-map-entries
> >     (lambda () (when (equal (org-entry-get nil prop) val)
> >          (cons (org-get-heading) (org-get-entry)))))))
> >
> >     (defun org-buffers-insert-parsed-entry (entry)
> >      "Insert a parsed entry"
> >      (unless (org-at-heading-p) (org-insert-heading))
> >      (insert (car entry) "\n")
> >      (if (org-buffers-state-get :properties)
> >          (insert (cdr entry))))
> >
> >     (defun org-buffers-get-buffer-props (buffer)
> >      "Create alist of properties of BUFFER, as strings."
> >      (with-current-buffer buffer
> >        (mapcar
> >         (lambda (pair) (cons (car pair) (eval (cdr pair))))
> >         org-buffers-buffer-properties)))
> >
> >     ;;; Follow-link behaviour
> >
> >     (defun org-buffers-follow-link ()
> >      "Follow link to buffer on this line.
> >     The buffer-switching behaviour of this function is determined by
> >     the variable `org-buffers-follow-link-method'. See also
> >     `org-buffers-switch-to-buffer' and
> >     `org-buffers-switch-to-buffer-other-window', whose behaviour is
> >     hard-wired."
> >      (interactive)
> >      (org-buffers-switch-to-buffer-generic
> org-buffers-follow-link-method))
> >
> >     (defun org-buffers-switch-to-buffer ()
> >     "Switch to this entry's buffer in current window."
> >      (interactive)
> >      (org-buffers-switch-to-buffer-generic 'current-window))
> >
> >     (defun org-buffers-switch-to-buffer-other-window ()
> >      "Switch to this entry's buffer in other window."
> >      (interactive)
> >      (org-buffers-switch-to-buffer-generic 'other-window))
> >
> >     (defun org-buffers-switch-to-buffer-generic (method)
> >      (save-excursion
> >        (let ((atom (org-buffers-state-get :atom)) buffer)
> >          (cond
> >           ((eq atom 'heading) (org-back-to-heading))
> >           (t (beginning-of-line)))
> >          (setq buffer (org-buffers-get-buffer-name))
> >          (if (get-buffer buffer)
> >      (case method
> >        ('org-open-at-point (org-open-at-point))
> >        ('current-window (switch-to-buffer buffer))
> >        ('other-window (switch-to-buffer-other-window buffer)))
> >     (error "No such buffer: %s" buffer)))))
> >
> >     (defun org-buffers-get-buffer-name ()
> >      "Get buffer-name for current entry."
> >      (let ((headings-p (org-buffers-state-eq :atom 'heading)))
> >        (or (and headings-p (org-entry-get nil "buffer-name"))
> >     (and (save-excursion
> >           (if headings-p (org-back-to-heading))
> >           (re-search-forward "\\[\\[buffer:\\([^\]]*\\)" (point-at-eol)
> t))
> >         (org-link-unescape (match-string 1))))))
> >
> >     ;;; Setting tags and executing operations
> >
> >     (defun org-buffers-tag-for-deletion ()
> >      "Mark buffer for deletion.
> >     If a region is selected, all buffers in the region are marked for
> >     deletion. Buffers marked for deletion can be deleted using
> >     `org-buffers-execute-pending-operations'."
> >      (interactive)
> >      (org-buffers-set-tags '("delete")))
> >
> >     (defun org-buffers-remove-tags ()
> >      "Remove deletion marks from buffers.
> >     If a region is selected, marks are removed from all buffers in
> >     the region."
> >      (interactive)
> >      (org-buffers-set-tags nil))
> >
> >     (defun org-buffers-set-tags (data)
> >      "Set tags to DATA at all non top-level headings in region.
> >     DATA should be a list of strings. If DATA is nil, remove all tags
> >     at such headings."
> >      (let* ((buffer-read-only nil)
> >     (region-p (org-region-active-p))
> >     (beg (if region-p (region-beginning) (point)))
> >     (end (if region-p (region-end) (point)))
> >     (headings-p (org-buffers-state-eq :atom 'heading))beg-line end-line)
> >        (save-excursion
> >          (setq beg-line (progn (goto-char beg) (org-current-line))
> >        end-line (progn (goto-char end) (org-current-line)))
> >          (if headings-p
> >      (setq
> >       end (if (and region-p (not (eq end-line beg-line)) (not (eobp)))
> >       (progn (goto-char end) (org-back-to-heading) (point))
> >     (progn (outline-end-of-heading) (point)))
> >       beg (progn (goto-char beg) (point-at-bol)))
> >     (org-buffers-toggle-headings) ;; doesn't alter line numbers
> >     (setq beg (progn (org-goto-line beg-line) (point-at-bol))
> >          end (if (eq end-line beg-line) (point-at-eol)
> >        (progn (org-goto-line end-line) (point-at-bol)))))
> >          (narrow-to-region beg end)
> >          (goto-char (point-min))
> >          (org-buffers-map-entries
> >           (lambda ()
> >     (when (or (org-buffers-state-eq :by "NONE")
> >       (> (org-outline-level) 1))
> >       (org-set-tags-to
> >        (if data (delete-duplicates (append data (org-get-tags)) :test
> >     'string-equal))))))
> >          (widen)
> >          (org-content))
> >        (unless region-p
> >          (outline-next-heading)
> >          (unless (or (> (org-outline-level) 1) (org-buffers-state-eq :by
> >     "NONE"))
> >     (outline-next-heading)))
> >            (unless headings-p (org-buffers-toggle-headings))))
> >
> >     (defun org-buffers-execute-pending-operations ()
> >      "Execute all pending operations.
> >     Currently the only type of operation supported is
> >     deletion. Buffers are tagged for deletion using
> >     `org-buffers-tag-for-deletion'. Remove such tags from buffers
> >     using `org-buffers-remove-tags'."
> >      (interactive)
> >      (let ((buffer-read-only nil)
> >     (headings-p (org-buffers-state-eq :atom 'heading)) buffer)
> >        (unless headings-p (org-buffers-toggle-headings))
> >        (org-buffers-delete-regions
> >         (nreverse
> >          (org-buffers-map-entries
> >           (lambda ()
> >     (if (setq buffer (org-buffers-get-buffer-name))
> >         (if (not (kill-buffer buffer))
> >     (error "Failed to kill buffer %s" buffer)
> >           (if (and (org-first-sibling-p)
> >     (not (save-excursion (org-goto-sibling))))
> >       (org-up-heading-safe)) ;; Only child so delete parent also
> >           (cons (point) (1+ (org-end-of-subtree))))))
> >           "+delete")))
> >        (unless headings-p (org-buffers-toggle-headings))))
> >
> >     ;;; Utilities
> >
> >     (defun org-buffers-map-entries (func &optional match)
> >      (org-scan-tags
> >       func (if match (cdr (org-make-tags-matcher match)) t)))
> >
> >     (defun org-buffers-set-state (state)
> >      "Add STATE to global state list.
> >     New settings have precedence over existing ones."
> >      (mapc
> >       (lambda (pair) (unless (assoc (car pair) state)
> >        (add-to-list 'state pair)))
> >       org-buffers-state)
> >      (setq org-buffers-state state))
> >
> >     (defmacro org-buffers-delete-regions (regions)
> >      "Delete regions in list.
> >     REGIONS is a list of (beg . end) cons cells specifying buffer
> >     regions."
> >      `(mapc (lambda (pair) (if pair (delete-region (car pair) (cdr
> pair))))
> >     ,regions))
> >
> >     (defmacro org-buffers-state-get (key)
> >      `(cdr (assoc ,key org-buffers-state)))
> >
> >     (defmacro org-buffers-state-eq (key val)
> >      `(equal (org-buffers-state-get ,key) ,val))
> >
> >     (defmacro org-buffers-outline-level ()
> >      '(save-excursion (beginning-of-line) (org-outline-level)))
> >
> >     ;;; Links to buffers
> >
> >     (org-add-link-type "buffer" 'display-buffer)
> >     (add-hook 'org-store-link-functions 'org-buffers-store-link)
> >
> >     (defun org-buffers-store-link (&optional force)
> >      "Store a link to an Emacs buffer.
> >     Returns nil by default, to avoid hijacking other link types."
> >      (if force
> >          (let* ((target (buffer-name))
> >         (desc target) link)
> >     (org-store-link-props :type "buffer")
> >     (setq link (org-make-link "buffer:" target))
> >     (org-add-link-props :link link :description desc)
> >     link)))
> >
> >     (provide 'org-buffers)
> >     ;;; org-buffers.el ends here
> >     _______________________________________________
> >     Emacs-orgmode mailing list
> >     Please use `Reply All' to send replies to the list.
> >     Emacs-orgmode@gnu.org
> >     http://lists.gnu.org/mailman/listinfo/emacs-orgmode
> >
> >
> > _______________________________________________
> > Emacs-orgmode mailing list
> > Please use `Reply All' to send replies to the list.
> > Emacs-orgmode@gnu.org
> > http://lists.gnu.org/mailman/listinfo/emacs-orgmode
>

[-- Attachment #1.2: Type: text/html, Size: 39452 bytes --]

[-- Attachment #2: Type: text/plain, Size: 201 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Please use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using Org for browsing and managing buffers
  2010-04-16  7:11     ` Livin Stephen Sharma
@ 2010-04-16 14:22       ` Dan Davison
  0 siblings, 0 replies; 13+ messages in thread
From: Dan Davison @ 2010-04-16 14:22 UTC (permalink / raw)
  To: Livin Stephen Sharma; +Cc: emacs-org-mode-help gnu

Livin Stephen Sharma <livin.stephen@gmail.com> writes:

> yep, now it works!
> Thanks
>
> About moving up/down:
>  I was a bit surprised that 'p' was not a counterpart of 'n' (the latter works
> exactly like 'n' in Org-Agenda)
>
> Then I saw that in my setup (*no* customizations), there is some duplication in
> the functions mapped to 'p' and 'P':

Hi,

I've been working on improving the key bindings, in discussion with Eric
Fraga. It looks like you have loaded the new code into a system already
running the old code, and the keymap has ended up as a hybrid between
the two. The simplest thing would be to restart emacs. I don't know of
another way to reliably make sure that all the necessary variables get
reset. With the new bindings you will have p and n for movement as well
as a bunch of other bindings from `org-speed-commands-default'.

Thanks for trying it out!

Dan

>
>
>
>
>     key             binding
>
>     ---             -------
>
>
>
>     SPC org-buffers-display-buffer
>
>     . org-buffers-switch-to-buffer
>
>     ? org-buffers-help
>
>     B org-buffers-list:by
>
>     H org-buffers-toggle-headings
>
>     P org-buffers-toggle-properties
>
>     T org-buffers-columns-view
>
>     b org-buffers-list:by
>
>     c org-buffers-columns-view
>
>     d org-buffers-tag-for-deletion
>
>     g org-buffers-list:refresh
>
>     h org-buffers-toggle-headings
>
>     o org-buffers-switch-to-buffer-other-window
>
>     p org-buffers-toggle-properties
>
>     q bury-buffer
>
>     u org-buffers-remove-tags
>
>     x org-buffers-execute-pending-operations
>
>     <return> org-buffers-follow-link
>
>
>
>
> On 16 April 2010 02:51, Dan Davison <davison@stats.ox.ac.uk> wrote:
>
>     Livin Stephen Sharma <livin.stephen@gmail.com> writes:
>
>     > Am I the only one encountering:
>     >
>     >     org-buffers-list: Invalid function: org-buffers-state-get
>
>     I haven't seen that error, but I may have been doing something incorrect
>     (with macros). I've got rid of them now; let me know if you still get
>     the error.
>
>     Code file: http://github.com/dandavison/org-buffers/raw/master/
>     org-buffers.el
>     Git repo:  http://github.com/dandavison/org-buffers
>
>     Thanks,
>
>     Dan
>
>
>     >
>     >
>     >
>     > I do see many people are using this successfully
>     > :)
>     >
>     > Livin Stephen
>     >
>     >
>     >
>     > On Apr 09, 2010, at 06:47:20 , Dan Davison wrote:
>     >
>     >
>     >     I've been working on an Org tool to browse Emacs buffers. Emacs has
>     the
>     >     function list-buffers (C-x C-b), where you can view a list of
>     buffers,
>     >     delete buffers, etc. This is intended to be a replacement for
>     >     list-buffers, implemented in Org-mode.
>     >
>     >     The code is attached, and there's a git repo at
>     >     http://github.com/dandavison/org-buffers
>     >
>     >     After putting the code in your load-path and doing
>     >     (require 'org-buffers), use the function `org-buffers-list' to create
>     >     the listing buffer. This is a read-only Org-mode buffer populated
>     with
>     >     links to open buffers. Information is stored for each buffer using
>     >     properties. By default, the buffers are grouped by major mode. Here's
>     a
>     >     screenshot.
>     >
>     >     http://www.princeton.edu/~ddavison/org-buffers/by-major-mode.png
>     >
>     >     The buffer has some special key-bindings:
>     >
>     >     +--------------------------------------------------------------+
>     >     | ?   | Show all keybindings                                   |
>     >     |-----+--------------------------------------------------------|
>     >     | g   | Update buffer (prefix arg does hard reset)             |
>     >     |-----+--------------------------------------------------------|
>     >     | b   | Select a different property to group by                |
>     >     |-----+--------------------------------------------------------|
>     >     | RET | follow link to buffer on this line                     |
>     >     |-----+--------------------------------------------------------|
>     >     | d   | Mark buffer for deletion                               |
>     >     |-----+--------------------------------------------------------|
>     >     | u   | Remove mark                                            |
>     >     |-----+--------------------------------------------------------|
>     >     | x   | Delete marked buffers                                  |
>     >     |-----+--------------------------------------------------------|
>     >     | o   | Like RET (see variable org-buffers-follow-link-method) |
>     >     |-----+--------------------------------------------------------|
>     >     | .   | Like RET but switch to buffer in same window           |
>     >     |-----+--------------------------------------------------------|
>     >     | h   | toggle between headings and plain entries for buffers  |
>     >     |-----+--------------------------------------------------------|
>     >     | p   | toggle in-buffer properties on/off                     |
>     >     |-----+--------------------------------------------------------|
>     >     | c   | Switch to column-view                                  |
>     >     +--------------------------------------------------------------+
>     >
>     >     If there's an active region, d and u operate on all buffers in the
>     >     region.
>     >
>     >     Some variables that can be configured:
>     >     - org-buffers-buffer-properties
>     >     - org-buffers-excluded-modes
>     >     - org-buffers-excluded-buffers
>     >     - org-buffers-follow-link-method
>     >     - org-buffers-mode-hook
>     >     - org-buffers-buffer-name
>     >
>     >     Some possible extensions:
>     >     - Browse recent files using recentf
>     >     - Allow several buffers to be marked for side-by-side display
>     >     - Maintain folding configuration across buffer updates
>     >     - Make faster
>     >
>     >     As always, any feedback, suggestions and patches will be very
>     welcome!
>     >
>     >     Dan
>     >
>     >     p.s. The column-view mode works for following links, but does need
>     >     further attention.
>     >
>     >     ;;; org-buffers.el --- An Org-mode tool for buffer management
>     >
>     >     ;; Copyright (C) 2010  Dan Davison
>     >
>     >     ;; Author: Dan Davison <dandavison0 at gmail dot com>
>     >     ;; Keywords: outlines, hypermedia, calendar, wp
>     >     ;; Homepage: http://orgmode.org
>     >
>     >     ;;; License:
>     >
>     >     ;; This program is free software; you can redistribute it and/or
>     modify
>     >     ;; it under the terms of the GNU General Public License as published
>     by
>     >     ;; the Free Software Foundation; either version 3, or (at your
>     option)
>     >     ;; any later version.
>     >     ;;
>     >     ;; This program is distributed in the hope that it will be useful,
>     >     ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
>     >     ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>     >     ;; GNU General Public License for more details.
>     >     ;;
>     >     ;; You should have received a copy of the GNU General Public License
>     >     ;; along with GNU Emacs; see the file COPYING.  If not, write to the
>     >     ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
>     >     ;; Boston, MA 02110-1301, USA.
>     >
>     >     ;;; Commentary:
>     >
>     >     ;;; Code:
>     >
>     >     (require 'org)
>     >     (require 'cl)
>     >
>     >     ;;; Variables
>     >     (defvar org-buffers-buffer-name
>     >      "*Buffers*"
>     >      "Name of buffer in which buffer list is displayed")
>     >
>     >     (defvar org-buffers-state
>     >      '((:by . "major-mode") (:atom . heading) (:properties . nil))
>     >      "Association list specifiying the current state of org-buffers.")
>     >
>     >     (defvar org-buffers-follow-link-method 'org-open-at-point
>     >      "Method used to follow link with RET. Must be one of
>     >
>     >     'org-open-at-point :: use `org-open-at-point' to follow link.
>     >     'current-window    :: use switch-to-buffer
>     >     'other-window      :: use switch-to-buffer-other-window
>     >
>     >     Setting this variable to 'current-window makes the behaviour more
>     >     consistent with that of `Buffer-menu-mode' and `dired-mode'")
>     >
>     >     (defvar org-buffers-buffer-properties
>     >      '(("buffer-name" . (buffer-name))
>     >        ("major-mode" . (let ((mode (symbol-name major-mode)))
>     >          (if (string-match "-mode$" mode)
>     >      (replace-match "" nil t mode) mode)))
>     >        ("buffer-file-name" . (buffer-file-name))
>     >        ("default-directory" . default-directory)
>     >        ("buffer-modified-p" . (format "%s" (buffer-modified-p))))
>     >      "Association list specifying properties to be stored for each
>     >     buffer. The car of each element is the name of the property, and
>     >     the cdr is an expression which, when evaluated in the buffer,
>     >     yields the property value.")
>     >
>     >     (defcustom org-buffers-excluded-buffers
>     >      `("*Completions*" ,org-buffers-buffer-name)
>     >      "List of names of buffers that should not be listed by
>     >      org-buffers-list."
>     >      :group 'org-buffers)
>     >
>     >     (defcustom org-buffers-excluded-modes nil
>     >      "List of names of major-modes (strings) that should not be listed
>     >      by org-buffers-list."
>     >      :group 'org-buffers)
>     >
>     >     ;;; Mode
>     >     (defvar org-buffers-mode-map (make-sparse-keymap))
>     >
>     >     (defvar org-buffers-mode-hook nil
>     >      "Hook for functions to be called after buffer listing is
>     >      created. Note that the buffer is read-only, so if the hook
>     >      function is to modify the buffer it should use a let binding to
>     >      temporarily bind buffer-read-only to nil.")
>     >
>     >     (define-minor-mode org-buffers-mode
>     >      "An Org-mode tool for buffer management.
>     >     \\{org-buffers-mode-map}"
>     >      nil " buffers" nil
>     >      (org-set-local 'org-tag-alist '(("delete" . ?d)))
>     >      (org-set-local'org-tags-column -50)
>     >      (org-set-local 'org-columns-default-format "%25buffer-name(Buffer)
>     >     %25major-mode(Mode) %25default-directory(Dir) %5buffer-modified-p
>     (Modified)
>     >     ")
>     >      (add-hook 'kill-buffer-hook 'org-buffers-reset-state nil 'local))
>     >
>     >     (defun org-buffers-help ()
>     >      (interactive)
>     >      (describe-function 'org-buffers-mode))
>     >
>     >     ;;; Keys
>     >     (define-key org-buffers-mode-map [(return)] 'org-buffers-follow-link)
>     >     (define-key org-buffers-mode-map "b" 'org-buffers-list:by)
>     >     (define-key org-buffers-mode-map "c" 'org-buffers-columns-view)
>     >     (define-key org-buffers-mode-map "d" 'org-buffers-tag-for-deletion)
>     >     (define-key org-buffers-mode-map "g" 'org-buffers-list:refresh)
>     >     (define-key org-buffers-mode-map "." 'org-buffers-switch-to-buffer)
>     >     (define-key org-buffers-mode-map "h" 'org-buffers-toggle-headings)
>     >     (define-key org-buffers-mode-map "o"
>     >     'org-buffers-switch-to-buffer-other-window)
>     >     (define-key org-buffers-mode-map "p" 'org-buffers-toggle-properties)
>     >     (define-key org-buffers-mode-map "u" 'org-buffers-remove-tags)
>     >     (define-key org-buffers-mode-map "x"
>     >     'org-buffers-execute-pending-operations)
>     >     (define-key org-buffers-mode-map "?" 'org-buffers-help)
>     >     ;;; Listing and view cycling
>     >
>     >     (defun org-buffers-list (&optional refresh frame)
>     >      "Create an Org-mode listing of Emacs buffers.
>     >     By default, buffers are grouped by major mode. Optional
>     >     argument FRAME specifies the frame whose buffers should be
>     >     listed."
>     >      (interactive)
>     >      (pop-to-buffer
>     >       (or
>     >        (and (not refresh) (get-buffer org-buffers-buffer-name))
>     >        (let ((org-buffers-p (equal (buffer-name)
>     org-buffers-buffer-name))
>     >      (by (or (org-buffers-state-get :by) "major-mode"))
>     >      (atom (org-buffers-state-get :atom)) target)
>     >          (when org-buffers-p
>     >     (if (and (org-before-first-heading-p) (not (org-on-heading-p)))
>     >        (outline-next-heading))
>     >     (setq target
>     >          (condition-case nil (org-make-org-heading-search-string) (error
>     >     nil))))
>     >          (with-current-buffer (get-buffer-create org-buffers-buffer-name)
>     >     (setq buffer-read-only nil)
>     >     (erase-buffer)
>     >     (org-mode)
>     >     (dolist
>     >        (buffer
>     >         (sort (remove-if 'org-buffers-exclude-p
>     >          (mapcar 'buffer-name (buffer-list frame))) 'string<))
>     >      (org-insert-heading t)
>     >      (insert
>     >       (org-make-link-string (concat "buffer:" buffer) buffer) "\n")
>     >      (dolist (pair (org-buffers-get-buffer-props buffer))
>     >        (org-set-property (car pair) (cdr pair))))
>     >     (org-buffers-set-state '((:atom . heading)))
>     >     (goto-char (point-min))
>     >     (unless (equal by "NONE") (org-buffers-group-by by))
>     >     (if target (condition-case nil (org-link-search target) (error nil)))
>     >     (beginning-of-line)
>     >     (if (equal by "NONE")
>     >        (org-overview)
>     >      (case atom
>     >        ('heading (progn (org-overview) (org-content)))
>     >        ('line (progn (show-all) (org-buffers-toggle-headings)))))
>     >     (save-excursion
>     >      (mark-whole-buffer)
>     >      (indent-region (point-min) (point-max)))
>     >     (org-buffers-mode)
>     >     (setq buffer-read-only t)
>     >     (current-buffer))))))
>     >
>     >     (defun org-buffers-list:refresh (&optional arg)
>     >      "Refresh org-buffers listing."
>     >      (interactive "P")
>     >      (if arg (org-buffers-reset-state))
>     >      (org-buffers-list 'refresh))
>     >
>     >     (defun org-buffers-list:by (&optional prop)
>     >      "Group buffers according to value of property PROP."
>     >      (interactive)
>     >      (let ((buffer-read-only nil)
>     >     (headings-p (org-buffers-state-eq :atom 'heading)))
>     >        (unless (org-buffers-state-get :properties)
>     >          (org-buffers-toggle-properties))
>     >        (org-buffers-set-state
>     >         `((:by .
>     >        ,(or prop
>     >     (org-completing-read
>     >      "Property to group by: "
>     >      (cons "NONE" (mapcar 'car org-buffers-buffer-properties)))))))
>     >        (org-buffers-list 'refresh)
>     >        (unless headings-p (org-buffers-toggle-headings))))
>     >
>     >     (defun org-buffers-toggle-properties ()
>     >      "Toggle entry properties in org-buffers listing buffer.
>     >     Removing properties may provide a less cluttered appearance for
>     >     browsing. However, in-buffer properties will be restored during
>     >     certain operations, such as `org-buffers-list:by'."
>     >      (interactive)
>     >      (if (org-buffers-state-get :properties)
>     >          (progn (org-buffers-delete-properties)
>     >         (show-all)
>     >         (org-buffers-set-state '((:properties . nil))))
>     >        (org-buffers-set-state
>     >         '((:atom . heading) (:properties . t)))
>     >        (org-buffers-list 'refresh)))
>     >
>     >     (defun org-buffers-toggle-headings ()
>     >      "Toggle viewing of buffers as org headings.
>     >     Headings will be automatically restored during certain
>     >     operations, such as setting deletion tags."
>     >      (interactive)
>     >      (let ((buffer-read-only nil)
>     >     (headings-p (org-buffers-state-eq :atom 'heading))
>     >     (flat-p (org-buffers-state-eq :by "NONE")))
>     >        (if (and headings-p (org-buffers-state-get :properties))
>     >     (org-buffers-toggle-properties))
>     >        (save-excursion
>     >          (goto-char (point-min))
>     >          (if (and (or headings-p (not flat-p))
>     >           (not (outline-on-heading-p)))
>     >      (outline-next-heading))
>     >          (if flat-p
>     >      (progn
>     >        (push-mark (point) 'nomsg 'activate)
>     >        (end-of-buffer)
>     >        (org-ctrl-c-star)
>     >        (pop-mark))
>     >     (while (not (eobp))
>     >      (push-mark
>     >       (save-excursion (forward-line 1) (point)) 'nomsg 'activate)
>     >      (org-forward-same-level 1)
>     >      (org-ctrl-c-star)
>     >      (pop-mark)))
>     >          (mark-whole-buffer)
>     >          (indent-region (point-min) (point-max)))
>     >        (org-buffers-set-state
>     >         `((:atom . ,(if headings-p 'line 'heading))))))
>     >
>     >     (defun org-buffers-delete-properties ()
>     >      (let ((buffer-read-only nil))
>     >        (save-excursion
>     >          (goto-char (point-min))
>     >          (org-buffers-delete-regions
>     >           (nreverse
>     >     (org-buffers-map-entries 'org-buffers-get-property-block))))))
>     >
>     >     (defun org-buffers-get-property-block ()
>     >      "Return the (beg . end) range of the property drawer.
>     >     Unlike the org version the limits include the keywords delimiting
>     >     the drawer."
>     >      (let ((beg (point))
>     >     (end (progn (outline-next-heading) (point))))
>     >        (goto-char beg)
>     >        (if (re-search-forward org-property-drawer-re end t)
>     >     (cons (match-beginning 1) (match-end 0)))))
>     >
>     >     (defun org-buffers-group-by (property)
>     >      "Group top level headings according to the value of PROPERTY."
>     >      (let ((atom (org-buffers-state-get :atom)))
>     >        (save-excursion
>     >          (goto-char (point-min))
>     >          (mapc (lambda (subtree) ;; Create subtree for each value of
>     `property'
>     >          (org-insert-heading t)
>     >          (if (> (org-buffers-outline-level) 1)
>     >      (org-promote))
>     >          (insert (car subtree) "\n")
>     >          (org-insert-subheading t)
>     >          (mapc 'org-buffers-insert-parsed-entry (cdr subtree)))
>     >        (prog1
>     >     (mapcar (lambda (val) ;; Form list of parsed entries for each unique
>     value
>     >     of `property'
>     >      (cons val (org-buffers-parse-selected-entries property val)))
>     >     (sort
>     >     (delete-dups (org-buffers-map-entries (lambda () (org-entry-get nil
>     >     property nil))))
>     >     'string<))
>     >          (erase-buffer))))))
>     >
>     >     (defun org-buffers-exclude-p (buffer)
>     >      "Return non-nil if BUFFER should not be listed."
>     >      (or (member (with-current-buffer buffer major-mode)
>     >          org-buffers-excluded-modes)
>     >          (member buffer org-buffers-excluded-buffers)
>     >          (string= (substring buffer 0 1) " ")))
>     >
>     >     (defun org-buffers-reset-state ()
>     >      (org-buffers-set-state
>     >       '((:by . "major-mode") (:atom . heading) (:properties . nil))))
>     >
>     >     (defun org-buffers-columns-view ()
>     >      "View buffers in Org-mode columns view.
>     >     This is currently experimental. RET can be used to follow links
>     >     in the first column, but certain other org-buffers keys conflict
>     >     with column-view or otherwise do not work correctly."
>     >      (interactive)
>     >      (let ((by (org-buffers-state-get :by))
>     >     (buffer-read-only nil))
>     >        (unless (equal by "NONE") (org-buffers-list:by "NONE"))
>     >        (unless (org-buffers-state-get :properties)
>     >          (org-buffers-toggle-properties))
>     >        (unless (equal by "NONE")
>     >          (goto-char (point-min))
>     >          (org-sort-entries-or-items nil ?r nil nil by)
>     >          (org-overview))
>     >        (mark-whole-buffer)
>     >        (org-columns)))
>     >
>     >     ;;; Parsing and inserting entries
>     >     (defun org-buffers-parse-selected-entries (prop val)
>     >      "Parse all entries with property PROP value VAL."
>     >      (delq nil
>     >     (org-buffers-map-entries
>     >     (lambda () (when (equal (org-entry-get nil prop) val)
>     >          (cons (org-get-heading) (org-get-entry)))))))
>     >
>     >     (defun org-buffers-insert-parsed-entry (entry)
>     >      "Insert a parsed entry"
>     >      (unless (org-at-heading-p) (org-insert-heading))
>     >      (insert (car entry) "\n")
>     >      (if (org-buffers-state-get :properties)
>     >          (insert (cdr entry))))
>     >
>     >     (defun org-buffers-get-buffer-props (buffer)
>     >      "Create alist of properties of BUFFER, as strings."
>     >      (with-current-buffer buffer
>     >        (mapcar
>     >         (lambda (pair) (cons (car pair) (eval (cdr pair))))
>     >         org-buffers-buffer-properties)))
>     >
>     >     ;;; Follow-link behaviour
>     >
>     >     (defun org-buffers-follow-link ()
>     >      "Follow link to buffer on this line.
>     >     The buffer-switching behaviour of this function is determined by
>     >     the variable `org-buffers-follow-link-method'. See also
>     >     `org-buffers-switch-to-buffer' and
>     >     `org-buffers-switch-to-buffer-other-window', whose behaviour is
>     >     hard-wired."
>     >      (interactive)
>     >      (org-buffers-switch-to-buffer-generic
>     org-buffers-follow-link-method))
>     >
>     >     (defun org-buffers-switch-to-buffer ()
>     >     "Switch to this entry's buffer in current window."
>     >      (interactive)
>     >      (org-buffers-switch-to-buffer-generic 'current-window))
>     >
>     >     (defun org-buffers-switch-to-buffer-other-window ()
>     >      "Switch to this entry's buffer in other window."
>     >      (interactive)
>     >      (org-buffers-switch-to-buffer-generic 'other-window))
>     >
>     >     (defun org-buffers-switch-to-buffer-generic (method)
>     >      (save-excursion
>     >        (let ((atom (org-buffers-state-get :atom)) buffer)
>     >          (cond
>     >           ((eq atom 'heading) (org-back-to-heading))
>     >           (t (beginning-of-line)))
>     >          (setq buffer (org-buffers-get-buffer-name))
>     >          (if (get-buffer buffer)
>     >      (case method
>     >        ('org-open-at-point (org-open-at-point))
>     >        ('current-window (switch-to-buffer buffer))
>     >        ('other-window (switch-to-buffer-other-window buffer)))
>     >     (error "No such buffer: %s" buffer)))))
>     >
>     >     (defun org-buffers-get-buffer-name ()
>     >      "Get buffer-name for current entry."
>     >      (let ((headings-p (org-buffers-state-eq :atom 'heading)))
>     >        (or (and headings-p (org-entry-get nil "buffer-name"))
>     >     (and (save-excursion
>     >           (if headings-p (org-back-to-heading))
>     >           (re-search-forward "\\[\\[buffer:\\([^\]]*\\)" (point-at-eol)
>     t))
>     >         (org-link-unescape (match-string 1))))))
>     >
>     >     ;;; Setting tags and executing operations
>     >
>     >     (defun org-buffers-tag-for-deletion ()
>     >      "Mark buffer for deletion.
>     >     If a region is selected, all buffers in the region are marked for
>     >     deletion. Buffers marked for deletion can be deleted using
>     >     `org-buffers-execute-pending-operations'."
>     >      (interactive)
>     >      (org-buffers-set-tags '("delete")))
>     >
>     >     (defun org-buffers-remove-tags ()
>     >      "Remove deletion marks from buffers.
>     >     If a region is selected, marks are removed from all buffers in
>     >     the region."
>     >      (interactive)
>     >      (org-buffers-set-tags nil))
>     >
>     >     (defun org-buffers-set-tags (data)
>     >      "Set tags to DATA at all non top-level headings in region.
>     >     DATA should be a list of strings. If DATA is nil, remove all tags
>     >     at such headings."
>     >      (let* ((buffer-read-only nil)
>     >     (region-p (org-region-active-p))
>     >     (beg (if region-p (region-beginning) (point)))
>     >     (end (if region-p (region-end) (point)))
>     >     (headings-p (org-buffers-state-eq :atom 'heading))beg-line end-line)
>     >        (save-excursion
>     >          (setq beg-line (progn (goto-char beg) (org-current-line))
>     >        end-line (progn (goto-char end) (org-current-line)))
>     >          (if headings-p
>     >      (setq
>     >       end (if (and region-p (not (eq end-line beg-line)) (not (eobp)))
>     >       (progn (goto-char end) (org-back-to-heading) (point))
>     >     (progn (outline-end-of-heading) (point)))
>     >       beg (progn (goto-char beg) (point-at-bol)))
>     >     (org-buffers-toggle-headings) ;; doesn't alter line numbers
>     >     (setq beg (progn (org-goto-line beg-line) (point-at-bol))
>     >          end (if (eq end-line beg-line) (point-at-eol)
>     >        (progn (org-goto-line end-line) (point-at-bol)))))
>     >          (narrow-to-region beg end)
>     >          (goto-char (point-min))
>     >          (org-buffers-map-entries
>     >           (lambda ()
>     >     (when (or (org-buffers-state-eq :by "NONE")
>     >       (> (org-outline-level) 1))
>     >       (org-set-tags-to
>     >        (if data (delete-duplicates (append data (org-get-tags)) :test
>     >     'string-equal))))))
>     >          (widen)
>     >          (org-content))
>     >        (unless region-p
>     >          (outline-next-heading)
>     >          (unless (or (> (org-outline-level) 1) (org-buffers-state-eq :by
>     >     "NONE"))
>     >     (outline-next-heading)))
>     >            (unless headings-p (org-buffers-toggle-headings))))
>     >
>     >     (defun org-buffers-execute-pending-operations ()
>     >      "Execute all pending operations.
>     >     Currently the only type of operation supported is
>     >     deletion. Buffers are tagged for deletion using
>     >     `org-buffers-tag-for-deletion'. Remove such tags from buffers
>     >     using `org-buffers-remove-tags'."
>     >      (interactive)
>     >      (let ((buffer-read-only nil)
>     >     (headings-p (org-buffers-state-eq :atom 'heading)) buffer)
>     >        (unless headings-p (org-buffers-toggle-headings))
>     >        (org-buffers-delete-regions
>     >         (nreverse
>     >          (org-buffers-map-entries
>     >           (lambda ()
>     >     (if (setq buffer (org-buffers-get-buffer-name))
>     >         (if (not (kill-buffer buffer))
>     >     (error "Failed to kill buffer %s" buffer)
>     >           (if (and (org-first-sibling-p)
>     >     (not (save-excursion (org-goto-sibling))))
>     >       (org-up-heading-safe)) ;; Only child so delete parent also
>     >           (cons (point) (1+ (org-end-of-subtree))))))
>     >           "+delete")))
>     >        (unless headings-p (org-buffers-toggle-headings))))
>     >
>     >     ;;; Utilities
>     >
>     >     (defun org-buffers-map-entries (func &optional match)
>     >      (org-scan-tags
>     >       func (if match (cdr (org-make-tags-matcher match)) t)))
>     >
>     >     (defun org-buffers-set-state (state)
>     >      "Add STATE to global state list.
>     >     New settings have precedence over existing ones."
>     >      (mapc
>     >       (lambda (pair) (unless (assoc (car pair) state)
>     >        (add-to-list 'state pair)))
>     >       org-buffers-state)
>     >      (setq org-buffers-state state))
>     >
>     >     (defmacro org-buffers-delete-regions (regions)
>     >      "Delete regions in list.
>     >     REGIONS is a list of (beg . end) cons cells specifying buffer
>     >     regions."
>     >      `(mapc (lambda (pair) (if pair (delete-region (car pair) (cdr
>     pair))))
>     >     ,regions))
>     >
>     >     (defmacro org-buffers-state-get (key)
>     >      `(cdr (assoc ,key org-buffers-state)))
>     >
>     >     (defmacro org-buffers-state-eq (key val)
>     >      `(equal (org-buffers-state-get ,key) ,val))
>     >
>     >     (defmacro org-buffers-outline-level ()
>     >      '(save-excursion (beginning-of-line) (org-outline-level)))
>     >
>     >     ;;; Links to buffers
>     >
>     >     (org-add-link-type "buffer" 'display-buffer)
>     >     (add-hook 'org-store-link-functions 'org-buffers-store-link)
>     >
>     >     (defun org-buffers-store-link (&optional force)
>     >      "Store a link to an Emacs buffer.
>     >     Returns nil by default, to avoid hijacking other link types."
>     >      (if force
>     >          (let* ((target (buffer-name))
>     >         (desc target) link)
>     >     (org-store-link-props :type "buffer")
>     >     (setq link (org-make-link "buffer:" target))
>     >     (org-add-link-props :link link :description desc)
>     >     link)))
>     >
>     >     (provide 'org-buffers)
>     >     ;;; org-buffers.el ends here
>     >     _______________________________________________
>     >     Emacs-orgmode mailing list
>     >     Please use `Reply All' to send replies to the list.
>     >     Emacs-orgmode@gnu.org
>     >     http://lists.gnu.org/mailman/listinfo/emacs-orgmode
>     >
>     >
>     > _______________________________________________
>     > Emacs-orgmode mailing list
>     > Please use `Reply All' to send replies to the list.
>     > Emacs-orgmode@gnu.org
>     > http://lists.gnu.org/mailman/listinfo/emacs-orgmode
>
>
> _______________________________________________
> Emacs-orgmode mailing list
> Please use `Reply All' to send replies to the list.
> Emacs-orgmode@gnu.org
> http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using Org for browsing and managing buffers
  2010-04-15 12:18     ` Eric S Fraga
@ 2010-04-19  3:47       ` Dan Davison
  2010-04-19  8:27         ` Eric S Fraga
  0 siblings, 1 reply; 13+ messages in thread
From: Dan Davison @ 2010-04-19  3:47 UTC (permalink / raw)
  To: Eric S Fraga; +Cc: emacs org-mode mailing list

[-- Attachment #1: Type: text/plain, Size: 4639 bytes --]

http://github.com/dandavison/org-buffers
http://github.com/dandavison/org-buffers/raw/master/org-buffers.el

Hi Eric,

Eric S Fraga <ucecesf@ucl.ac.uk> writes:
[...]
> - I like the fact I can customise RET or, more to the point, that it
>   be consistent with the rest of org-mode.  I personally would set
>   org-buffers-follow-link-method to 'current-window but then it would
>   be nice to have SPC, say, open the buffer in another window, to
>   behave consistently with org-agenda?

I've added the SPACE binding you suggest. And, although it would be
out-of-keeping with other org-mode links, it looks like there's a good
argument for making RET switch to the buffer in the same window, like
dired et al. I've done that. I've put a table at the end comparing
these bindings across a few different major modes.

> - I would prefer some consistency or symmetry in the creation and
>   burying of the buffer: given that (by default) org-buffers-list
>   brings up a new window in the current frame, quitting that buffer
>   should also delete the window;  otherwise, I would like it to not
>   split the frame.  Does that make sense?

Yes. This is all to do with pop-to-buffer versus switch-to-buffer, my
understanding of which was shaky. I have now changed to using
switch-to-buffer by default, and I think this gives behaviour
consistent with what you requested. I've also introduced a variable
org-buffers-switch-to-buffer-function which can be set to
'pop-to-buffer, in which case the variables pop-up-windows and
pop-up-frames, amongst others, become relevant.

> - what's the point of orb-buffers-toggle-heading? 

Cleaner (less starry) appearance, seeing as many buffers are named
*Like This*.

> I ask because I
>   don't understand what functionality it adds and the default binding
>   (h) conflicts with my speed keys (I use vi-like bindings for speed
>   motion keys).

I overlooked that before. I've moved it to H.

> - In column view mode (which I also have not figured out why it would
>   be used...), the heading uses a different font size than the normal
>   entries so the headings don't line up at all.  This may be my fault,
>   however.

I don't see this.

I've changed the column view binding to T ("tabular") so that the
standard speed commands c and C are available. As for the point, it kind
of comes full circle to the list-buffers / ibuffers appearance, thus
showing that most things are a subset of org.

> - if I bring up the buffers list a second time, having created a new
>   buffer in the meantime, the new buffer does not appear until I hit
>   'g'.  I think any invocation of org-buffers-list should do an
>   automatic update of the list.

A C-u prefix to org-buffers-list now forces update. I don't think I
agree that it should be default. Speed is my concern -- I'd like it to
show the listing immediately when possible. I believe we're both using
"atom"-powered netbooks, and mine at least is a little sluggish at
generating the listing. I notice dired says "The directory has changed
on disk, use g to update" so maybe I could do the same.

>
> - Lastly, it would be nice to either avoid the single blank line at
>   the start of the buffer or have point be at the first heading.
>   Having point at the first (empty) line seems to cause some problems
>   with speed motion keys sometimes...  it also wastes a line!

I've made point go to the first heading when the listing is
created. However, I am wary about getting rid of that initial line, as I
believe Carsten has said that Org/outline.el isn't always happy with
first heading on first line. Certainly, I'm not inserting that newline
character explicitly -- it appears via my (ab)use of Carsten's
functions.

>   Actually, I think it might be useful to have point be placed at the
>   heading that corresponds to the buffer currently being visited when
>   the org-buffers-list command is invoked.  A thought.

Yes I like that and I've done it. It will only happen with a fresh
listing though (first time, or C-u prefix), Otherwise buffer point is
maintained.

Along similar lines, I've made it so that if you invoke C-x f
(find-file) or C-x d (dired), the minibuffer prompt will start from the
directory of the buffer on the current line, rather than whatever
directory is associated with the listings buffer. I've found this useful
(only works for the keybindings currently, not for M-x or from menu).

Also you can now flag buffers for reversion (i.e. revert-buffer) using
"r"[6], and a few other changes.

Thanks, your suggestions have been really helpful.

Dan

This table is with (setq pop-up-windows t), which is default in emacs23.

[-- Attachment #2.1: Type: text/plain, Size: 1499 bytes --]

|              | switch       | switch          | display other-window |           |
|              | same window  | other window    | without switch       | next item |
|              |              | (pop-to-buffer) |                      |           |
|--------------+--------------+-----------------+----------------------+-----------|
| dired        | RET          | o               | unavailable?         | SPACE     |
| org links    | unavailable? | RET             | unavailable? [3]     |           |
| org agenda   | RET          | TAB             | SPACE [1]            |           |
| magit log    | unavailable? | RET             | SPACE                |           |
| gnus summary | unavailable? | unavailable?    | RET, SPACE [2]       |           |
| ibuffer      | RET          | o               | C-o                  | SPACE     |
| list-buffers | RET          | o               | C-o                  | SPACE     |
|--------------+--------------+-----------------+----------------------+-----------|
| org-buffers  | RET          | [5]               | SPACE[4]           |           |

[1] scrolls but does not advance to next automatically

[2] scrolls and space advances to next entry on reaching end; RET doesn't advance

[3] for org-mode links, SPACE could be bound to
display-in-other-window-without-switching-and-scroll (?)

[4] scrolls and advances

[5] Customize variable org-buffers-switch-to-buffer-function, or bind
function org-buffers-switch-to-buffer-other-window.

[-- Attachment #2.2: Type: text/html, Size: 2633 bytes --]

[-- Attachment #3: Type: text/plain, Size: 56 bytes --]


[6] Helpful if you switch branches in version control.

[-- Attachment #4: Type: text/plain, Size: 201 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Please use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using Org for browsing and managing buffers
  2010-04-19  3:47       ` Dan Davison
@ 2010-04-19  8:27         ` Eric S Fraga
  2010-04-19 13:18           ` Dan Davison
  0 siblings, 1 reply; 13+ messages in thread
From: Eric S Fraga @ 2010-04-19  8:27 UTC (permalink / raw)
  To: Dan Davison; +Cc: emacs org-mode mailing list

On Sun, 18 Apr 2010 23:47:11 -0400, Dan Davison <davison@stats.ox.ac.uk> wrote:
> 
> Hi Eric,
> 
> Eric S Fraga <ucecesf@ucl.ac.uk> writes:
> [...]
> > - I like the fact I can customise RET or, more to the point, that it
> >   be consistent with the rest of org-mode.  I personally would set
> >   org-buffers-follow-link-method to 'current-window but then it would
> >   be nice to have SPC, say, open the buffer in another window, to
> >   behave consistently with org-agenda?
> 
> I've added the SPACE binding you suggest. And, although it would be
> out-of-keeping with other org-mode links, it looks like there's a good
> argument for making RET switch to the buffer in the same window, like
> dired et al. I've done that. I've put a table at the end comparing
> these bindings across a few different major modes.

Very nice summary!  Shows that there is significant inconsistency in
behaviour across typical/popular emacs modes.  Probably too late to
increase that consistency overall but I like the choices you have made
for org-buffers.

> > - what's the point of orb-buffers-toggle-heading? 
> 
> Cleaner (less starry) appearance, seeing as many buffers are named
> *Like This*.

Ah, true!

On this topic, one suggestion (which might be difficult to implement,
however): the best thing is about org is the hierarchical nature of
headlines.  This would seem to map well to the hierarchical nature of
modes.  For instance, org mode is also a text mode.  Would it make
sense to have all text mode buffers grouped with sub-modes (for want
of a better word) as subheadings?  On the other hand, I'm not sure
what this would add so probably ignore this... :-)

> > I ask because I
> >   don't understand what functionality it adds and the default binding
> >   (h) conflicts with my speed keys (I use vi-like bindings for speed
> >   motion keys).
> 
> I overlooked that before. I've moved it to H.

Doesn't seem to work for me (pulled from git this morning, 8am BST):

,----
| Debugger entered--Lisp error: (wrong-type-argument integer-or-marker-p nil)
|   delete-region(nil nil)
|   (lambda (pair) (delete-region (car pair) (cdr pair)))(nil)
|   mapc((lambda (pair) (delete-region (car pair) (cdr pair))) (nil nil (4614 . 4748) nil (4407 . 4572) nil (4204 . 4360) nil (3953 . 4169) (3695 . 3911) (3441 . 3653) (3193 . 3403) (2947 . 3157) (2693 . 2911) (2441 . 2649) (2197 . 2405) (1953 . 2163) nil (1767 . 1911) nil (1561 . 1712) nil (1300 . 1524) (1131 . 1270) (942 . 1091) (734 . 884) (555 . 696) nil (260 . 499) nil (50 . 201) nil))
|   org-buffers-delete-regions((nil nil (4614 . 4748) nil (4407 . 4572) nil (4204 . 4360) nil (3953 . 4169) (3695 . 3911) (3441 . 3653) (3193 . 3403) (2947 . 3157) (2693 . 2911) (2441 . 2649) (2197 . 2405) (1953 . 2163) nil (1767 . 1911) nil (1561 . 1712) nil (1300 . 1524) (1131 . 1270) (942 . 1091) (734 . 884) (555 . 696) nil (260 . 499) nil (50 . 201) nil))
|   (save-excursion (goto-char (point-min)) (org-buffers-delete-regions (nreverse ...)))
|   (let ((inhibit-read-only t)) (save-excursion (goto-char ...) (org-buffers-delete-regions ...)))
|   org-buffers-delete-properties()
|   (progn (org-buffers-delete-properties) (show-all) (org-buffers-set-state (quote ...)))
|   (if (org-buffers-state-get :properties) (progn (org-buffers-delete-properties) (show-all) (org-buffers-set-state ...)) (org-buffers-set-state (quote ...)) (org-buffers-list (quote refresh)))
|   org-buffers-toggle-properties()
|   (if (and headings-p (org-buffers-state-get :properties)) (org-buffers-toggle-properties))
|   (let ((inhibit-read-only t) (headings-p ...) (flat-p ...)) (if (and headings-p ...) (org-buffers-toggle-properties)) (save-excursion (goto-char ...) (if ... ...) (if flat-p ... ...) (mark-whole-buffer) (indent-region ... ...)) (org-buffers-set-state (\` ...)))
|   org-buffers-toggle-headings()
|   call-interactively(org-buffers-toggle-headings nil nil)
`----

> > - In column view mode (which I also have not figured out why it would
> >   be used...), the heading uses a different font size than the normal
> >   entries so the headings don't line up at all.  This may be my fault,
> >   however.
> 
> I don't see this.

doesn't seem to happen to me now.  I may have imagined it...

> > - if I bring up the buffers list a second time, having created a new
> >   buffer in the meantime, the new buffer does not appear until I hit
> >   'g'.  I think any invocation of org-buffers-list should do an
> >   automatic update of the list.
> 
> A C-u prefix to org-buffers-list now forces update. I don't think I
> agree that it should be default. Speed is my concern -- I'd like it

Okay.  I understand the motivation.  It comes down to the difference
in behaviour between the default buffers listing approach in emacs and
the way dired works.  As long as I remember that it's more like dired,
I'm happy!

> > - Lastly, it would be nice to either avoid the single blank line at
> >   the start of the buffer or have point be at the first heading.
> >   Having point at the first (empty) line seems to cause some problems
> >   with speed motion keys sometimes...  it also wastes a line!
> 
> I've made point go to the first heading when the listing is
> created. However, I am wary about getting rid of that initial line, as I
> believe Carsten has said that Org/outline.el isn't always happy with
> first heading on first line. Certainly, I'm not inserting that newline
> character explicitly -- it appears via my (ab)use of Carsten's
> functions.

Okay.

> >   Actually, I think it might be useful to have point be placed at the
> >   heading that corresponds to the buffer currently being visited when
> >   the org-buffers-list command is invoked.  A thought.
> 
> Yes I like that and I've done it. It will only happen with a fresh
> listing though (first time, or C-u prefix), Otherwise buffer point is
> maintained.

Okay, again like dired as opposed to list-buffers.  Fine.

> Along similar lines, I've made it so that if you invoke C-x f
> (find-file) or C-x d (dired), the minibuffer prompt will start from the
> directory of the buffer on the current line, rather than whatever
> directory is associated with the listings buffer. I've found this useful
> (only works for the keybindings currently, not for M-x or from
> menu).

This sounds very reasonable.

> Also you can now flag buffers for reversion (i.e. revert-buffer) using
> "r"[6], and a few other changes.

I have auto-revert-mode set on most buffers so this is not of great
use to me but I can see it being useful to others.

> Thanks, your suggestions have been really helpful.

You're very welcome!  Suggestions are easy; implementation is the
tricky bit. :-)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using Org for browsing and managing buffers
  2010-04-19  8:27         ` Eric S Fraga
@ 2010-04-19 13:18           ` Dan Davison
  0 siblings, 0 replies; 13+ messages in thread
From: Dan Davison @ 2010-04-19 13:18 UTC (permalink / raw)
  To: e.fraga; +Cc: emacs org-mode mailing list

> On this topic, one suggestion (which might be difficult to implement,
> however): the best thing is about org is the hierarchical nature of
> headlines.  This would seem to map well to the hierarchical nature of
> modes.  For instance, org mode is also a text mode.  Would it make
> sense to have all text mode buffers grouped with sub-modes (for want
> of a better word) as subheadings?  On the other hand, I'm not sure
> what this would add so probably ignore this... :-)

Other groupings might be good too. E.g. the comint process buffer for a
language grouped with the code files; all magit buffers in a magit tree;
all gnus buffers (summary, group, article) in a gnus tree. It seems that
the best thing might be to have a flexible way of specifying the tree
structure. E.g some way to specify "projects" for which all buffers
should be grouped together. Not sure how to implement that though.

I've also been wondering about adding recentf files (buffers you might
want, in addition to buffers you have). Then it might make sense to
present them in a hierarchy based on the filesystem location. That's
also true when grouping buffers by their directory (B def RET).

So making it work with > 2 levels of hierarchy is definitely something
worth thinking about, especially if someone has a good idea how to
specify the desired tree structure a priori.

A year or two ago someone posted code to preserve folding state of an
org buffer using an auxiliary file. Don't think it's in contrib. But I
might try to dig that out also. Anyone know where it is?

>
>> > I ask because I
>> >   don't understand what functionality it adds and the default binding
>> >   (h) conflicts with my speed keys (I use vi-like bindings for speed
>> >   motion keys).
>> 
>> I overlooked that before. I've moved it to H.
>
> Doesn't seem to work for me (pulled from git this morning, 8am BST):

Fixed, thanks!

Dan

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2010-04-19 13:20 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-04-09  1:17 Using Org for browsing and managing buffers Dan Davison
2010-04-09  3:43 ` Austin Frank
2010-04-09 14:49   ` Dan Davison
2010-04-14 20:23 ` Eric S Fraga
2010-04-15  4:20   ` Dan Davison
2010-04-15 12:18     ` Eric S Fraga
2010-04-19  3:47       ` Dan Davison
2010-04-19  8:27         ` Eric S Fraga
2010-04-19 13:18           ` Dan Davison
2010-04-15 10:11 ` Livin Stephen Sharma
2010-04-15 21:21   ` Dan Davison
2010-04-16  7:11     ` Livin Stephen Sharma
2010-04-16 14:22       ` Dan Davison

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).