emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Contribution to SES (resend)


From: Vincent Belaïche
Subject: Contribution to SES (resend)
Date: Thu, 22 Apr 2010 08:52:51 +0200

Dear all,

I would like to make a contribution to SES, a user of which I am.

Here is the Change log which I propose:


--8<-------------coupez ici--------------début-------------->8---
2010-04-22  Vincent Belaïche  <address@hidden>

        * ses.el (ses-list): Addition of the ses-list macro in order to
        have more flexibility for range building. This also makes `ses+'
        kind of obsolete as `(apply 'ses+ (ses-range A1 A5))' can be
        replaced by `(apply '+ (ses-list A1 A5 !))' which is more
        universal as you could have anything instead of `+'.
--8<-------------coupez ici---------------fin--------------->8---

And here is a diff -c old new of ses.el:


--8<-------------coupez ici--------------début-------------->8---
*** ses.el.old  Wed Apr 21 21:34:40 2010
--- ses.el      Thu Apr 22 06:47:27 2010
***************
*** 141,146 ****
--- 141,147 ----
  (defconst ses-mode-edit-map
    (let ((keys '("\C-c\C-r"    ses-insert-range
                "\C-c\C-s"    ses-insert-ses-range
+               "\C-c\C-v"    ses-insert-ses-list
                [S-mouse-3]   ses-insert-range-click
                [C-S-mouse-3] ses-insert-ses-range-click
                "\M-\C-i"     lisp-complete-symbol))
***************
*** 1085,1091 ****
         ((ses-sym-rowcol cur)
        ;;Save this reference
        (add-to-list 'result-so-far cur))
!        ((eq (car-safe cur) 'ses-range)
        ;;All symbols in range are referenced
        (dolist (x (cdr (macroexpand cur)))
          (add-to-list 'result-so-far x)))
--- 1086,1092 ----
         ((ses-sym-rowcol cur)
        ;;Save this reference
        (add-to-list 'result-so-far cur))
!        ((memq (car-safe cur) '(ses-list ses-range))
        ;;All symbols in range are referenced
        (dolist (x (cdr (macroexpand cur)))
          (add-to-list 'result-so-far x)))
***************
*** 1144,1150 ****
            ;;implies 'delete.
            (unless ses-relocate-return
              (setq ses-relocate-return 'delete))))
!        ((eq (car-safe cur) 'ses-range)
          (setq cur (ses-relocate-range cur startrow startcol rowincr colincr))
          (if cur
              (push cur result)))
--- 1145,1151 ----
            ;;implies 'delete.
            (unless ses-relocate-return
              (setq ses-relocate-return 'delete))))
!        ((memq (car-safe cur) '(ses-list ses-range))
          (setq cur (ses-relocate-range cur startrow startcol rowincr colincr))
          (if cur
              (push cur result)))
***************
*** 1159,1175 ****
        (nreverse result))))
  
  (defun ses-relocate-range (range startrow startcol rowincr colincr)
!   "Relocate one RANGE, of the form '(ses-range min max).  Cells starting
! at (STARTROW,STARTCOL) are being shifted by (ROWINCR,COLINCR).  Result is the
! new range, or nil if the entire range is deleted.  If new rows are being added
! just beyond the end of a row range, or new columns just beyond a column range,
! the new rows/columns will be added to the range.  Sets `ses-relocate-return'
! if the range was altered."
    (let* ((minorig   (cadr range))
         (minrowcol (ses-sym-rowcol minorig))
         (min       (ses-relocate-symbol minorig minrowcol
                                         startrow startcol
                                         rowincr colincr))
         (maxorig   (nth 2 range))
         (maxrowcol (ses-sym-rowcol maxorig))
         (max       (ses-relocate-symbol maxorig maxrowcol
--- 1160,1179 ----
        (nreverse result))))
  
  (defun ses-relocate-range (range startrow startcol rowincr colincr)
!   "Relocate one RANGE, of the form '(ses-range min max) or
! '(ses-list min max ...).  Cells starting at (STARTROW,STARTCOL)
! are being shifted by (ROWINCR,COLINCR).  Result is the new range,
! or nil if the entire range is deleted.  If new rows are being
! added just beyond the end of a row range, or new columns just
! beyond a column range, the new rows/columns will be added to the
! range.  Sets `ses-relocate-return' if the range was altered."
    (let* ((minorig   (cadr range))
         (minrowcol (ses-sym-rowcol minorig))
         (min       (ses-relocate-symbol minorig minrowcol
                                         startrow startcol
                                         rowincr colincr))
+        (rest (cdddr range))
+        (fun (car range))
         (maxorig   (nth 2 range))
         (maxrowcol (ses-sym-rowcol maxorig))
         (max       (ses-relocate-symbol maxorig maxrowcol
***************
*** 1228,1234 ****
                 (funcall field (ses-sym-rowcol min))))
          ;;This range has changed size
          (setq ses-relocate-return 'range))
!       (list 'ses-range min max))))
  
  (defun ses-relocate-all (minrow mincol rowincr colincr)
    "Alter all cell values, symbols, formulas, and reference-lists to relocate
--- 1232,1238 ----
                 (funcall field (ses-sym-rowcol min))))
          ;;This range has changed size
          (setq ses-relocate-return 'range))
!       `( ,fun ,min ,max @,rest))))
  
  (defun ses-relocate-all (minrow mincol rowincr colincr)
    "Alter all cell values, symbols, formulas, and reference-lists to relocate
***************
*** 2823,2841 ****
                                            ,(cdr ses--curcell))))))
      (insert (substring (prin1-to-string (nreverse x)) 1 -1))))
  
! (defun ses-insert-ses-range ()
!   "Inserts \"(ses-range x y)\" in the minibuffer to represent the currently
! highlighted range in the spreadsheet."
!   (interactive "*")
    (let (x)
      (with-current-buffer (window-buffer minibuffer-scroll-window)
        (ses-command-hook)  ;For ses-coverage
        (ses-check-curcell 'needrange)
!       (setq x (format "(ses-range %S %S)"
                      (car ses--curcell)
                      (cdr ses--curcell))))
      (insert x)))
  
  (defun ses-insert-range-click (event)
    "Mouse version of `ses-insert-range'."
    (interactive "*e")
--- 2827,2859 ----
                                            ,(cdr ses--curcell))))))
      (insert (substring (prin1-to-string (nreverse x)) 1 -1))))
  
! (defun ses--insert-ses-range-or-ses-list (to-be-inserted)
!   "Insert \"(ses-range x y)\" or \"(ses-list x y)\" into the
!   minibuffer depending on TO-BE-INSERTED being equal to \"range\"
!   or to \"list\"."
    (let (x)
      (with-current-buffer (window-buffer minibuffer-scroll-window)
        (ses-command-hook)  ;For ses-coverage
        (ses-check-curcell 'needrange)
!       (setq x (format "(ses-%s %S %S)"
!                     to-be-inserted
                      (car ses--curcell)
                      (cdr ses--curcell))))
      (insert x)))
  
+ (defun ses-insert-ses-range ()
+   "Inserts \"(ses-range x y)\" in the minibuffer to represent the currently
+ highlighted range in the spreadsheet."
+   (interactive "*")
+   (ses--insert-ses-range-or-ses-list "range"))
+ 
+ (defun ses-insert-ses-list ()
+   "Inserts \"(ses-list x y)\" in the minibuffer to represent the currently
+ highlighted range in the spreadsheet."
+   (interactive "*")
+   (ses--insert-ses-range-or-ses-list "list"))
+ 
+ 
  (defun ses-insert-range-click (event)
    "Mouse version of `ses-insert-range'."
    (interactive "*e")
***************
*** 2890,2901 ****
    "Expands to a list of cell-symbols for the range.  The range automatically
  expands to include any new row or column inserted into its middle.  The SES
  library code specifically looks for the symbol `ses-range', so don't create an
! alias for this macro!"
    (let (result)
      (ses-dorange (cons from to)
        (push (ses-cell-symbol row col) result))
      (cons 'list result)))
  
  (defun ses-delete-blanks (&rest args)
    "Return ARGS reversed, with the blank elements (nil and *skip*) removed."
    (let (result)
--- 2908,3030 ----
    "Expands to a list of cell-symbols for the range.  The range automatically
  expands to include any new row or column inserted into its middle.  The SES
  library code specifically looks for the symbol `ses-range', so don't create an
! alias for this macro!
! 
! Cells are listed in reverse order, that is to say from TO up to
! FROM, for instance `(ses-range A1 B2)' will produce (B2 B1 A2
! A1). This is important to know if you make a formula like `(apply
! '- (ses-range A1 A5))'."
    (let (result)
      (ses-dorange (cons from to)
        (push (ses-cell-symbol row col) result))
      (cons 'list result)))
  
+ (defun ses--clean-! (&rest x)
+   "Clean by delq list X from any occurrence of `nil' or `*skip*'"
+   (delq nil (delq '*skip* x)))
+ 
+ (defun ses--clean-!x (x y)
+   "Clean list X  by replacing by Y any occurrence of `nil' or `*skip*'.
+    This will change X by making setcar on its cons cells."
+   (let ((ret x) ret-elt)
+     (while ret
+       (setq ret-elt (car ret))
+       (when (memq ret-elt '(nil *skip*))
+       (setcar ret y))
+       (setq ret (cdr ret))))
+   x)
+ 
+ (defsubst ses--clean-!0 (&rest x) 
+   "Clean list X by replacing by 0  any occurrence of `nil' or `*skip*'.
+    This will change X by making setcar on its cons cells."
+   (ses--clean-!x x 0))
+ (defsubst ses--clean-!. (&rest x) 
+   "Clean list X by replacing by \"\"  any occurrence of `nil' or `*skip*'.
+    This will change X by making setcar on its cons cells."
+   (ses--clean-!x x ""))
+ 
+ (defmacro ses-list (from to &rest rest)
+   "Expands to a list of cell-symbols for the range groing from
+ FROM up to TO.  The range automatically expands to include any
+ new row or column inserted into its middle.  The SES library code
+ specifically looks for the symbol `ses-list', so don't create an
+ alias for this macro!
+ 
+ By passing in REST some flags one can configure the way the range
+ is read and how it is formatted. 
+ 
+ In the sequel we assume that cells A1, B1, A2 B2 have respective values
+ 1 2 3 and 4 for examplication.
+ 
+ A `>v' (default) `>^', `<v', `<^', `v>', `v<', `^>', `^<' flag
+ will configure the order of browsing through the range. This
+ way `(ses-list A1 B2 ^>)' will evaluate to `(1 3 2 4)',
+ while `(ses-list A1 B2 >^)' will evaluate to (3 4 1 2).
+ 
+ A `!' flag will remove all cells whose value is nil or `*skip*'
+ while `!0' will replace them by 0, and `!.' will replace them by
+ \"\".
+ 
+ A `*', `*1' or `*2' flag will vectorize the range in the sense of
+ Calc. See info node `(Calc) Top'. Flag `*' will output either a
+ vector or a matrix depending on the number of rows, `*1' will
+ flatten the result to a one row vector, and `*2' will make a
+ matrix whatever the number of rows. 
+ 
+ Warning: interaction with Calc is expermimental and may produce
+ confusing results if you are not aware of Calc data format. Use
+ `math-format-value' as a printer for Calc objects."
+   (let (result-row result (prev-row -1)
+                  reorient-x reorient-y transpose vectorize 
+                  (clean 'list))
+     (ses-dorange (cons from to)
+       (when (/= prev-row row)
+       (push result-row result)
+       (setq result-row nil))
+       (push (ses-cell-symbol row col) result-row)
+       (setq prev-row row))
+     (push result-row result)
+     (dolist (x rest)
+       (let ((s  (assq x `((>v setq transpose nil reorient-x nil reorient-y 
nil)
+                         (>^ setq transpose nil reorient-x nil reorient-y t) 
+                         (<^ setq transpose nil reorient-x t reorient-y t) 
+                         (<v setq transpose nil reorient-x t reorient-y nil)   
+                         (v> setq transpose t reorient-x nil reorient-y t)     
+                         (^> setq transpose t reorient-x nil reorient-y nil)   
+                         (^< setq transpose t reorient-x t reorient-y nil) 
+                         (v< setq transpose t reorient-x t reorient-y t)   
+                         (*  . #1=(setq vectorize x))
+                         (*2 . #1#)
+                         (*1 . #1#)
+                         (! setq clean 'ses--clean-!)
+                         (!0 setq clean 'ses--clean-!0)
+                         (!. setq clean 'ses--clean-!\.) ))))
+       (if s (eval (cdr s))
+         (error "Unexpected flag `%S' in ses-list" x))))
+ 
+     (if reorient-y 
+       (setcdr (last result 2) nil)
+       (setq result (cdr (nreverse result))))
+     (unless reorient-x
+       (setq result (mapcar 'nreverse result)))
+     (when transpose
+       (let ((ret (mapcar (lambda (x) (list x)) (pop result))) iter)
+       (while result
+         (setq iter ret)
+         (dolist (elt (pop result))
+           (setcar iter (cons elt (car iter)))
+           (setq iter (cdr iter))))
+       (setq result ret)))
+ 
+     (eval (cdr (assq vectorize
+                    '((nil cons clean (apply 'append result))
+                      (*1 . #2=(cons clean (cons (quote 'vec) (apply 'append 
result))))
+                      (*2 . #3=(cons clean (cons (quote 'vec) (mapcar (lambda 
(x) 
+                                                                        (cons  
clean (cons (quote 'vec) x)))
+                                                                      
result))))
+                      (* if (cdr result) #3# #2#)))))))
+ 
+ 
  (defun ses-delete-blanks (&rest args)
    "Return ARGS reversed, with the blank elements (nil and *skip*) removed."
    (let (result)
***************
*** 2932,2938 ****
      (cons 'list result)))
  
  ;;All standard formulas are safe
! (dolist (x '(ses-cell-value ses-range ses-delete-blanks ses+ ses-average
             ses-select))
    (put x 'side-effect-free t))
  
--- 3061,3067 ----
      (cons 'list result)))
  
  ;;All standard formulas are safe
! (dolist (x '(ses-cell-value ses-range ses-list ses-delete-blanks ses+ 
ses-average
             ses-select))
    (put x 'side-effect-free t))
  

--8<-------------coupez ici---------------fin--------------->8---


Very best regards,

   Vincent.






reply via email to

[Prev in Thread] Current Thread [Next in Thread]