Browse Source

babel: cleaned up code and improved documentation of indexing into variables

* lisp/ob-ref.el (org-babel-ref-index-list): slight code cleanup, also
  now allowing an empty index to mean the entire range

* doc/org.texi (var): updated the documentation of Babel index
  referencing to include working examples covering the full range of
  index behavior
Eric Schulte 15 years ago
parent
commit
32b7a76d41
2 changed files with 100 additions and 52 deletions
  1. 76 36
      doc/org.texi
  2. 24 16
      lisp/ob-ref.el

+ 76 - 36
doc/org.texi

@@ -11445,19 +11445,14 @@ The following header arguments are defined:
 
 
 @node var, results, Specific header arguments, Specific header arguments
 @node var, results, Specific header arguments, Specific header arguments
 @subsubsection @code{:var}
 @subsubsection @code{:var}
-The @code{:var} header argument is used to pass arguments to
-code blocks.  The specifics of how arguments are included
-in a code block vary by language; these are
-addressed in the language-specific documentation. However, the
-syntax used to specify arguments is the same across all
-languages.  The values passed to arguments can be
-@itemize @bullet
-@item literal values
-@item values from org-mode tables
-@item the results of other code blocks
-@end itemize
-
-These values can be indexed in a manner similar to arrays---see the argument
+The @code{:var} header argument is used to pass arguments to code blocks.
+The specifics of how arguments are included in a code block vary by language;
+these are addressed in the language-specific documentation. However, the
+syntax used to specify arguments is the same across all languages.  The
+values passed to arguments can be literal values, values from org-mode
+tables, or the results of other code blocks.
+
+These values can be indexed in a manner similar to arrays---see the
 ``indexable variable values'' heading below.
 ``indexable variable values'' heading below.
 
 
 The following syntax is used to pass arguments to code blocks using the
 The following syntax is used to pass arguments to code blocks using the
@@ -11540,43 +11535,88 @@ following the source name.
 @end example
 @end example
 
 
 @subsubheading Indexable variable values
 @subsubheading Indexable variable values
-It is possible to assign a portion of a value to a variable in a source
-block.  The following example assigns the second and third rows of the table
+It is possible to reference portions of variable values by ``indexing'' into
+the variables.  Indexes are 0 based with negative values counting back from
+the end.  If an index is separated by ``,''s then each subsequent section
+will index into the next deepest nesting or dimension of the value.  The
+following example assigns the last cell of the first row the table
 @code{example-table} to the variable @code{data}:
 @code{example-table} to the variable @code{data}:
 
 
 @example
 @example
-:var data=example-table[1:2]
-@end example
+#+results: example-table
+| 1 | a |
+| 2 | b |
+| 3 | c |
+| 4 | d |
 
 
-Note: ranges are indexed using the @code{:} operator.
+#+begin_src emacs-lisp :var data=example-table[0,-1]
+  data
+#+end_src
 
 
-Note: indices are 0 based.
+#+results:
+: a
+@end example
 
 
-The following example assigns the second column of the first row of
-@code{example-table} to @code{data}:
+Ranges of variable values can be referenced using two integer separated by a
+@code{:}, in which case the entire inclusive range is referenced.  For
+example the following assigns the entire first column of @code{example-table}
+to @code{data}.
 
 
 @example
 @example
-:var data=example-table[0,1]
+#+results: example-table
+| 1 | a |
+| 2 | b |
+| 3 | c |
+| 4 | d |
+
+#+begin_src emacs-lisp :var data=example-table[1:2]
+  data
+#+end_src
+
+#+results:
+| 2 | b |
+| 3 | c |
 @end example
 @end example
 
 
-It is possible to index into the results of code blocks as well as
-tables.  Any number of dimensions can be indexed.  Dimensions are separated
-from one another by commas.
+Additionally an empty index, or the single character @code{*} are both
+interpreted to mean the entire range and as such are equivalent to
+@code{0:-1}, as shown in the following example in which the entire first
+column is referenced.
+
+@example
+#+results: example-table
+| 1 | a |
+| 2 | b |
+| 3 | c |
+| 4 | d |
+
+#+begin_src emacs-lisp :var data=example-table[,0]
+  data
+#+end_src
+
+#+results:
+| 1 | 2 | 3 | 4 |
+@end example
 
 
-For more information on indexing behavior see the documentation for the
-@code{org-babel-ref-index-list} function, provided below.
+It is possible to index into the results of code blocks as well as tables.
+Any number of dimensions can be indexed.  Dimensions are separated from one
+another by commas, as shown in the following example.
 
 
-@deffn
-org-babel-ref-index-list is a Lisp function in `org-babel-ref.el'.
+@example
+#+source: 3D
+#+begin_src emacs-lisp
+  '(((1  2  3)  (4  5  6)  (7  8  9))
+    ((10 11 12) (13 14 15) (16 17 18))
+    ((19 20 21) (22 23 24) (25 26 27)))
+#+end_src
 
 
-(org-babel-ref-index-list index lis)
+#+begin_src emacs-lisp :var data=3D[1,,1]
+  data
+#+end_src
 
 
-Return the subset of LIS indexed by INDEX.  If INDEX is
-separated by ,s then each PORTION is assumed to index into the
-next deepest nesting or dimension.  A valid PORTION can consist
-of either an integer index, or two integers separated by a : in
-which case the entire range is returned.
-@end deffn
+#+results:
+| 11 | 14 | 17 |
+@end example
 
 
 @node results, file, var, Specific header arguments
 @node results, file, var, Specific header arguments
 @subsubsection @code{:results}
 @subsubsection @code{:results}

+ 24 - 16
lisp/ob-ref.el

@@ -177,28 +177,36 @@ return nil."
 
 
 (defun org-babel-ref-index-list (index lis)
 (defun org-babel-ref-index-list (index lis)
   "Return the subset of LIS indexed by INDEX.
   "Return the subset of LIS indexed by INDEX.
-If INDEX is separated by ,s then each PORTION is assumed to index
-into the next deepest nesting or dimension.  A valid PORTION can
-consist of either an integer index, or two integers separated by
-a : in which case the entire range is returned."
-  (if (string-match "^,?\\([^,]+\\)" index)
-      (let ((length (length lis))
+
+Indices are 0 based and negative indices count from the end of
+LIS, so 0 references the first element of LIS and -1 references
+the last.  If INDEX is separated by \",\"s then each \"portion\"
+is assumed to index into the next deepest nesting or dimension.
+
+A valid \"portion\" can consist of either an integer index, two
+integers separated by a \":\" in which case the entire range is
+returned, or an empty string or \"*\" both of which are
+interpreted to mean the entire range and as such are equivalent
+to \"0:-1\"."
+  (if (and (> (length index) 0) (string-match "^\\([^,]*\\),?" index))
+      (let ((ind-re "\\(\\([-[:digit:]]+\\):\\([-[:digit:]]+\\)\\|\*\\)")
+	    (length (length lis))
             (portion (match-string 1 index))
             (portion (match-string 1 index))
             (remainder (substring index (match-end 0))))
             (remainder (substring index (match-end 0))))
         (flet ((wrap (num) (if (< num 0) (+ length num) num))
         (flet ((wrap (num) (if (< num 0) (+ length num) num))
-               (open (lis) (if (and (listp lis) (= (length lis) 1)) (car lis) lis)))
+               (open (ls) (if (and (listp ls) (= (length ls) 1)) (car ls) ls)))
           (open
           (open
            (mapcar
            (mapcar
             (lambda (sub-lis) (org-babel-ref-index-list remainder sub-lis))
             (lambda (sub-lis) (org-babel-ref-index-list remainder sub-lis))
-            (if (string-match "\\(\\([-[:digit:]]+\\):\\([-[:digit:]]+\\)\\|\*\\)"
-                              portion)
-                (mapcar (lambda (n) (nth n lis))
-                        (apply 'number-sequence
-                               (if (match-string 2 portion)
-                                   (list
-                                    (wrap (string-to-number (match-string 2 portion)))
-                                    (wrap (string-to-number (match-string 3 portion))))
-                                 (list (wrap 0) (wrap -1)))))
+            (if (or (= 0 (length portion)) (string-match ind-re portion))
+                (mapcar
+		 (lambda (n) (nth n lis))
+		 (apply 'number-sequence
+			(if (and (> (length portion) 0) (match-string 2 portion))
+			    (list
+			     (wrap (string-to-number (match-string 2 portion)))
+			     (wrap (string-to-number (match-string 3 portion))))
+			  (list (wrap 0) (wrap -1)))))
               (list (nth (wrap (string-to-number portion)) lis)))))))
               (list (nth (wrap (string-to-number portion)) lis)))))))
     lis))
     lis))