Add first working draft of folder browser.
authorChris Hanson <org/chris-hanson/cph>
Sat, 26 May 2001 03:01:00 +0000 (03:01 +0000)
committerChris Hanson <org/chris-hanson/cph>
Sat, 26 May 2001 03:01:00 +0000 (03:01 +0000)
v7/src/imail/compile.scm
v7/src/imail/ed-ffi.scm
v7/src/imail/imail-browser.scm [new file with mode: 0644]
v7/src/imail/imail.pkg
v7/src/imail/print.sh

index c592cbe04bae7567db532a1f342d344db0da1d62..317fc13b2b5a5d957d4f65dfd3ec6b1e3326f53c 100644 (file)
@@ -1,8 +1,8 @@
 ;;; -*-Scheme-*-
 ;;;
-;;; $Id: compile.scm,v 1.10 2000/06/08 18:08:25 cph Exp $
+;;; $Id: compile.scm,v 1.11 2001/05/26 02:58:25 cph Exp $
 ;;;
-;;; Copyright (c) 2000 Massachusetts Institute of Technology
+;;; Copyright (c) 2000-2001 Massachusetts Institute of Technology
 ;;;
 ;;; This program is free software; you can redistribute it and/or
 ;;; modify it under the terms of the GNU General Public License as
@@ -16,7 +16,8 @@
 ;;;
 ;;; You should have received a copy of the GNU General Public License
 ;;; along with this program; if not, write to the Free Software
-;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+;;; 02111-1307, USA.
 
 ;;;; IMAIL mail reader: compilation
 
@@ -40,7 +41,8 @@
                     (access edwin-syntax-table (->environment '(EDWIN)))))
                (lambda (filename)
                  (compile-file filename '() syntax-table)))
-             '("imail-summary"
+             '("imail-browser"
+               "imail-summary"
                "imail-top"))
     (cref/generate-constructors "imail")
     (sf "imail.con")
index 1c695253de180e08ee6aa4c8e32768ccce459367..12bf6d6b65d90d29420f7ccbefbb5b7a96356101 100644 (file)
@@ -1,8 +1,8 @@
 ;;; -*-Scheme-*-
 ;;;
-;;; $Id: ed-ffi.scm,v 1.13 2000/07/05 00:13:18 cph Exp $
+;;; $Id: ed-ffi.scm,v 1.14 2001/05/26 02:58:27 cph Exp $
 ;;;
-;;; Copyright (c) 2000 Massachusetts Institute of Technology
+;;; Copyright (c) 2000-2001 Massachusetts Institute of Technology
 ;;;
 ;;; This program is free software; you can redistribute it and/or
 ;;; modify it under the terms of the GNU General Public License as
 ;;;
 ;;; You should have received a copy of the GNU General Public License
 ;;; along with this program; if not, write to the Free Software
-;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+;;; 02111-1307, USA.
 
 ;;;; IMAIL mail reader: Edwin buffer packaging info
 
 (standard-scheme-find-file-initialization
- '#(("imail-core"      (edwin imail)
+ '#(("imail-browser"   (edwin imail front-end folder-browser)
+                       edwin-syntax-table)
+    ("imail-core"      (edwin imail)
                        system-global-syntax-table)
     ("imail-file"      (edwin imail file-folder)
                        system-global-syntax-table)
diff --git a/v7/src/imail/imail-browser.scm b/v7/src/imail/imail-browser.scm
new file mode 100644 (file)
index 0000000..d39b6ab
--- /dev/null
@@ -0,0 +1,482 @@
+;;; -*-Scheme-*-
+;;;
+;;; $Id: imail-browser.scm,v 1.1 2001/05/26 03:00:53 cph Exp $
+;;;
+;;; Copyright (c) 2001 Massachusetts Institute of Technology
+;;;
+;;; 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 2 of the
+;;; License, 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 this program; if not, write to the Free Software
+;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+;;; 02111-1307, USA.
+
+;;;; IMAIL mail reader: folder browser
+
+#|
+
+To do:
+
+* Change revert command to preserve the position of point as well as
+  possible.
+
+* Change revert command to preserve which folders are expanded and
+  collapsed.
+
+* Change commands to operate on marked folders if any are marked:
+
+       imail-create-folder
+       imail-copy-folder
+       imail-rename-folder
+
+|#
+
+(declare (usual-integrations))
+\f
+(define-command imail-browse-container
+  "Visit a buffer showing the contents of an IMAIL container."
+  (lambda ()
+    (list (prompt-for-container "Browse container" #f
+                               'HISTORY 'IMAIL-BROWSE-CONTAINER
+                               'HISTORY-INDEX 0
+                               'REQUIRE-MATCH? #t)))
+  (lambda (url-string)
+    (let* ((url (imail-parse-partial-url url-string))
+          (container (open-resource url))
+          (buffer
+           (new-buffer
+            (string-append (url-presentation-name url)
+                           "-browser"))))
+      (set-buffer-imail-container! buffer container)
+      (set-buffer-imail-url-selector! buffer browser-selected-url)
+      (receive-modification-events container notice-container-events)
+      (rebuild-imail-browser-buffer buffer)
+      (select-buffer buffer))))
+
+(define (browser-selected-url mark)
+  (let ((info (browser-line-info #f mark)))
+    (and info
+        (browser-line-info-url info))))
+
+(define (rebuild-imail-browser-buffer buffer)
+  (let ((container (selected-container #t buffer)))
+    (buffer-widen! buffer)
+    (with-read-only-defeated (buffer-start buffer)
+      (lambda ()
+       (region-delete! (buffer-region buffer))
+       (let ((container-url (resource-locator container))
+             (mark (mark-left-inserting-copy (buffer-start buffer))))
+         (let ((title (url->string container-url)))
+           (insert-string title mark)
+           (insert-newline mark)
+           (insert-chars #\- (string-length title) mark)
+           (insert-newline mark))
+         (insert-browser-lines container-url container-url mark))))
+    (set-buffer-major-mode! buffer (ref-mode-object imail-browser))
+    (buffer-not-modified! buffer)
+    (set-buffer-read-only! buffer)
+    (set-buffer-point! buffer (buffer-start buffer))))
+\f
+(define (insert-browser-lines container-1 container-2 mark)
+  (for-each (lambda (subfolder-url)
+             (insert-browser-line subfolder-url container-2 mark))
+           (sort (container-url-contents container-1) browser-url<?)))
+
+(define (insert-browser-line url container-url mark)
+  (let ((start (mark-right-inserting-copy mark))
+       (info (make-browser-line-info url)))
+    (with-region-marked mark
+      (lambda (start end)
+       (region-put! start end 'IMAIL-BROWSER-LINE-INFO info))
+      (lambda ()
+       (insert-string "  " mark)
+       (insert-chars #\space (* 4 (browser-url-depth url container-url)) mark)
+       (with-region-marked mark
+         (lambda (start end)
+           (set-region-local-comtabs!
+            (make-region start end)
+            (let ((comtab (make-comtab)))
+              (define-key comtab button1-down
+                (ref-command-object imail-browser-mouse-toggle-container))
+              (list comtab))))
+         (lambda ()
+           (insert-char (if (browser-line-info-container-url info)
+                            #\+
+                            #\space)
+                        mark)))
+       (insert-char #\space mark)
+       (insert-string (url-content-name url) mark)
+       (insert-newline mark)))))
+
+(define (update-container-line-marker mark char)
+  (replace-right-char
+   (mark+ (line-start mark 0)
+         (+ 2
+            (* 4
+               (browser-url-depth
+                (selected-url #t mark)
+                (resource-locator
+                 (selected-container #t (mark-buffer mark)))))))
+   char))
+
+(define (browser-url-depth url container)
+  (let loop ((url* url))
+    (let ((container* (container-url url*)))
+      (if (eq? container* container)
+         0
+         (begin
+           (if (eq? container* url*)
+               (error "URL not in container:" url container))
+           (+ 1 (loop container*)))))))
+
+(define (make-browser-line-info url)
+  (vector url (url-is-container? url) #f))
+
+(define (browser-line-info-url info)
+  (vector-ref info 0))
+
+(define (browser-line-info-container-url info)
+  (vector-ref info 1))
+
+(define (browser-line-info-container-expanded? info)
+  (vector-ref info 2))
+
+(define (browser-line-info-container-expanded! info)
+  (vector-set! info 2 #t))
+
+(define (browser-line-info-container-collapsed! info)
+  (vector-set! info 2 #f))
+
+(define (browser-line-info #!optional error? mark)
+  (or (region-get (if (or (default-object? mark) (not mark))
+                     (current-point)
+                     mark)
+                 'IMAIL-BROWSER-LINE-INFO
+                 #f)
+      (and (if (default-object? error?) #t error?)
+          (editor-error "Point not on browser line."))))
+\f
+(define (notice-container-events container type arguments)
+  (for-each
+   (lambda (buffer)
+     (case type
+       ((CREATE-RESOURCE)
+       (let ((url (car arguments)))
+         (with-buffer-open buffer
+           (lambda ()
+             (call-with-values
+                 (lambda () (find-browser-line-for url buffer))
+               (lambda (mark match?)
+                 (let ((mark (mark-left-inserting-copy mark)))
+                   (if match?
+                       (delete-string mark (line-start mark 1 'LIMIT)))
+                   (insert-browser-line url
+                                        (resource-locator
+                                         (selected-container #t buffer))
+                                        mark)
+                   (mark-temporary! mark))))))))
+       ((DELETE-RESOURCE)
+       (let ((url (car arguments)))
+         (with-buffer-open buffer
+           (lambda ()
+             (call-with-values
+                 (lambda () (find-browser-line-for url buffer))
+               (lambda (mark match?)
+                 (if match?
+                     (delete-string mark
+                                    (line-start mark 1 'LIMIT)))))))))))
+   (find-browsers-for container)))
+
+(define (find-browsers-for container)
+  (list-transform-positive (buffer-list)
+    (lambda (buffer)
+      (or (eq? (selected-container #f buffer) container)
+         (memq container (browser-expanded-containers buffer))))))
+
+(define (browser-expanded-containers buffer)
+  (buffer-get buffer 'IMAIL-BROWSER-EXPANDED-CONTAINERS '()))
+
+(define (add-browser-expanded-container! buffer container)
+  (buffer-put! buffer
+              'IMAIL-BROWSER-EXPANDED-CONTAINERS
+              (let ((containers (browser-expanded-containers buffer)))
+                (if (memq container containers)
+                    containers
+                    (cons container containers)))))
+
+(define (remove-browser-expanded-container! buffer container)
+  (buffer-put! buffer
+              'IMAIL-BROWSER-EXPANDED-CONTAINERS
+              (delq! container (browser-expanded-containers buffer))))
+
+(define (find-browser-line-for url buffer)
+  (let loop ((mark (buffer-start buffer)))
+    (if (group-end? mark)
+       (values mark #f)
+       (let ((url* (selected-url #f mark)))
+         (cond ((not url*) (loop (line-start mark 1 'LIMIT)))
+               ((eq? url* url) (values mark #t))
+               ((browser-url<? url url*) (values mark #f))
+               (else (loop (line-start mark 1 'LIMIT))))))))
+
+(define (browser-url<? url1 url2)
+  (string<? (url->string url1) (url->string url2)))
+
+(define (url-contained? url1 url2)
+  (let loop ((url url1))
+    (or (eq? url url2)
+       (let ((url* (container-url url)))
+         (and (not (eq? url* url))
+              (loop url*))))))
+\f
+(define (with-buffer-open buffer thunk)
+  (without-text-clipped buffer
+    (lambda ()
+      (with-read-only-defeated buffer
+       (lambda ()
+         (let ((value (thunk)))
+           (buffer-not-modified! buffer)
+           value))))))
+
+(define (with-region-marked mark marker thunk)
+  (let ((start (mark-right-inserting-copy mark)))
+    (let ((value (thunk)))
+      (marker start mark)
+      (mark-temporary! start)
+      value)))
+
+(define (mouse-command-mark)
+  (let ((button-event (current-button-event)))
+    (let ((window (button-event/window button-event)))
+      (or (window-coordinates->mark window
+                                   (button-event/x button-event)
+                                   (button-event/y button-event))
+         (buffer-end (window-buffer window))))))
+
+(define (replace-right-char mark char)
+  (group-replace-char! (mark-group mark)
+                      (mark-index mark)
+                      char))
+\f
+(define-major-mode imail-browser read-only "IMAIL Browser"
+  "Major mode in effect in IMAIL folder browser.
+Each line summarizes a single mail folder.
+
+\\{imail-browser}"
+  (lambda (buffer)
+    (local-set-variable! truncate-lines #t buffer)
+    (buffer-put! buffer 'REVERT-BUFFER-METHOD imail-browser-revert-buffer)
+    (event-distributor/invoke! (ref-variable imail-browser-mode-hook buffer)
+                              buffer)))
+
+(define-variable imail-browser-mode-hook
+  "An event distributor that is invoked when entering IMAIL Browser mode."
+  (make-event-distributor))
+
+(define (imail-browser-revert-buffer buffer dont-use-auto-save? dont-confirm?)
+  dont-use-auto-save?
+  (if (or dont-confirm? (prompt-for-yes-or-no? "Revert IMAIL browser buffer"))
+      (rebuild-imail-browser-buffer buffer)))
+
+(define-key 'imail-browser #\+ 'imail-create-folder)
+(define-key 'imail-browser #\C 'imail-copy-folder)
+(define-key 'imail-browser #\R 'imail-rename-folder)
+
+(define-key 'imail-browser #\? 'describe-mode)
+(define-key 'imail-browser #\c 'imail-browser-view-container)
+(define-key 'imail-browser #\d 'imail-browser-flag-folder-deletion)
+(define-key 'imail-browser #\f 'imail-browser-view-folder)
+(define-key 'imail-browser #\g 'imail-browser-revert)
+(define-key 'imail-browser #\h 'describe-mode)
+(define-key 'imail-browser #\m 'imail-browser-mark-folder)
+(define-key 'imail-browser #\q 'imail-browser-quit)
+(define-key 'imail-browser #\t 'imail-browser-toggle-container)
+(define-key 'imail-browser #\u 'imail-browser-unmark)
+(define-key 'imail-browser #\x 'imail-browser-do-deletions)
+
+(define-key 'imail-browser #\rubout 'imail-browser-backup-unmark)
+(define-key 'imail-browser #\M-rubout 'imail-browser-unmark-all-folders)
+\f
+(define-command imail-browser-view-folder
+  ""
+  ()
+  (lambda ()
+    (let ((url (selected-url)))
+      (if (folder-url? url)
+         ((ref-command imail) (url->string url))
+         (editor-error "Not a selectable folder.")))))
+
+(define-command imail-browser-view-container
+  ""
+  ()
+  (lambda ()
+    (let ((url (selected-url)))
+      (let ((container (url-is-container? url)))
+       (if container
+           ((ref-command imail-browse-container) (url->string container))
+           (editor-error "Not a selectable container."))))))
+
+(define-command imail-browser-mouse-toggle-container
+  ""
+  ()
+  (lambda ()
+    ((ref-command imail-browser-toggle-container) (mouse-command-mark))))
+
+(define-command imail-browser-toggle-container
+  ""
+  "d"
+  (lambda (mark)
+    (let ((buffer (mark-buffer mark))
+         (info (browser-line-info #t mark)))
+      (let ((container (browser-line-info-container-url info)))
+       (if (not container)
+           (editor-error "Not on a container line."))
+       (with-buffer-open buffer
+         (lambda ()
+           (if (browser-line-info-container-expanded? info)
+               (let ((start (line-start mark 1 'LIMIT)))
+                 (let loop ((end start))
+                   (if (and (not (group-end? end))
+                            (let ((url (selected-url #f end)))
+                              (and url
+                                   (url-contained? url container))))
+                       (loop (line-start end 1 'LIMIT))
+                       (delete-string start end)))
+                 (update-container-line-marker mark #\+)
+                 (let ((container (get-memoized-resource container #f)))
+                   (if container
+                       (remove-browser-expanded-container! buffer container)))
+                 (browser-line-info-container-collapsed! info))
+               (begin
+                 (let ((mark
+                        (mark-left-inserting-copy
+                         (line-start mark 1 'LIMIT))))
+                   (insert-browser-lines container
+                                         (selected-container-url #t buffer)
+                                         mark)
+                   (mark-temporary! mark))
+                 (update-container-line-marker mark #\-)
+                 (let ((container (open-resource container)))
+                   (receive-modification-events container
+                                                notice-container-events)
+                 (add-browser-expanded-container! buffer container))
+                 (browser-line-info-container-expanded! info)))))))))
+
+(define-command imail-browser-revert
+  "Re-read the contents of the buffer."
+  ()
+  (lambda () (revert-buffer (selected-buffer) #t #t)))
+
+(define-command imail-browser-quit
+  "Kill the selected buffer.
+Discards any pending changes."
+  ()
+  (lambda () (kill-buffer-interactive (selected-buffer))))
+\f
+(define-command imail-browser-flag-folder-deletion
+  "Mark the folder under point to be deleted.
+With prefix argument, mark the next N folders for deletion."
+  "p"
+  (lambda (n) (imail-browser-mark-lines n #\D)))
+
+(define-command imail-browser-mark-folder
+  ""
+  "p"
+  (lambda (n) (imail-browser-mark-lines n #\*)))
+
+(define-command imail-browser-unmark
+  ""
+  "p"
+  (lambda (n) (imail-browser-mark-lines n #\space)))
+
+(define-command imail-browser-backup-unmark
+  ""
+  "p"
+  (lambda (n) ((ref-command imail-browser-unmark) (- n))))
+
+(define-command imail-browser-unmark-all-folders
+  ""
+  "cRemove marks (RET means all)"
+  (lambda (mark-char)
+    (let ((buffer (selected-buffer)))
+      (with-buffer-open buffer
+       (lambda ()
+         (let loop ((mark (line-start (buffer-start buffer) 0)))
+           (if (not (group-end? mark))
+               (begin
+                 (if (and (or (char=? mark-char #\return)
+                              (char=? (extract-right-char mark) mark-char))
+                          (selected-url #f mark))
+                     (replace-right-char mark #\space))
+                 (let ((mark (line-start mark 1 #f)))
+                   (if mark
+                       (loop mark)))))))))))
+
+(define (imail-browser-mark-lines n mark-char)
+  (with-buffer-open (selected-buffer)
+    (lambda ()
+      (cond ((> n 0)
+            (let loop ((n n) (mark (line-start (current-point) 0)))
+              (if (selected-url #f mark)
+                  (begin
+                    (replace-right-char mark mark-char)
+                    (let ((mark (line-start mark 1 'ERROR)))
+                      (set-current-point! mark)
+                      (if (> n 1)
+                          (loop (- n 1) mark))))
+                  (editor-failure))))
+           ((< n 0)
+            (let loop ((n n) (mark (line-start (current-point) -1 'ERROR)))
+              (set-current-point! mark)
+              (if (selected-url #f mark)
+                  (begin
+                    (replace-right-char mark mark-char)
+                    (if (< n -1)
+                        (loop (+ n 1) (line-start mark -1 'ERROR))))
+                  (editor-failure))))))))
+\f
+(define-command imail-browser-do-deletions
+  "Delete each folder that is marked for deletion."
+  ()
+  (lambda ()
+    (let ((buffer (selected-buffer)))
+      (with-buffer-open buffer
+       (lambda ()
+         (let ((urls (browser-marked-urls buffer #\D)))
+           (if (and (pair? urls)
+                    (cleanup-pop-up-buffers
+                     (lambda ()
+                       (browser-pop-up-urls-window urls)
+                       (prompt-for-yes-or-no? "Delete these folders"))))
+               (for-each delete-resource urls))))))))
+
+(define (browser-pop-up-urls-window urls)
+  (pop-up-temporary-buffer " *imail-browser-folders*"
+                          '(READ-ONLY SHRINK-WINDOW)
+    (lambda (buffer window)
+      (local-set-variable! truncate-partial-width-windows #f buffer)
+      (write-strings-densely
+       (map url->string urls)
+       (mark->output-port (buffer-point buffer))
+       (window-x-size (or window (car (buffer-windows buffer))))))))
+
+(define (browser-marked-urls buffer mark-char)
+  (let loop ((mark (buffer-start buffer)) (result '()))
+    (let ((char (extract-right-char mark)))
+      (if char
+         (loop (line-start mark 1 'ERROR)
+               (let ((url
+                      (and (eq? char mark-char)
+                           (selected-url #f mark))))
+                 (if url
+                     (cons url result)
+                     result)))
+         (reverse! result)))))
\ No newline at end of file
index 744084f8a61d151ec457a42f1c569d572ed85cef..34551f24bd270cd5a2f5d83e5a304432b43601d0 100644 (file)
@@ -1,6 +1,6 @@
 ;;; -*-Scheme-*-
 ;;;
-;;; $Id: imail.pkg,v 1.82 2001/05/18 19:21:12 cph Exp $
+;;; $Id: imail.pkg,v 1.83 2001/05/26 02:58:30 cph Exp $
 ;;;
 ;;; Copyright (c) 2000-2001 Massachusetts Institute of Technology
 ;;;
@@ -16,7 +16,8 @@
 ;;;
 ;;; You should have received a copy of the GNU General Public License
 ;;; along with this program; if not, write to the Free Software
-;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+;;; 02111-1307, USA.
 
 ;;;; IMAIL mail reader: packaging
 
          write-imail-summary-line!))
 
 (define-package (edwin imail front-end folder-browser)
-  ;;(files "imail-browser")
+  (files "imail-browser")
   (parent (edwin imail front-end))
-  (export (edwin)))
\ No newline at end of file
+  (export (edwin)
+         edwin-command$imail-browse-container
+         edwin-command$imail-browser-backup-unmark
+         edwin-command$imail-browser-do-deletions
+         edwin-command$imail-browser-flag-folder-deletion
+         edwin-command$imail-browser-mark-folder
+         edwin-command$imail-browser-mouse-toggle-container
+         edwin-command$imail-browser-quit
+         edwin-command$imail-browser-revert
+         edwin-command$imail-browser-toggle-container
+         edwin-command$imail-browser-unmark
+         edwin-command$imail-browser-unmark-all-folders
+         edwin-command$imail-browser-view-container
+         edwin-command$imail-browser-view-folder
+         edwin-mode$imail-browser
+         edwin-variable$imail-browser-mode-hook))
\ No newline at end of file
index 1064477b955d43725e5658f5ff667b7750f6fca9..88f30297b30de3d650a538687f57e94cd48acc24 100755 (executable)
@@ -1,8 +1,8 @@
 #!/bin/sh
 #
-# $Id: print.sh,v 1.8 2000/06/29 22:06:11 cph Exp $
+# $Id: print.sh,v 1.9 2001/05/26 03:01:00 cph Exp $
 #
-# Copyright (c) 1999-2000 Massachusetts Institute of Technology
+# Copyright (c) 1999-2001 Massachusetts Institute of Technology
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License as
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
 
-prlist todo.txt imail-top.scm imail-summary.scm imail-core.scm \
+prlist todo.txt imail-top.scm imail-summary.scm imail-browser.scm \
+  imail-core.scm \
   imail-imap.scm imap-response.scm imap-syntax.scm \
   imail-file.scm imail-rmail.scm imail-umail.scm \
   imail-util.scm url.scm parser.scm rexp.scm