From f7464fdd2e33e5dc6c159a4adc8f53902e6d4511 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 13 Apr 2011 23:20:15 -0400 Subject: Initial commit of Luke Shumaker's "dot-files". --- .emacs.d/org-7.4/contrib/babel/langs/ob-oz.el | 306 +++++++++++++++++ .../org-7.4/contrib/babel/library-of-babel.org | 370 +++++++++++++++++++++ 2 files changed, 676 insertions(+) create mode 100644 .emacs.d/org-7.4/contrib/babel/langs/ob-oz.el create mode 100644 .emacs.d/org-7.4/contrib/babel/library-of-babel.org (limited to '.emacs.d/org-7.4/contrib/babel') diff --git a/.emacs.d/org-7.4/contrib/babel/langs/ob-oz.el b/.emacs.d/org-7.4/contrib/babel/langs/ob-oz.el new file mode 100644 index 0000000..e1e6e35 --- /dev/null +++ b/.emacs.d/org-7.4/contrib/babel/langs/ob-oz.el @@ -0,0 +1,306 @@ +;;; ob-oz.el --- org-babel functions for Oz evaluation + +;; Copyright (C) 2009 Torsten Anders and Eric Schulte + +;; Author: Torsten Anders and Eric Schulte +;; Keywords: literate programming, reproducible research +;; Homepage: http://orgmode.org +;; Version: 0.01 + +;;; 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: + +;; Org-Babel support for evaluating Oz source code. +;; +;; Oz code is always send to the Oz Programming Environment (OPI), the +;; Emacs mode and compiler interface for Oz programs. Therefore, only +;; session mode is supported. In practice, non-session code blocks are +;; handled equally well by the session mode. However, only a single +;; session is supported. Consequently, the :session header argument is +;; ignored. +;; +;; The Org-babel header argument :results is interpreted as +;; follows. :results output requires the respective code block to be +;; an Oz statement and :results value requires an Oz +;; expression. Currently, results are only supported for expressions +;; (i.e. the result of :results output is always nil). +;; +;; Expression evaluation happens synchronously. Therefore there is an +;; additional header argument :wait-time , which specifies the +;; maximum time to wait for the result of a given expression. nil +;; means to wait as long as it takes to get a result (potentially wait +;; forever). +;; +;; NOTE: Currently the copyright of this file may not be in a state to +;; permit inclusion as core software into Emacs or Org-mode. + +;;; Requirements: + +;; - Mozart Programming System, the implementation of the Oz +;; programming language (http://www.mozart-oz.org/), which includes +;; the major mode mozart for editing Oz programs. +;; +;; - StartOzServer.oz which is located in the contrib/scripts +;; directory of the Org-mode repository + +;;; TODO: + +;; - Decide: set communication to \\switch -threadedqueries? +;; +;; - Only start Oz compiler when required, e.g., load Org-babel only when needed? +;; +;; - Avoid synchronous evaluation to avoid blocking Emacs (complex +;; Strasheela programs can take long to find a result..). In order +;; to cleanly map code blocks to their associated results (which can +;; arrive then in any order) I could use IDs +;; (e.g. integers). However, how do I do concurrency in Emacs Lisp, +;; and how can I define org-babel-execute:oz concurrently. +;; +;; - Expressions are rarely used in Oz at the top-level, and using +;; them in documentation and Literate Programs will cause +;; confusion. Idea: hide expression from reader and instead show +;; them statement (e.g., MIDI output statement) and then include +;; result in Org file. Implementation: for expressions (:results +;; value) support an additional header argument that takes arbitrary +;; Oz code. This code is not seen by the reader, but will be used +;; for the actual expression at the end. Alternative: feed all +;; relevant code as statement (:results output), then add expression +;; as extra code block which outputs, e.g., file name (so the file +;; name must be accessible by global var), but the code of this +;; extra codeblock is not seen. Hm, in that case it might be even +;; more easy to manually add this link to the Org file. +;; + + +(require 'ob) +;;; major mode for editing Oz programs +(require 'mozart) + +;; +;; Interface to communicate with Oz. +;; (1) For statements without any results: oz-send-string +;; (2) For expressions with a single result: oz-send-string-expression +;; (defined in org-babel-oz-ResultsValue.el) +;; + +;; oz-send-string-expression implements an additional very direct +;; communication between Org-babel and the Oz compiler. Communication +;; with the Oz server works already without this code via the function +;; oz-send-string from mozart.el.in, but this function does not get +;; back any results from Oz to Emacs. The following code creates a +;; socket for sending code to the OPI compiler and results are +;; returned by the same socket. On the Oz side, a socket is opened and +;; conected to the compiler of the OPI (via oz-send-string). On the +;; Emacs side, a connection to this socket is created for feeding code +;; and receiving results. This additional communication channel to the +;; OPI compiler ensures that results are returned cleanly (e.g., only +;; the result of the sent code is returned, no parsing or any +;; processing of *Oz Emulator* is required). +;; +;; There is no buffer, nor sentinel involved. Oz code is send +;; directly, and results from Oz are send back, but Emacs Lisp +;; requires a filter function for processing results. + +(defvar org-babel-oz-server-dir + (file-name-as-directory + (expand-file-name + "scripts" + (file-name-as-directory + (expand-file-name + "../../.." + (file-name-directory (or load-file-name buffer-file-name)))))) + "Path to the contrib/scripts directory in which +StartOzServer.oz is located.") + +(defvar org-babel-oz-port 6001 + "Port for communicating with Oz compiler.") +(defvar org-babel-oz-OPI-socket nil + "Socket for communicating with OPI.") + +(defvar org-babel-oz-collected-result nil + "Aux var to hand result from org-babel-oz-filter to oz-send-string-expression.") +(defun org-babel-oz-filter (proc string) + "Processes output from socket org-babel-oz-OPI-socket." +;; (setq org-babel-oz-collected-results (cons string org-babel-oz-collected-results)) + (setq org-babel-oz-collected-result string) + ) + + +(defun org-babel-oz-create-socket () + (message "Create OPI socket for evaluating expressions") + ;; Start Oz directly + (run-oz) + ;; Create socket on Oz side (after Oz was started). + (oz-send-string (concat "\\insert '" org-babel-oz-server-dir "StartOzServer.oz'")) + ;; Wait until socket is created before connecting to it. + ;; Quick hack: wait 3 sec + ;; + ;; extending time to 30 secs does not help when starting Emacs for + ;; the first time (and computer does nothing else) + (sit-for 3) + ;; connect to OPI socket + (setq org-babel-oz-OPI-socket + ;; Creates a socket. I/O interface of Emacs sockets as for processes. + (open-network-stream "*Org-babel-OPI-socket*" nil "localhost" org-babel-oz-port)) + ;; install filter + (set-process-filter org-babel-oz-OPI-socket #'org-babel-oz-filter) +) + +;; communication with org-babel-oz-OPI-socket is asynchronous, but +;; oz-send-string-expression turns is into synchronous... +(defun oz-send-string-expression (string &optional wait-time) + "Similar to oz-send-string, oz-send-string-expression sends a string to the OPI compiler. However, string must be expression and this function returns the result of the expression (as string). oz-send-string-expression is synchronous, wait-time allows to specify a maximum wait time. After wait-time is over with no result, the function returns nil." + (if (not org-babel-oz-OPI-socket) + (org-babel-oz-create-socket)) + (let ((polling-delay 0.1) + result) + (process-send-string org-babel-oz-OPI-socket string) + ;; wait for result + (if wait-time + (let ((waited 0)) + (unwind-protect + (progn + (while + ;; stop loop if org-babel-oz-collected-result \= nil or waiting time is over + (not (or (not (equal org-babel-oz-collected-result nil)) + (> waited wait-time))) + (progn + (sit-for polling-delay) +;; (message "org-babel-oz: next polling iteration") + (setq waited (+ waited polling-delay)))) +;; (message "org-babel-oz: waiting over, got result or waiting timed out") +;; (message (format "wait-time: %s, waited: %s" wait-time waited)) + (setq result org-babel-oz-collected-result) + (setq org-babel-oz-collected-result nil)))) + (unwind-protect + (progn + (while (equal org-babel-oz-collected-result nil) + (sit-for polling-delay)) + (setq result org-babel-oz-collected-result) + (setq org-babel-oz-collected-result nil)))) + result)) + +(defun org-babel-expand-body:oz (body params &optional processed-params) + (let ((vars (second (or processed-params (org-babel-process-params params)))))) + (if vars + ;; only add var declarations if any variables are there + (concat + ;; prepend code to define all arguments passed to the code block + "local\n" + (mapconcat + (lambda (pair) + (format "%s=%s" + (car pair) + (org-babel-oz-var-to-oz (cdr pair)))) + vars "\n") "\n" + "in\n" + body + "end\n") + body)) + +(defun org-babel-execute:oz (body params) + "Execute a block of Oz code with org-babel. This function is +called by `org-babel-execute-src-block' via multiple-value-bind." + (let* ((processed-params (org-babel-process-params params)) +;; (session (org-babel-ruby-initiate-session (first processed-params))) + (vars (second processed-params)) +;; (result-params (third processed-params)) + (result-type (fourth processed-params)) + (full-body (org-babel-expand-body:oz body params processed-params)) + (wait-time (plist-get params :wait-time)) + ;; set the session if the session variable is non-nil +;; (session-buffer (org-babel-oz-initiate-session session)) +;; (session (org-babel-prep-session:oz session params)) + ) + ;; actually execute the source-code block + (org-babel-reassemble-table + (case result-type + (output + (progn + (message "Org-babel: executing Oz statement") + (oz-send-string full-body))) + (value + (progn + (message "Org-babel: executing Oz expression") + (oz-send-string-expression full-body (if wait-time + wait-time + 1))))) + (org-babel-pick-name (nth 4 processed-params) (cdr (assoc :colnames params))) + (org-babel-pick-name (nth 5 processed-params) (cdr (assoc :rownames params)))))) + +;; This function should be used to assign any variables in params in +;; the context of the session environment. +(defun org-babel-prep-session:oz (session params) + "Prepare SESSION according to the header arguments specified in PARAMS." + (error "org-babel-prep-session:oz unimplemented")) +;; TODO: testing... (copied from org-babel-haskell.el) +;; (defun org-babel-prep-session:oz (session params) +;; "Prepare SESSION according to the header arguments specified in PARAMS." +;; (save-window-excursion +;; (org-babel-oz-initiate-session session) +;; (let* ((vars (org-babel-ref-variables params)) +;; (var-lines (mapconcat ;; define any variables +;; (lambda (pair) +;; (format "%s=%s" +;; (car pair) +;; (org-babel-ruby-var-to-ruby (cdr pair)))) +;; vars "\n")) +;; (vars-file (concat (make-temp-file "org-babel-oz-vars") ".oz"))) +;; (when vars +;; (with-temp-buffer +;; (insert var-lines) (write-file vars-file) +;; (oz-mode) +;; ;; (inferior-oz-load-file) ; ?? +;; )) +;; (current-buffer)))) +;; + + +;; TODO: testing... (simplified version of def in org-babel-prep-session:ocaml) +;; +;; BUG: does not work yet. Error: ad-Orig-error: buffer none doesn't exist or has no process +;; UNUSED DEF +(defun org-babel-oz-initiate-session (&optional session params) + "If there is not a current inferior-process-buffer in SESSION +then create. Return the initialized session." + (unless (string= session "none") + ;; TODO: make it possible to have multiple sessions + (save-window-excursion + ;; (run-oz) + (get-buffer oz-compiler-buffer)))) + +(defun org-babel-oz-var-to-oz (var) + "Convert an elisp var into a string of Oz source code +specifying a var of the same value." + (if (listp var) +;; (concat "[" (mapconcat #'org-babel-oz-var-to-oz var ", ") "]") + (eval var) + (format "%s" var) ; don't preserve string quotes. +;; (format "%s" var) + )) + +;; TODO: +(defun org-babel-oz-table-or-string (results) + "If the results look like a table, then convert them into an +Emacs-lisp table, otherwise return the results as a string." + (error "org-babel-oz-table-or-string unimplemented")) + + +(provide 'ob-oz) +;;; org-babel-oz.el ends here diff --git a/.emacs.d/org-7.4/contrib/babel/library-of-babel.org b/.emacs.d/org-7.4/contrib/babel/library-of-babel.org new file mode 100644 index 0000000..abc15a9 --- /dev/null +++ b/.emacs.d/org-7.4/contrib/babel/library-of-babel.org @@ -0,0 +1,370 @@ +#+title: The Library of Babel +#+author: Org-mode People +#+STARTUP: odd hideblocks + +* Introduction + The Library of Babel is an extensible collection of ready-made and + easily-shortcut-callable source-code blocks for handling common + tasks. Org-babel comes pre-populated with the source-code blocks + located in this file. It is possible to add source-code blocks from + any org-mode file to the library by calling =(org-babel-lob-ingest + "path/to/file.org")=. + + This file is included in worg mainly less for viewing through the + web interface, and more for contribution through the worg git + repository. If you have code snippets that you think others may + find useful please add them to this file and [[file:~/src/worg/worg-git.org::contribute-to-worg][contribute them]] to + worg. + + The raw Org-mode text of this file can be downloaded at + [[repofile:contrib/babel/library-of-babel.org][library-of-babel.org]] + +* Simple +A collection of simple utility functions + +#+srcname: echo +#+begin_src emacs-lisp :var input="echo'd" + input +#+end_src + +* File I/O +** reading and writing files +Read the contents of the file at =file=. The =:results vector= and +=:results scalar= header arguments can be used to read the contents of +file as either a table or a string. +#+srcname: read +#+begin_src emacs-lisp :var file="" :var format="" + (if (string= format "csv") + (with-temp-buffer + (org-table-import (expand-file-name file) nil) + (org-table-to-lisp)) + (with-temp-buffer + (insert-file-contents (expand-file-name file)) + (buffer-string))) +#+end_src + +Write =data= to a file at =file=. If =data= is a list, then write it +as a table in traditional Org-mode table syntax. +#+srcname: write +#+begin_src emacs-lisp :var data="" :var file="" :var ext='() + (flet ((echo (r) (if (stringp r) r (format "%S" r)))) + (with-temp-file file + (case (and (listp data) + (or ext (intern (file-name-extension file)))) + ('tsv (insert (orgtbl-to-tsv data '(:fmt echo)))) + ('csv (insert (orgtbl-to-csv data '(:fmt echo)))) + (t (org-babel-insert-result data))))) + nil +#+end_src + +** remote files +**** json +Read local or remote file in [[http://www.json.org/][json]] format into emacs-lisp objects. +#+srcname: json +#+begin_src emacs-lisp :var file='() :var url='() + (require 'json) + (cond + (file + (with-temp-filebuffer file + (goto-char (point-min)) + (json-read))) + (url + (require 'w3m) + (with-temp-buffer + (w3m-retrieve url) + (goto-char (point-min)) + (json-read)))) +#+end_src + +**** Google docs +The following code blocks make use of the [[http://code.google.com/p/googlecl/][googlecl]] Google command line +tool. This tool provides functionality for accessing Google services +from the command line, and the following code blocks use /googlecl/ +for reading from and writing to Google docs with Org-mode code blocks. + +****** read a document from Google docs +The =google= command seems to be throwing "Moved Temporarily" errors +when trying to download textual documents, but this is working fine +for spreadsheets. +#+source: gdoc-read +#+begin_src emacs-lisp :var title="example" :var format="csv" + (let* ((file (concat title "." format)) + (cmd (format "google docs get --format %S --title %S" format title))) + (message cmd) (message (shell-command-to-string cmd)) + (prog1 (if (string= format "csv") + (with-temp-buffer + (org-table-import (shell-quote-argument file) '(4)) + (org-table-to-lisp)) + (with-temp-buffer + (insert-file-contents (shell-quote-argument file)) + (buffer-string))) + (delete-file file))) +#+end_src + +For example, a line like the following can be used to read the +contents of a spreadsheet named =num-cells= into a table. +: #+call: gdoc-read(title="num-cells"") + +A line like the following can be used to read the contents of a +document as a string. +: #+call: gdoc-read(title="loremi", :format "txt") + +****** write a document to a Google docs +Write =data= to a google document named =title=. If =data= is tabular +it will be saved to a spreadsheet, otherwise it will be saved as a +normal document. +#+source: gdoc-write +#+begin_src emacs-lisp :var title="babel-upload" :var data=fibs(n=10) :results silent + (let* ((format (if (listp data) "csv" "txt")) + (tmp-file (make-temp-file "org-babel-google-doc" nil (concat "." format))) + (cmd (format "google docs upload --title %S %S" title tmp-file))) + (with-temp-file tmp-file + (insert + (if (listp data) + (orgtbl-to-csv + data '(:fmt (lambda (el) (if (stringp el) el (format "%S" el))))) + (if (stringp data) data (format "%S" data))))) + (message cmd) + (prog1 (shell-command-to-string cmd) (delete-file tmp-file))) +#+end_src + +example usage +: #+source: fibs +: #+begin_src emacs-lisp :var n=8 +: (flet ((fib (m) (if (< m 2) 1 (+ (fib (- m 1)) (fib (- m 2)))))) +: (mapcar (lambda (el) (list el (fib el))) (number-sequence 0 (- n 1)))) +: #+end_src +: +: #+call: gdoc-write(title="fibs", data=fibs(n=10)) + +* Plotting code + +** R + Plot column 2 (y axis) against column 1 (x axis). Columns 3 and beyond, if present, are ignored. + +#+srcname: R-plot(data=R-plot-example-data) +#+begin_src R +plot(data) +#+end_src + +#+tblname: R-plot-example-data +| 1 | 2 | +| 2 | 4 | +| 3 | 9 | +| 4 | 16 | +| 5 | 25 | + +#+lob: R-plot(data=R-plot-example-data) + +#+resname: R-plot(data=R-plot-example-data) +: nil + +** Gnuplot + +* Org reference +** headline references +#+source: headline +#+begin_src emacs-lisp :var headline=top :var file='() + (save-excursion + (when file (get-file-buffer file)) + (org-open-link-from-string (org-make-link-string headline)) + (save-restriction + (org-narrow-to-subtree) + (buffer-string))) +#+end_src + +#+call: headline(headline="headline references") + +* Tables +** LaTeX Table export +*** booktabs +This block can be used to wrap a table in the latex =booktabs= +environment, it takes the following arguments -- all but the first two +are optional. +| arg | description | +|-------+--------------------------------------------| +| table | a reference to the table | +| align | optional alignment string | +| env | optional environment, default to "tabular" | +| width | optional width specification string | + +#+srcname: booktabs +#+begin_src emacs-lisp :var table='((:head) hline (:body)) :var align='() :var env="tabular" :var width='() :noweb yes :results latex + (flet ((to-tab (tab) + (orgtbl-to-generic + (mapcar (lambda (lis) + (if (listp lis) + (mapcar (lambda (el) + (if (stringp el) + el + (format "%S" el))) lis) + lis)) tab) + (list :lend " \\\\" :sep " & " :hline "\\hline")))) + (org-fill-template + " + \\begin{%env}%width%align + \\toprule + %table + \\bottomrule + \\end{%env}\n" + (list + (cons "env" (or env "table")) + (cons "width" (if width (format "{%s}" width) "")) + (cons "align" (if align (format "{%s}" align) "")) + (cons "table" + ;; only use \midrule if it looks like there are column headers + (if (equal 'hline (second table)) + (concat (to-tab (list (first table))) + "\n\\midrule\n" + (to-tab (cddr table))) + (to-tab table)))))) +#+end_src + +*** longtable +This block can be used to wrap a table in the latex =longtable= +environment, it takes the following arguments -- all but the first two +are optional. +| arg | description | +|-----------+-------------------------------------------------------------| +| table | a reference to the table | +| align | optional alignment string | +| width | optional width specification string | +| hline | the string to use as hline separator, defaults to "\\hline" | +| head | optional "head" string | +| firsthead | optional "firsthead" string | +| foot | optional "foot" string | +| lastfoot | optional "lastfoot" string | + +#+srcname: longtable +#+begin_src emacs-lisp :var table='((:table)) :var align='() :var width='() :var hline="\\hline" :var firsthead='() :var head='() :var foot='() :var lastfoot='() :noweb yes :results latex + (org-fill-template + " + \\begin{longtable}%width%align + %firsthead + %head + %foot + %lastfoot + + %table + \\end{longtable}\n" + (list + (cons "width" (if width (format "{%s}" width) "")) + (cons "align" (if align (format "{%s}" align) "")) + (cons "firsthead" (if firsthead (concat firsthead "\n\\endfirsthead\n") "")) + (cons "head" (if head (concat head "\n\\endhead\n") "")) + (cons "foot" (if foot (concat foot "\n\\endfoot\n") "")) + (cons "lastfoot" (if lastfoot (concat lastfoot "\n\\endlastfoot\n") "")) + (cons "table" (orgtbl-to-generic + (mapcar (lambda (lis) + (if (listp lis) + (mapcar (lambda (el) + (if (stringp el) + el + (format "%S" el))) lis) + lis)) table) + (list :lend " \\\\" :sep " & " :hline hline))))) +#+end_src + +** Elegant lisp for transposing a matrix. + +#+tblname: transpose-example +| 1 | 2 | 3 | +| 4 | 5 | 6 | + +#+srcname: transpose +#+begin_src emacs-lisp :var table=transpose-example + (apply #'mapcar* #'list table) +#+end_src + +#+resname: +| 1 | 4 | +| 2 | 5 | +| 3 | 6 | + +* Misc +#+srcname: python-identity(a=1) +#+begin_src python +a +#+end_src +#+srcname: python-add(a=1, b=2) +#+begin_src python +a + b +#+end_src +* GANTT Charts + +The =elispgantt= source block was sent to the mailing list by Eric +Fraga. It was modified slightly by Tom Dye. + +#+source: elispgantt +#+begin_src emacs-lisp :var table=gantttest + (let ((dates "") + (entries (nthcdr 2 table)) + (milestones "") + (nmilestones 0) + (ntasks 0) + (projecttime 0) + (tasks "") + (xlength 1)) + (message "Initial: %s\n" table) + (message "Entries: %s\n" entries) + (while entries + (let ((entry (first entries))) + (if (listp entry) + (let ((id (first entry)) + (type (nth 1 entry)) + (label (nth 2 entry)) + (task (nth 3 entry)) + (dependencies (nth 4 entry)) + (start (nth 5 entry)) + (duration (nth 6 entry)) + (end (nth 7 entry)) + (alignment (nth 8 entry))) + (if (> start projecttime) (setq projecttime start)) + (if (string= type "task") + (let ((end (+ start duration)) + (textposition (+ start (/ duration 2))) + (flush "")) + (if (string= alignment "left") + (progn + (setq textposition start) + (setq flush "[left]")) + (if (string= alignment "right") + (progn + (setq textposition end) + (setq flush "[right]")))) + (setq tasks + (format "%s \\gantttask{%s}{%s}{%d}{%d}{%d}{%s}\n" + tasks label task start end textposition flush)) + (setq ntasks (+ 1 ntasks)) + (if (> end projecttime) + (setq projecttime end))) + (if (string= type "milestone") + (progn + (setq milestones + (format + "%s \\ganttmilestone{$\\begin{array}{c}\\mbox{%s}\\\\ \\mbox{%s}\\end{array}$}{%d}\n" + milestones label task start)) + (setq nmilestones (+ 1 nmilestones))) + (if (string= type "date") + (setq dates (format "%s \\ganttdateline{%s}{%d}\n" + dates label start)) + (message "Ignoring entry with type %s\n" type))))) + (message "Ignoring non-list entry %s\n" entry)) ; end if list entry + (setq entries (cdr entries)))) ; end while entries left + (format "\\pgfdeclarelayer{background} + \\pgfdeclarelayer{foreground} + \\pgfsetlayers{background,foreground} + \\renewcommand{\\ganttprojecttime}{%d} + \\renewcommand{\\ganttntasks}{%d} + \\noindent + \\begin{tikzpicture}[y=-0.75cm,x=0.75\\textwidth] + \\begin{pgfonlayer}{background} + \\draw[very thin, red!10!white] (0,1+\\ganttntasks) grid [ystep=0.75cm,xstep=1/\\ganttprojecttime] (1,0); + \\draw[\\ganttdatelinecolour] (0,0) -- (1,0); + \\draw[\\ganttdatelinecolour] (0,1+\\ganttntasks) -- (1,1+\\ganttntasks); + \\end{pgfonlayer} + %s + %s + %s + \\end{tikzpicture}" projecttime ntasks tasks milestones dates)) +#+end_src -- cgit v1.2.3-54-g00ecf