[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/gnuplot de13740 038/184: Added experimental context-sensit
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/gnuplot de13740 038/184: Added experimental context-sensitive completion and help code. |
Date: |
Sun, 29 Aug 2021 11:03:11 -0400 (EDT) |
branch: elpa/gnuplot
commit de137406c8674b85eec6dcfa7b6a2aec8e7031db
Author: Jonathan Oddie <j.j.oddie@gmail.com>
Commit: Jonathan Oddie <j.j.oddie@gmail.com>
Added experimental context-sensitive completion and help code.
---
.gitignore | 3 +-
gnuplot-context.el | 2113 ++++++++++++++++++++++++++++++++++++++++++++++
gnuplot-debug-context.el | 64 ++
3 files changed, 2179 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index 8acbc2b..c4d293f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,5 +4,6 @@
*.pdf
*.dvi
*~
-#*#
+/#*#
+*/#*#
/hacks.el
diff --git a/gnuplot-context.el b/gnuplot-context.el
new file mode 100644
index 0000000..4f3ecea
--- /dev/null
+++ b/gnuplot-context.el
@@ -0,0 +1,2113 @@
+;;;; gnuplot-context.el -- context-sensitive help and completion for gnuplot
+
+;; Copyright (C) 2012 Jonathan Oddie <j.j.oddie@gmail.com>
+
+;; Author: Jonathan Oddie <j.j.oddie@gmail.com>
+;; Maintainer: Jonathan Oddie <j.j.oddie@gmail.com>
+;; Created: Wednesday, 08 February 2012
+;; Updated: Wednesday, 08 February 2012
+;; Version: 0.6.1
+;; Keywords: gnuplot, plotting
+
+;; This file is not part of GNU Emacs.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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, or (at your option)
+;; any later version.
+;;
+;; This lisp script 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.
+;;
+;; Permission is granted to distribute copies of this lisp script
+;; provided the copyright notice and this permission are preserved in
+;; all copies.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, you can either send email to this
+;; program's maintainer or write to: The Free Software Foundation,
+;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; send bug reports to the author (j.j.oddie@gmail.com)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Commentary:
+;;
+;; This file provides context-sensitive completion, ElDoc support and
+;; info page links for gnuplot-mode buffers.
+;;
+;; Usage
+;; =====
+;;
+;; Put this file somewhere in your load path, byte compile and
+;; (require 'gnuplot-context). This will give you context-sensitive
+;; completion and info page links, assuming you have the correct
+;; version of the Gnuplot documentation installed somewhere in your
+;; info path.
+;;
+;; ElDoc support (one-line help displayed in the mode line) has to be
+;; compiled from the Gnuplot source tree. Running "doc2texi.el" in the
+;; "docs" directory should produce an Elisp "gnuplot-eldoc.el" file
+;; with ElDoc strings extracted from the gnuplot.doc documentation
+;; source. Install this somewhere in your load path. You can then
+;; toggle ElDoc on and off by typing M-x `eldoc-mode' in a gnuplot
+;; buffer, or put it in a load hook if you always want it on.
+;;
+;;
+;; Internal details
+;; ================
+;;
+;; Gnuplot's command language has a fair amount of syntactic
+;; complexity, and the only way I could think of to support these
+;; features was to do a complete parse of the command line. So that's
+;; what this package does. Instead of building a parse tree, it
+;; matches up until the token at point, and then either makes a list
+;; of possible completions, or sets the variables `gnuplot-eldoc' and
+;; `gnuplot-info-at-point' based on where it is in the grammar at that
+;; point.
+;;
+;; The parsing/matching process happens in two phases, tokenizing (see
+;; `gnuplot-tokenize') and matching (`gnuplot-match-pattern'). The
+;; simplest way I could think of to build a complete list of
+;; completions was to backtrack through the grammar and try every
+;; possible path. This is implemented in the parsing function
+;; `gnuplot-match-pattern' by simululating a stack machine with
+;; continuations. The grammar in S-expression notation
+;; (`gnuplot-grammar') is compiled down into a vector of "machine
+;; code" for the parsing machine (see `gnuplot-compile-pattern',
+;; `gnuplot-compile-grammar' and `gnuplot-compiled-grammar'). This is
+;; complicated, but it seems to work well enough, and saves on the
+;; Emacs call stack.
+;;
+;; Compiling the grammar does require increasing `max-lisp-eval-depth'
+;; modestly, which shouldn't cause any problems on modern machines, and
+;; only needs to be done once, when byte-compiling.
+;;
+;; The pattern-matching language
+;; =============================
+;;
+;; The gnuplot-mode grammar (see `gnuplot-compiled-grammar') is a list
+;; of rules (RULE PATTERN), with each pattern written in S-expression
+;; notation as follows:
+;;
+;; any
+;; Match any token
+;;
+;; name, number, string
+;; Match a token of the given type
+;;
+;; Any other symbol
+;; Match another named rule in the grammar. May be recursive.
+;;
+;; "STRING"
+;; Match literally: a token with exactly the text "STRING".
+;;
+;; (kw KEYWORD ALIASES ...)
+;; Match abbreviated Gnuplot keywords. KEYWORD can be a string or
+;; a cons (PREFIX . SUFFIX). In the latter case, this pattern
+;; will match PREFIX plus any number of characters from the
+;; beginning of SUFFIX. Any literal string from ALIASES will
+;; also match. The token-id of the matching token is mutated to
+;; the canonical value of KEYWORD.
+;; Example:
+;; (kw ("linew" ."idth") "lw") matches "linew", "linewi",
+;; ... "linewidth" as well as "lw". Any of these tokens will
+;; appear as "linewidth" in subsequent processing. (This is
+;; important for the "info-keyword" form, see below).
+;;
+;; The other pattern forms combine simpler patterns, much like regular
+;; expressions:
+;;
+;; (sequence { :eldoc "eldoc string" }
+;; { :info "info page" }
+;; PATTERN PATTERN... )
+;; Match all the PATTERNs in sequence or fail. Sequences can also
+;; have optional ElDoc strings and info pages associated with
+;; them; the innermost ElDoc or info page around point is the one
+;; shown to the user. Alternatively, either property may be a
+;; symbol, which should be a function to be called to get the
+;; real value. Finally, if no ElDoc string is specified but the
+;; variable `gnuplot-eldoc-hash' contains a value for the name of
+;; the info page at point, that value is used as the ElDoc string
+;; instead.
+;;
+;; (either PATTERN PATTERN...)
+;; Match the first PATTERN to succeed or fail. Like regexp `|'.
+;;
+;; (many PATTERN)
+;; Match PATTERN as many times as possible, like regexp
+;; `*'. Backtracks if a later part of the pattern fails.
+;;
+;; (lazy-many PATTERN)
+;; Similar to "many", but match as few times as possible, like
+;; regexp `*?'. This has the side effect of preferring whatever
+;; pattern comes afterwards for determining ElDoc and info
+;; strings; see the rule for "plot-expression" for an example.
+;;
+;; (maybe PATTERN)
+;; Match PATTERN 0 or 1 times, like regexp `?'.
+;;
+;; (capture NAME PATTERN)
+;; Match PATTERN, capturing the tokens in a capture group named
+;; NAME. Capture groups are stored in `gnuplot-captures'
+;; and can be retrieved using `gnuplot-capture-group'. This is
+;; used to store the plotting style, which we need in order to
+;; give the correct ElDoc string for "using" clauses, and for
+;; info keywords (see below)
+;;
+;; (info-keyword PATTERN)
+;; Match PATTERN, and use whatever the value of the first token
+;; it matches is to look up info pages for this pattern. Most
+;; Gnuplot info pages have the same name as the keyword they
+;; document, so by using this we only have to put :info
+;; properties on the few that don't (like "set").
+;;
+;; For convenience, "many", "lazy-many", "maybe", "capture" and
+;; "info-keyword" wrap the rest of their arguments in an implicit
+;; "sequence", so we can write (maybe "," expression) instead of
+;; (maybe (sequence "," expression))
+;;
+;; (delimited-list PATTERN SEPARATOR)
+;; Match a list of PATTERNs separated by SEPARATOR. Sugar for:
+;; (sequence PATTERN (many (sequence SEPARATOR PATTERN)))
+;;
+;; (assert LISP-FORM)
+;; Evaluate LISP-FORM and fail if it returns NIL. We need this in
+;; the patterns for "plot" and "splot" to check whether the
+;; command at point should be parsed in parametric mode or
+;; not. See `gnuplot-guess-parametric-p'.
+;;
+;;
+;; Bugs, TODOs, etc.
+;; =======================
+;;
+;; The tokenizer should stop before or at point, instead of going to the
+;; end of the line.
+;;
+;; In ElDoc mode, we parse the whole line every time the user stops
+;; typing. This is wasteful; should cache things in text properties
+;; instead.
+;;
+;; The pattern matching engine uses backtracking, which can take
+;; exponential time. So far it seems "fast enough" in actual use.
+;;
+;; The patterns don't really distinguish between "plot" and "splot"
+;; for things like plot styles, binary arguments, etc.
+;;
+;; Some other the patterns are probably not quite right, especially for
+;; things like abbreviated keywords, and features that I don't use
+;; myself like "fit". Hopefully anyone bothered by this will submit
+;; patches ;-)
+;;
+;; It would be possible to provide more helpful ElDoc strings for
+;; sub-parts of complicated options like "cntrparam". This is a time
+;; and maintenance issue rather than a technical one.
+;;
+;; It might be useful to complete on user-defined functions and
+;; variables as well as built-ins.
+;;
+
+(eval-when-compile (require 'cl))
+
+;; Prevent compiler warnings about undefined functions
+(eval-when-compile (require 'gnuplot))
+
+;; Load external ElDoc strings if we can find them.
+(defvar gnuplot-eldoc-hash nil
+ "ElDoc strings for gnuplot-mode.
+
+These have to be compiled from the Gnuplot source tree using
+`doc2texi.el'.")
+
+(condition-case nil
+ (load-library "gnuplot-eldoc")
+ (error
+ (setq gnuplot-eldoc-hash (make-hash-table))))
+
+
+;;;; The tokenizer.
+
+(defstruct gnuplot-token
+ start ; Buffer start position
+ end ; Buffer end position
+ id ; Text
+ type) ; name, number, string, operator, end-of-input
+
+(defvar gnuplot-token-at-point nil
+ "Gnuplot token at point, set by `gnuplot-tokenize'.")
+
+(defvar gnuplot-operator-regexp
+ (eval-when-compile
+ (regexp-opt
+ '("(" ")" "(" ")" "{" "," "}" "[" ":" "]" "!" "**" "-" "+" "~" "!" "*" "/"
+ "%" "+" "-" "." "<" "<=" ">" ">=" "==" "!=" "eq" "ne" "&" "^" "|" "&&"
"||"
+ "?" ":" "=" "$")))
+ "Regexp to match Gnuplot operators for tokenizing.")
+
+(eval-when-compile
+ (defmacro gnuplot-tokenize-by-regexps (&rest rules)
+ `(cond ,@(mapcar
+ (lambda (rule)
+ (let ((regexp (car rule))
+ (token-type (cadr rule)))
+ `((looking-at ,regexp)
+ (let ((str (match-string-no-properties 0)))
+ (forward-char (length str))
+ (make-gnuplot-token :id str
+ :type ',token-type
+ :start (match-beginning 0)
+ :end (match-end 0))))))
+ rules))))
+
+(defun gnuplot-tokenize ()
+ "Tokenize the Gnuplot command at point. Returns a list of `gnuplot-token'
objects."
+ (let ((p (point)))
+ (save-excursion
+ (gnuplot-beginning-of-command)
+ (let ((tokens '())
+ (parse-limit (gnuplot-point-at-end-of-command)))
+
+ (setq gnuplot-token-at-point nil)
+
+ (while (progn
+ (skip-syntax-forward "-")
+ (while (looking-at "\\\\\n")
+ (forward-line)
+ (skip-syntax-forward "-"))
+ (< (point) parse-limit))
+
+ (if (looking-at "#")
+ (goto-char parse-limit)
+
+ (let* ((from (point))
+ (token
+ (cond
+ ((gnuplot-tokenize-by-regexps
+ ("[A-Za-z_][A-Za-z0-9_]*" name)
+
("[0-9]+\\(\\.[0-9]*\\)?\\([eE][+-]?[0-9]+\\)?\\|\\.[0-9]+\\([eE][+-]?[0-9]+\\)?"
number)
+ (gnuplot-operator-regexp operator)))
+
+ ((looking-at "['\"]")
+ (let* ((bounds (bounds-of-thing-at-point 'sexp))
+ (from (point))
+ (to (or (cdr bounds)
+ parse-limit)))
+ (goto-char to)
+ (make-gnuplot-token
+ :id (buffer-substring-no-properties from to)
+ :type 'string
+ :start from :end to)))
+
+ (t (error
+ "gnuplot-tokenize: bad token beginning %s"
+ (buffer-substring-no-properties (point)
parse-limit))))))
+ (if (and (not gnuplot-token-at-point)
+ (eq (gnuplot-token-type token) 'name)
+ (<= p (gnuplot-token-end token)))
+ (setq gnuplot-token-at-point token))
+ (push token tokens))))
+
+ (let ((end-of-input
+ (make-gnuplot-token :type 'end-of-input
+ :start parse-limit
+ :end parse-limit)))
+ (when (not gnuplot-token-at-point)
+ (setq gnuplot-token-at-point end-of-input))
+
+ (nreverse (cons end-of-input tokens)))))))
+
+(defun gnuplot-end-of-tokens-p (tokens)
+ (or (not tokens)
+ (equal (gnuplot-token-type (car tokens)) 'end-of-input)))
+
+
+
+;;;; The pattern and grammar compiler
+;;
+;; These functions compile the source S-expression grammar into a
+;; vector of instructions for the parsing machine,
+;; `gnuplot-match-pattern'. Its state consists of a program counter
+;; (PC), a position in the list of tokens, a call stack, and a second
+;; stack of backtracking entries (continuations). Its "machine
+;; instructions" are the following:
+;;
+;; (any)
+;; Match any token (fails only at end of command).
+;;
+;; (literal LITERAL NO-COMPLETE)
+;; Match token with `gnuplot-token-id' LITERAL or fail. If we
+;; have reached the token before point, include LITERAL in the
+;; completion list unless NO-COMPLETE is non-`nil'.
+;;
+;; (token-type TYPE)
+;; Match a token with `gnuplot-token-type' TYPE, or fail.
+;;
+;; (keyword REGEXP NAME)
+;; Match any token whose `gnuplot-token-id' matches REGEXP. Use
+;; NAME for the completion list.
+;;
+;; (jump OFFSET FIXED)
+;; Jump to (set PC to) OFFSET if FIXED is non-nil, otherwise to
+;; PC + OFFSET
+;;
+;; (call OFFSET FIXED)
+;; Like "jump", but push a return address onto the stack for
+;; (return). (The compiler adds the name of the rule being called
+;; as a fourth element on the end of the list, but this is just a
+;; comment for debugging purposes).
+;;
+;; (return)
+;; Return to the PC address on top of the stack, or finish
+;; matching if stack is empty. (Usually this doesn't happen,
+;; because the machine stops as soon as it gets to the token at
+;; point).
+;;
+;; (choice OFFSET)
+;; Push a backtracking entry for location PC + OFFSET onto the
+;; backtracking stack. Backtracking entries save the contents of
+;; the call stack, position in the token list, and the values of
+;; capture groups.
+;;
+;; (fail)
+;; Pop the most recent backtracking entry and continue from
+;; there, or fail the whole match if out of backtrack
+;; points. Failing to match returns the remainder of the token
+;; list, although we don't currently use this for anything.
+;;
+;; (commit OFFSET)
+;; Discard one backtracking point and jump to PC + OFFSET. This
+;; is used to make the (either) form non-deterministic.
+;;
+;; (push TYPE VALUE)
+;; Push an entry for an eldoc or info string (specified by TYPE)
+;; onto the stack.
+;;
+;; (pop TYPE)
+;; Pop something off the stack; checks that it has the expected
+;; TYPE, for safety.
+;;
+;; (save-start NAME)
+;; Open a capture group named NAME. Pushes an entry onto
+;; `gnuplot-captures' with current position in token list as the
+;; start of the group.
+;;
+;; (save-end NAME)
+;; Close the capture group named NAME. Finds the topmost entry in
+;; `gnuplot-captures' with this name and sets its endpoint to the
+;; current position in token list. Error if no group with that
+;; name is found.
+;;
+;; (label NAME)
+;; This should never be reached and will cause an error. The
+;; compiler inserts it at the beginning of compiled rules only
+;; for debugging purposes.
+;;
+
+
+(eval-when-compile
+ ;; Compile a single pattern into a list of instructions. Leaves any
+ ;; calls to other rules as symbolic instructions (call SYMBOL); these
+ ;; are resolved into offsets by `gnuplot-compile-grammar', below.
+ (defun gnuplot-compile-pattern (pat)
+ (cond
+ ;; Strings match a single token literally
+ ((stringp pat)
+ ;; Don't add non-words to completion lists
+ (let ((wordp (string-match-p "^\\sw\\(\\sw\\|\\s_\\)*$" pat)))
+ `((literal ,pat ,(not wordp)))))
+
+ ;; Symbols match token types or calls to other patterns
+ ((symbolp pat)
+ (case pat
+ ((any) `((any)))
+ ((name number string) `((token-type ,pat)))
+ (t `((call ,pat)))))
+
+ ;; Other forms combine simpler patterns
+ (t
+ (let ((type (car pat)))
+ (case type
+ ;; (sequence...): concatenate patterns, with optional eldoc
+ ;; and info strings
+ ((sequence)
+ (destructuring-bind
+ (subpats eldoc info)
+ (gnuplot-filter-arg-list (cdr pat))
+ (let ((eldoc-push '()) (eldoc-pop '())
+ (info-push '()) (info-pop '())
+ (compiled
+ (mapcar 'gnuplot-compile-pattern subpats)))
+ (if eldoc
+ (setq eldoc-push `((push eldoc ,eldoc))
+ eldoc-pop `((pop eldoc))))
+ (if info
+ (setq info-push `((push info ,info))
+ info-pop `((pop info))))
+ (apply 'append
+ `(,info-push
+ ,eldoc-push
+ ,@compiled
+ ,eldoc-pop
+ ,info-pop)))))
+
+ ;; (either...): choose between patterns
+ ((either)
+ (cond
+ ((= (length pat) 2) ; trivial case
+ (gnuplot-compile-pattern (cadr pat)))
+
+ ((> (length pat) 3) ; could be more efficient...
+ (gnuplot-compile-pattern (gnuplot-either-helper pat)))
+
+ (t ; two patterns
+ (let* ((pat1 (cadr pat))
+ (pat2 (caddr pat))
+ (pat1-c (gnuplot-compile-pattern pat1))
+ (pat2-c (gnuplot-compile-pattern pat2))
+ (pat1-l (length pat1-c))
+ (pat2-l (length pat2-c)))
+ `((choice ,(+ pat1-l 2))
+ ,@pat1-c
+ (jump ,(+ pat2-l 1))
+ ,@pat2-c)))))
+
+ ;; Repetition (*)
+ ((many)
+ (let* ((pat1 (cons 'sequence (cdr pat)))
+ (pat1-c (gnuplot-compile-pattern pat1))
+ (pat1-l (length pat1-c)))
+ `((choice ,(+ pat1-l 2))
+ ,@pat1-c
+ (jump ,(- (+ pat1-l 1))))))
+
+ ;; Non-greedy-repetition (*?)
+ ((lazy-many)
+ (let* ((pat1 (cons 'sequence (cdr pat)))
+ (pat1-c (gnuplot-compile-pattern pat1))
+ (pat1-l (length pat1-c)))
+ `((choice 2)
+ (jump ,(+ pat1-l 2))
+ ,@pat1-c
+ (jump ,(- (+ pat1-l 2))))))
+
+ ;; Optional (?)
+ ((maybe)
+ (let* ((pat1 (cons 'sequence (cdr pat)))
+ (pat1-c (gnuplot-compile-pattern pat1))
+ (pat1-l (length pat1-c)))
+ `((choice ,(+ pat1-l 1))
+ ,@pat1-c)))
+
+ ;; Syntactic sugar for delimited lists
+ ((delimited-list)
+ (let* ((item (cadr pat))
+ (sep (caddr pat)))
+ (gnuplot-compile-pattern
+ `(sequence ,item (many (sequence ,sep ,item))))))
+
+ ;; keywords
+ ((kw)
+ (destructuring-bind (regex name)
+ (gnuplot-keyword-helper (cdr pat))
+ `((keyword ,regex ,name))))
+
+ ;; Capturing groups
+ ((capture)
+ (let* ((name (cadr pat))
+ (pat1 (cons 'sequence (cddr pat)))
+ (pat1-c (gnuplot-compile-pattern pat1)))
+ `((save-start ,name)
+ ,@pat1-c
+ (save-end ,name))))
+
+ ;; Use the first token as an info keyword
+ ((info-keyword)
+ (let* ((pat1 (cons 'sequence (cdr pat)))
+ (pat1-c (gnuplot-compile-pattern pat1)))
+ `((push info first-token)
+ ,@pat1-c
+ (pop info))))
+
+ ;; Assertions
+ ((assert)
+ (let* ((form (cadr pat)))
+ `((assert ,form))))
+
+ (t
+ (error "gnuplot-compile-pattern: bad pattern form %s" pat)))))))
+
+ ;; Helper function for destructuring (sequence ...) forms in patterns
+ ;; Takes the cdr of the sequence form, returns a list (PATTERNS ELDOC
+ ;; INFO).
+ (defun gnuplot-filter-arg-list (args)
+ (destructuring-bind
+ (&rest arg-list &key eldoc &key info &allow-other-keys) args
+ (let ((accum '()))
+ (while arg-list
+ (if (memq (car arg-list) '(:eldoc :info))
+ (pop arg-list)
+ (push (car arg-list) accum))
+ (pop arg-list))
+ (list (reverse accum) eldoc info))))
+
+ ;; Helper function for compiling (kw...) patterns
+ ;; Takes the cdr of the kw form, returns a list (REGEXP KEYWORD)
+ (defun gnuplot-keyword-helper (args)
+ (let ((keyword (car args)) (aliases (cdr args)))
+ (when (consp keyword)
+ (let ((pre (car keyword)) (suf (cdr keyword)))
+ (setq keyword (concat pre suf))
+ (while (progn
+ (push pre aliases)
+ (not (zerop (length suf))))
+ (setq pre (concat pre (substring suf 0 1))
+ suf (substring suf 1)))))
+ (let ((regex
+ (concat "^"
+ (regexp-opt (cons keyword aliases))
+ "$")))
+ (list regex keyword))))
+
+ ;; Helper function for compiling (either ...) patterns. Rewrites
+ ;; alternates (either A B C) into (either A (either B (either C D)))
+ (defun gnuplot-either-helper (pat)
+ (if (= (length pat) 3)
+ pat
+ `(either ,(cadr pat)
+ ,(gnuplot-either-helper
+ (cons 'either (cddr pat))))))
+
+ ;; Compile the grammar (a list of rule-pattern pairs (RULE PATTERN))
+ ;; into a single vector of matching-machine instructions. Compiles
+ ;; each pattern individually, then "links" them into one vector,
+ ;; converting symbolic (call ...) instructions into numeric offsets
+ (defun gnuplot-compile-grammar (grammar start-symbol)
+ (let ((compiled-pats '()) ; Alist of (name . instructions)
+ ;; Reserve space for a jump to the start symbol
+ (code-length 1))
+
+ ;; Compile each rule and find the total number of instructions
+ (dolist (item grammar)
+ (let* ((name (car item))
+ (pat (cadr item))
+ (code (gnuplot-compile-pattern pat)))
+ (push (cons name code) compiled-pats)
+ ;; Reserve space for a label at the beginning and (return) at
+ ;; the end
+ (setq code-length (+ code-length 2 (length code)))))
+
+ ;; Copy instructions into a single vector
+ (let ((object-code (make-vector code-length nil))
+ (name->offset (make-hash-table))
+ (i 1))
+ (setf (aref object-code 0) `(jump ,start-symbol))
+ (dolist (chunk compiled-pats)
+ (let ((name (car chunk))
+ (code (cdr chunk)))
+ (setf (aref object-code i) `(label ,name))
+ (incf i)
+ (puthash name i name->offset)
+ (while code
+ (setf (aref object-code i) (car code)
+ code (cdr code)
+ i (1+ i)))
+ (setf (aref object-code i) '(return)
+ i (1+ i))))
+
+ ;; Resolve symbolic jumps
+ (let ((pattern-name nil))
+ (dotimes (i (length object-code))
+ (let ((inst (aref object-code i)))
+ (case (car inst)
+ ((label)
+ (setq pattern-name (cadr inst)))
+
+ ((jump call)
+ (if (symbolp (cadr inst))
+ (let* ((name (cadr inst))
+ (location (gethash name name->offset)))
+ (if (not location)
+ (error
+ (concat "gnuplot-compile-grammar: "
+ "No rule found for symbol `%s' in pattern
`%s'")
+ name pattern-name))
+ (setcdr inst `(,location t ,name)))))))))
+ object-code))))
+
+;;; The grammar.
+(defvar gnuplot-compiled-grammar
+ (eval-when-compile
+ (let ((max-lisp-eval-depth 600))
+ (gnuplot-compile-grammar
+ '((expression
+ (sequence infix-expression
+ (maybe "?" expression ":" expression)))
+
+ (prefix-operator
+ (either "!" "~" "-" "+"))
+
+ (infix-operator
+ (either "**" "*" "/" "%" "+" "-" "." "<" "<=" ">" ">=" "==" "!=" "eq"
"ne"
+ "&" "^" "|" "&&" "||"))
+
+ (infix-expression
+ (sequence
+ (many prefix-operator)
+ primary-expression
+ (many infix-operator expression)))
+
+ (primary-expression
+ (sequence
+ (either number string parenthesized-expression
+ column-ref complex-number function-call name)
+ (many "!")
+ (maybe "**" infix-expression)
+ (maybe substring-range)))
+
+ (function-call
+ (either
+ (info-keyword
+ (sequence
+ (either "abs" "acos" "acosh" "arg" "asin" "asinh" "atan" "atan2"
"atanh"
+ "besj0" "besj1" "besy0" "besy1" "ceil" "column"
"columnhead"
+ "cos" "cosh" "defined" "erf" "erfc" "exists" "exp" "floor"
+ "gamma" "gprintf" "ibeta" "igamma" "imag" "int" "inverf"
+ "invnorm" "lambertw" "lgamma" "log" "log10" "norm" "real"
+ "sgn" "sin" "sinh" "sprintf" "sqrt" "strftime"
"stringcolumn"
+ "strlen" "strptime" "strstrt" "substr" "tan" "tanh"
"timecolumn"
+ "tm_hour" "tm_mday" "tm_min" "tm_mon" "tm_sec" "tm_wday"
+ "tm_yday" "tm_year" "valid" "value" "word" "words" "rand")
+ parenthesized-expression))
+ (sequence :info "elliptic_integrals"
+ (either "EllipticK" "EllipticE" "EllipticPi")
+ parenthesized-expression)))
+
+ (parenthesized-expression
+ (sequence "(" comma-list ")"))
+
+ (complex-number
+ (sequence
+ "{" number "," number "}"))
+
+ (column-ref
+ (sequence "$" number))
+
+ (substring-range-component
+ (maybe (either "*" expression)))
+
+ (substring-range
+ (sequence "[" (delimited-list substring-range-component ":" 2 2) "]"))
+
+;;; Assignments
+ (lhs
+ (sequence name
+ (maybe "(" (delimited-list name "," 1) ")")))
+
+ (assignment
+ (sequence lhs "=" (either lhs expression)))
+
+;;; Lists of expressions
+ (comma-list
+ (delimited-list expression ","))
+
+ (colon-list
+ (delimited-list expression ":"))
+
+ (tuple
+ (sequence "(" (delimited-list expression "," 2 3) ")"))
+
+;;; Commands
+ (command
+ (info-keyword
+ (either plot-command splot-command fit-command print-command
+ set-command cd-command call-command simple-command
+ eval-command load-command lower-raise-command pause-command
+ save-command system-command test-command undefine-command
+ update-command)))
+
+;;; PLOT, SPLOT commands
+ (plot-command
+ (sequence
+ (kw ("pl" . "ot"))
+
+ (either
+ ;; Parametric ranges
+ (sequence
+ (assert (gnuplot-guess-parametric-p))
+ (maybe t-axis-range) (maybe x-axis-range) (maybe y-axis-range))
+
+ ;; Non-parametric ranges
+ (sequence (maybe x-axis-range) (maybe y-axis-range)))
+
+ plot-body))
+
+ (splot-command
+ (sequence
+ ;; This capturing group lets `gnuplot-find-using-eldoc' know
+ ;; that this is an splot command
+ (capture :splot-command (kw ("spl" . "ot")))
+
+ (either
+ ;; Parametric ranges
+ (sequence
+ (assert (gnuplot-guess-parametric-p))
+ (maybe u-axis-range) (maybe v-axis-range)
+ (maybe x-axis-range) (maybe y-axis-range) (maybe z-axis-range))
+
+ ;; Non-parametric ranges
+ (sequence
+ (maybe x-axis-range) (maybe y-axis-range) (maybe z-axis-range)))
+
+ plot-body))
+
+ ;; Axis ranges
+ (axis-range-component
+ (maybe (either "*" expression)))
+
+ (axis-range-body
+ (delimited-list axis-range-component ":" 2 3))
+
+ (axis-range
+ (sequence
+ :info "ranges"
+ "[" (maybe (maybe name "=") axis-range-body) "]"))
+
+ (x-axis-range (sequence :eldoc "X RANGE: [{<dummy>=}<min>:<max>]"
axis-range))
+ (y-axis-range (sequence :eldoc "Y RANGE: [{<dummy>=}<min>:<max>]"
axis-range))
+ (z-axis-range (sequence :eldoc "Z RANGE: [{<dummy>=}<min>:<max>]"
axis-range))
+ (t-axis-range (sequence :eldoc "T RANGE: [{<dummy>=}<min>:<max>]"
axis-range))
+ (u-axis-range (sequence :eldoc "U RANGE: [{<dummy>=}<min>:<max>]"
axis-range))
+ (v-axis-range (sequence :eldoc "V RANGE: [{<dummy>=}<min>:<max>]"
axis-range))
+
+ ;; Body of a plot/splot command. Should really be different for
+ ;; parametric vs non-parametric, but that's too hard.
+ (plot-body
+ (delimited-list
+ (sequence (maybe iteration-spec) plot-expression plot-modifiers)
+ ","))
+
+ ;; Iteration: for [ ... ]
+ (iteration-spec
+ (sequence
+ ; :eldoc "for [<var> = <min> : <max>
{:<step>}]"
+ :info "iteration"
+ "for" "[" name "=" (delimited-list expression ":" 2 3) "]"))
+
+ ;; Expressions to plot can be preceded by any number of
+ ;; assignments, with or without commas
+ (plot-expression
+ (sequence
+ (lazy-many (sequence assignment (maybe ",")))
+ expression))
+
+;;; Plot/splot modifiers
+ ;; These should probably be more different for plot and splot ...
+ (plot-modifiers (many (either plot-modifier datafile-modifier)))
+
+ (plot-modifier
+ (info-keyword
+ (either
+ ;; simple one-word modifiers
+ (kw "nohidden3d") (kw "nocontours") (kw "nosurface")
+
+ ;; word followed by expression
+ (sequence
+ (either
+ (kw ("lines" . "tyle") "ls")
+ (kw ("linet" . "ype") "lt")
+ (kw ("linew" . "idth") "lw")
+ (kw ("pointt" . "ype") "pt")
+ (kw ("points" . "ize") "ps")
+ (kw ("pointi" . "nterval") "pi"))
+ expression)
+
+ ;; others defined below
+ title-modifier notitle-modifier axes-modifier with-modifier
+ linecolor-modifier fillstyle-modifier)))
+
+ (title-modifier
+ (sequence
+ (kw ("t" . "itle")) expression))
+
+ (notitle-modifier
+ (sequence
+ :info "title"
+ (kw ("not" . "itle"))
+ (maybe string)))
+
+ (axes-modifier
+ (sequence
+ (kw ("ax" . "es")) (either "x1y1" "x1y2" "x2y1" "x2y2")))
+
+ (linecolor-modifier
+ (sequence (kw "linecolor" "lc") color-spec))
+
+ (fillstyle-modifier
+ (sequence
+ (kw "fillstyle" "fs")
+ (either
+ "empty"
+ (sequence
+ "transparent"
+ (maybe (either "pattern" "solid") expression)
+ (maybe (either "noborder" (sequence "border" expression)))))))
+
+ (color-spec
+ (either
+ "variable"
+
+ (sequence
+ "palette"
+ (either "z" (sequence (either "frac" "cb") expression)))
+
+ (sequence
+ "rgbcolor"
+ (either "variable" string))))
+
+ (with-modifier
+ (sequence
+ :info "plotting_styles"
+ (kw ("w" . "ith"))
+
+ (capture
+ :with-style
+ (info-keyword
+ (either
+ ;; Simple styles that take no arguments
+ (kw ("l" . "ines")) (kw ("i" . "mpulses")) (kw ("p" . "oints"))
+ (kw ("linesp" . "oints") "lp") (kw ("d" . "ots")) (kw ("yerrorl"
. "ines"))
+ (kw ("errorl" . "ines")) (kw ("xerrorl" . "ines")) (kw
("xyerrorl" . "ines"))
+ (kw ("ye" . "rrorbars")) (kw ("e" . "rrorbars")) (kw ("xe" .
"rrorbars"))
+ (kw ("xye" . "rrorbars")) (kw "boxes") (kw ("hist" . "ograms"))
+ (kw ("boxer" . "rorbars")) (kw ("boxx" . "yerrorbars")) (kw ("st"
. "eps"))
+ (kw ("fs" . "teps")) (kw ("his" . "teps")) (kw ("fin" .
"ancebars"))
+ (kw ("can" . "dlesticks")) (kw ("pm" . "3d")) (kw "labels")
+ (kw ("cir" . "cles"))
+
+ ;; Image styles all use the same info page
+ (sequence
+ :info "image"
+ (either (kw ("ima" . "ge"))
+ (kw ("rgbima" . "ge"))
+ (kw ("rgba" . "lpha"))))
+
+ ;; More complicated styles defined below
+ filledcurves-style-clause
+ vectors-style-clause)))))
+
+ (filledcurves-style-clause
+ (sequence
+ (kw ("filledc" . "urves"))
+ (maybe
+ (either
+ "closed"
+
+ (sequence
+ (maybe (either "above" "below"))
+ (either "x1" "x2" "y1" "y2")
+ (maybe "=" expression))
+
+ (sequence "xy" "=" expression "," expression)))))
+
+ (vectors-style-clause
+ (sequence
+ (kw ("vec" . "tors"))
+ (many
+ (either
+ "nohead" "head" "heads" "filled" "empty" "nofilled" "front" "back"
+
+ (sequence
+ (either (kw "linestyle" "ls")
+ (kw "linetype" "lt")
+ (kw "linewidth" "lw"))
+ expression)
+
+ (sequence "size"
+ (delimited-list expression "," 2 3))))))
+
+;;; Datafile modifiers
+ (datafile-modifier
+ (info-keyword
+ (either binary-modifier
+ (sequence (maybe "nonuniform") (kw ("mat" . "rix")))
+ index-modifier every-modifier
+ thru-modifier using-modifier
+ smooth-modifier
+ "volatile" "noautoscale")))
+
+ (index-modifier
+ (sequence
+ (kw ("i" . "ndex"))
+ (either string (delimited-list expression ":" 0 2))))
+
+ (every-modifier
+ (sequence
+ (kw ("ev" . "ery")) (delimited-list expression ";" 0)))
+
+ (thru-modifier
+ (sequence
+ (kw "thru") expression))
+
+ (using-modifier
+ (sequence
+ :eldoc gnuplot-find-using-eldoc
+ (kw ("u" . "sing"))
+ (either
+ string
+ (sequence colon-list (maybe string)))))
+
+ (smooth-modifier
+ (sequence
+ (kw ("s" . "mooth"))
+ (either (kw ("a" . "csplines")) (kw ("b" . "ezier")) (kw ("c" .
"splines"))
+ (kw ("s" . "bezier")) (kw ("u" . "nique")) (kw ("f" .
"requency"))
+ (kw ("cum" . "ulative")) (kw ("k" . "density")))))
+
+;;; Binary datafile modifiers
+ (binary-modifier
+ (sequence
+ "binary" (many binary-keyword)))
+
+ (binary-keyword
+ (either
+ ;; All of these binary keywords are described on the same
+ ;; info page
+ (sequence
+ :info "keywords"
+ (either
+ "transpose" "flipx" "flipy" "flipz"
+ (sequence "flip" "=" (either "x" "y" "z"))
+ (sequence "scan" "=" name)
+ (sequence (either "dx" "dy" "dz") "=" number)
+ (sequence
+ (either "origin" "center" "perpendicular") "="
+ (delimited-list tuple ":"))
+ (sequence
+ (kw ("rot" . "ate") "rotation") "="
+ (sequence expression (maybe (kw ("d" . "eg")) (kw ("p" .
"i")))))))
+
+ ;; remaining binary keywords have their own info pages
+ (info-keyword
+ (sequence
+ (either "array" "record")
+ "="
+ (either
+ (delimited-list tuple ":")
+ (delimited-list expression ":")))
+
+ (sequence
+ (either "skip")
+ "="
+ (delimited-list expression ":"))
+
+ (sequence
+ (either "format" "endian" "filetype")
+ "="
+ expression))))
+
+;;; "fit" command
+ (fit-command
+ (sequence
+ :info "fit"
+ (kw "fit")
+ (many axis-range)
+ expression
+ string
+ (many plot-modifier)
+ (kw "via")
+ (either string (delimited-list name ","))))
+
+;;; print command
+ (print-command
+ (sequence "print" (delimited-list expression ",")))
+
+;;; set commands
+ (set-command
+ (sequence
+ :eldoc "set ..."
+ :info "set-show"
+ (either (kw "set") (kw "unset") (kw "show"))
+ (info-keyword
+ (either set-angles-clause set-arrow-clause
+ set-autoscale-clause set-bars-clause
+ set-border-clause set-boxwidth-clause
+ set-clabel-clause set-clip-clause
+ set-cntrparam-clause set-colorbox-clause
+ set-contour-clause set-datafile-clause
+ set-decimalsign-clause set-dgrid3d-clause
+ set-dummy-clause set-encoding-clause
+ set-fit-clause set-fontpath-clause
+ set-format-clause set-grid-clause
+ set-hidden3d-clause set-historysize-clause
+ set-isosamples-clause set-key-clause
+ set-label-clause set-loadpath-clause
+ set-locale-clause set-logscale-clause
+ set-mapping-clause set-margin-clause
+ set-multiplot-clause set-mxtics-clause
+ set-object-clause set-offsets-clause
+ set-origin-clause set-output-clause
+ set-parametric-clause set-pm3d-clause
+ set-palette-clause set-pointsize-clause
+ set-polar-clause set-print-clause
+ set-samples-clause set-size-clause
+ set-surface-clause set-table-clause
+ set-terminal-clause set-termoption-clause
+ set-tics-clause set-tics-clause-2
+ set-timestamp-clause set-timefmt-clause
+ set-title-clause set-view-clause
+ set-data-clause set-dtics-clause
+ set-mtics-clause set-range-clause
+ set-xyplane-clause set-zero-clause
+ set-zeroaxis-clause))))
+
+;;; positions and coordinate systems for set options
+ (position-system
+ (either "first" "second" "graph" "screen" "character"))
+
+ (dimension (sequence (maybe position-system) number))
+
+ (position
+ (sequence dimension "," dimension (maybe "," dimension)))
+
+ (to (either "to" "rto"))
+
+;;; all the different "set ... " options
+ (set-angles-clause
+ (sequence
+ "angles" (either "degrees" "radians")))
+
+ (set-arrow-clause
+ (sequence
+ "arrow" (maybe number)
+ (maybe "from" position)
+ (maybe to position)
+ (maybe
+ (either
+ (sequence (kw "arrowstyle" "as") number)
+ (sequence
+ (maybe (either "nohead" "head" "backhead" "heads"))
+ (maybe "size" dimension "," number
+ (maybe "," number))
+ (maybe (either "filled" "empty" "nofilled"))
+ (maybe (either "front" "back"))
+ (maybe linestyle-spec))))))
+
+ (set-autoscale-clause
+ (sequence
+ "autoscale"
+ (either "fix"
+ "keepfix"
+ "x" "y" "z" "cb" "x2" "y2" "xy"
+ "xmin" "ymin" "zmin" "cbmin" "x2min" "y2min"
+ "xmax" "ymax" "zmax" "cbmax" "x2max" "y2max"
+ "xfix" "yfix" "zfix" "cbfix" "x2fix" "y2fix"
+ "xfixmax" "yfixmax" "zfixmax" "cbfixmax" "x2fixmax"
"y2fixmax"
+ "xfixmin" "yfixmin" "zfixmin" "cbfixmin" "x2fixmin"
"y2fixmin")))
+
+ (set-bars-clause
+ (sequence
+ "bars"
+ (either number "small" "large" "fullwidth")
+ (either "front" "back")))
+
+ (set-border-clause
+ (sequence
+ "border"
+ (maybe number)
+ (maybe (either "front" "back"))
+ (maybe (kw "linewidth" "lw") expression)
+ (maybe
+ (either (kw "linestyle" "ls") (kw "linetype" "lt"))
+ expression)))
+
+ (set-boxwidth-clause
+ (sequence
+ "boxwidth" (maybe expression) (maybe (either "absolute"
"relative"))))
+
+ (set-clabel-clause
+ (sequence
+ "clabel" (maybe string)))
+
+ (set-clip-clause
+ (sequence
+ "clip" (maybe (either "points" "one" "two"))))
+
+ (set-cntrparam-clause
+ (sequence
+ (kw "cntrparam")
+ (either
+ "linear" "cubicspline" "bspline"
+
+ (sequence (either "points" "order") number)
+
+ (sequence
+ (kw "levels")
+ (either
+ number
+ (sequence (kw "auto") (maybe number))
+ (sequence
+ (kw "discrete") comma-list)
+ (sequence
+ (kw "incremental") (delimited-list expression "," 2 3)))))))
+
+ (set-colorbox-clause
+ (sequence
+ :info "color_box"
+ "colorbox"
+ (many
+ (either
+ "vertical" "horizontal"
+ "default" "user"
+ (sequence "origin" expression "," expression)
+ (sequence "size" expression "," expression)
+ "front" "back"
+ "noborder" "bdefault"
+ (sequence "border" expression)))))
+
+ (set-contour-clause
+ (sequence
+ "contour" (either "base" "surface" "both")))
+
+ (set-datafile-clause
+ (sequence
+ "datafile"
+ (either (sequence :info "set_datafile_fortran"
+ "fortran")
+ (sequence :info "set_datafile_nofpe_trap"
+ "nofpe_trap")
+ (sequence :info "set_datafile_missing"
+ "missing" (maybe string))
+ (sequence :info "set_datafile_separator"
+ "separator" (either "whitespace" string))
+ (sequence :info "set_datafile_commentschars"
+ "commentschars" (maybe string))
+ (sequence :info "set_datafile_binary"
+ "binary" (many binary-keyword)))))
+
+ (set-decimalsign-clause
+ (sequence
+ "decimalsign"
+ (either string (sequence "locale" (maybe string)))))
+
+ (set-dgrid3d-clause
+ (sequence
+ "dgrid3d"
+ (maybe expression) ; fixme
+ (maybe "," expression)
+ (either
+ "splines"
+ (sequence "qnorm" expression)
+ (sequence (either "gauss" "cauchy" "exp" "box" "hann")
+ (maybe expression)
+ (maybe "," expression)))))
+
+ (set-dummy-clause
+ (sequence
+ "dummy"
+ name (maybe "," name)))
+
+ (set-encoding-clause
+ (sequence
+ "encoding"
+ (either "default" "iso_8859_1" "iso_8859_15" "iso_8859_2"
"iso_8859_9"
+ "koi8r" "koi8u" "cp437" "cp850" "cp852" "cp1250" "cp1251"
"cp1254"
+ "utf8" "locale")))
+
+ (set-fit-clause
+ (sequence
+ :info "fit_"
+ "fit"
+ (either
+ (sequence "logfile" string)
+ "errorvariables" "noerrorvariables")))
+
+ (set-fontpath-clause
+ (sequence
+ "fontpath" (many string)))
+
+ (set-format-clause
+ (sequence
+ :info "format_"
+ "format"
+ (maybe (either "x" "y" "xy" "x2" "y2" "z" "cb"))
+ string))
+
+ (set-grid-clause
+ (sequence
+ "grid"
+ (either "nomxtics" "mxtics" "noxtics" "xtics" "nomytics" "mytics"
+ "noytics" "ytics" "nomztics" "mztics" "noztics" "ztics"
+ "nomx2tics" "mx2tics" "nox2tics" "x2tics" "nomy2tics"
+ "my2tics" "noy2tics" "y2tics" "nomcbtics" "mcbtics"
+ "nocbtics" "cbtics" "layerdefault" "front" "back"
+ (sequence linestyle-spec (maybe "," linestyle-spec)))))
+
+ (linestyle-spec
+ (either
+ (sequence (kw ("lines" . "tyle") "ls") expression)
+ (sequence (maybe (kw ("linet" . "ype") "lt") expression)
+ (maybe (kw ("linew" . "idth") "lw") expression))))
+
+ (set-hidden3d-clause
+ (sequence
+ "hidden3d"
+ (either
+ "defaults" "front" "back"
+ (sequence "offset" expression) "nooffset"
+ (sequence "trianglepattern"
+ (either "0" "1" "2" "3" "4" "5" "6" "7"))
+ (sequence "undefined" (either "1" "2" "3"))
+ (sequence "noundefined")
+ "altdiagonal" "noaltdiagonal"
+ "bentover" "nobentover")))
+
+ (set-historysize-clause
+ (sequence
+ "historysize" number))
+
+ (set-isosamples-clause
+ (sequence
+ "isosamples" number (maybe "," number)))
+
+ (set-key-clause
+ (sequence
+ "key"
+ (maybe (either "on" "off"))
+ (maybe "default")
+ (maybe
+ (either
+ "inside" "outside"
+ "lmargin" "rmargin" "tmargin" "bmargin"
+ (sequence "at" expression "," expression)))
+ (maybe
+ (either
+ "left" "right" "center"))
+ (maybe
+ (either
+ "top" "bottom" "center"))
+ (maybe (either "vertical" "horizontal"))
+ (maybe (either "Left" "Right"))
+ (maybe (either "reverse" "noreverse" "invert" "noinvert"))
+ (maybe "samplen" number)
+ (maybe "spacing" number)
+ (maybe "width" number)
+ (maybe "width" number)
+ (maybe (either "autotitle" "noautotitle") (maybe "columnheader"))
+ (maybe "title" expression)
+ (maybe (either "enhanced" "noenhanced"))
+ (maybe "font" string)
+ (maybe "textcolor" color-spec)
+ (maybe (either "box" "nobox")
+ linestyle-spec)
+ (maybe "maxcols" (either number "auto"))
+ (maybe "maxrows" (either number "auto"))))
+
+ (set-label-clause
+ (sequence
+ "label"
+ (maybe number)
+ (maybe string)
+ (maybe "at" expression "," expression)
+ (maybe (either "left" "center" "right"))
+ (maybe (either "norotate" (sequence "rotate" "by" expression)))
+ (maybe "font" string)
+ (maybe "noenhanced")
+ (maybe (either "front" "back"))
+ (maybe "textcolor" color-spec)
+; (maybe (either "nopoint" (sequence "point" point-style)))
+ (maybe "offset" position "," position)))
+
+ (set-loadpath-clause
+ (sequence
+ "loadpath" (many string)))
+
+ (set-locale-clause
+ (sequence
+ "locale" (maybe string)))
+
+ (set-logscale-clause
+ (sequence
+ "logscale"
+ (either "x" "y" "xy" "x2" "y2" "z" "cb" name)))
+
+ (set-mapping-clause
+ (sequence
+ "mapping" (either "cartesian" "spherical" "cylindrical")))
+
+ (set-margin-clause
+ (sequence
+ (either "bmargin" "lmargin" "rmargin" "tmargin")
+ (maybe "at" "screen") expression))
+
+ ;; TODO: set-mouse-clause
+
+ (set-multiplot-clause
+ (sequence
+ "multiplot"
+ (maybe
+ (sequence
+ "layout" number "," number
+ (maybe (either "rowsfirst" "columnsfirst"))
+ (maybe (either "downwards" "upwards"))
+ (maybe "title" string)
+ (maybe "scale" number (maybe "," number))
+ (maybe "offset" number (maybe "," number))))))
+
+ (set-mxtics-clause
+ (sequence
+ :info "mxtics"
+ (either "mxtics" "mytics" "mztics" "mx2tics" "my2tics" "mcbtics")
+ (either "default" number)))
+
+ ;; "set object", objects, dimensions, positions
+ (set-object-clause
+ (sequence
+ "object"
+ (info-keyword
+ (either rectangle-object ellipse-object circle-object
polygon-object))
+ (maybe (either "front" "back" "behind"))
+ (maybe (kw "fillcolor" "fc") color-spec)
+ (maybe "fs" expression)
+ (maybe "default")
+ (maybe (kw "linewidth" "lw") expression)))
+
+ (rectangle-object
+ (sequence
+ "rectangle"
+ (either
+ (sequence "from" position (either "to" "rto") position)
+ (sequence "center" position "size" dimension "," dimension)
+ (sequence "at" position "size" dimension "," dimension))))
+
+ (ellipse-object
+ (sequence
+ "ellipse"
+ (either "at" "center") position
+ "size" dimension "," dimension
+ (maybe "angle" number)))
+
+ (circle-object
+ (sequence
+ "circle"
+ (either "at" "center") position
+ "size" dimension
+ (maybe "arc" "[" number ":" number "]")))
+
+ (polygon-object
+ (sequence
+ "polygon"
+ "from" position (many (either "to" "rto") position)))
+
+ ;; "set offsets"
+ (set-offsets-clause
+ (sequence
+ "offsets"
+ (delimited-list (sequence (maybe "graph") expression) "," 4 4)))
+
+ (set-origin-clause
+ (sequence
+ "origin" expression "," expression))
+
+ (set-output-clause
+ (sequence
+ "output" (maybe string)))
+
+ (set-parametric-clause
+ (sequence
+ "parametric"))
+
+ (set-pm3d-clause
+ (sequence
+ "pm3d"
+ (many
+ (either
+ (sequence "at" name)
+ (sequence "interpolate" number "," number)
+ (either "scansautomatic" "scansforward" "scansbackward"
"depthorder")
+ (sequence "flush" (either "begin" "center" "end"))
+ (either "ftriangles" "noftriangles")
+ (either "clip1in" "clip4in")
+ (sequence "corners2color"
+ (either "mean" "geomean" "median" "min" "max" "c1" "c2"
"c3" "c4"))
+ (sequence "hidden3d" number)
+ "nohidden3d"
+ "implicit" "explicit" "map"))))
+
+ (set-palette-clause
+ (sequence
+ "palette"
+ (many
+ (either
+ "gray" "color"
+ (sequence "gamma" number)
+ (sequence "rgbformulae" number "," number "," number)
+ "defined" ; not complete
+ (sequence "functions" expression "," expression "," expression)
+ (sequence "file" string (many datafile-modifier))
+ (sequence (either "RGB" "HSV" "CMY" "YIQ" "XYZ"))
+ "positive" "negative"
+ "nops_allcF" "ps_allcF"
+ (sequence "maxcolors" number)))))
+
+ (set-pointsize-clause
+ (sequence
+ "pointsize" number))
+
+ (set-polar-clause "polar")
+
+ (set-print-clause
+ (sequence
+ "print"
+ (maybe string)))
+
+ (set-samples-clause
+ (sequence
+ "samples" expression (maybe "," expression)))
+
+ (set-size-clause
+ (sequence
+ "size"
+ (either
+ "square" "nosquare"
+ (sequence "ratio" expression)
+ "noratio"
+ (sequence expression "," expression))))
+
+ ;; TODO: set style *
+
+ (set-surface-clause "surface")
+
+ (set-table-clause (sequence "table" (maybe string)))
+
+ (set-terminal-clause ; not sure how to do this...
+ (sequence "terminal" (maybe (either "push" "pop"))))
+
+ (set-termoption-clause
+ (sequence
+ "termoption"
+ (either
+ "enhanced" "noenhanced"
+ (sequence "font" string)
+ "solid" "dashed"
+ (sequence (kw "linewidth" "lw") expression))))
+
+ (set-tics-clause
+ (sequence
+ (either "tics" "xtics" "ytics" "ztics" "x2tics" "y2tics" "cbtics")
+ (many
+ (either
+ "axis" "border" "mirror" "nomirror" "in" "out"
+ (sequence "scale" (either "default" expression "," expression))
+ (sequence "rotate" "by" expression) "norotate"
+ (sequence "offset" expression) "nooffset"
+ (sequence "format" string)
+ (sequence "font" string)
+ (sequence "textcolor" color-spec)))))
+
+ (set-tics-clause-2
+ (sequence
+ "tics" (either "front" "back")))
+
+ (set-timestamp-clause
+ (sequence
+ "timestamp"
+ (maybe string)
+ (maybe (either "top" "bottom"))
+ (maybe (either "rotate" "norotate"))
+ (maybe "offset" position "," position)
+ (maybe "font" string)))
+
+ (set-timefmt-clause
+ (sequence
+ "timefmt" string))
+
+ (set-title-clause
+ (sequence
+ "title"
+ (maybe string)
+ (maybe "offset" position)
+ (maybe "font" string)
+ (maybe (kw "textcolor" "tc")
+ (either "default" color-spec))
+ (maybe (either "enhanced" "noenhanced"))))
+
+ (set-view-clause
+ (sequence
+ "view"
+ (either
+ "map"
+ (sequence (either "equal" "noequal") (maybe (either "xy" "xyz")))
+ (delimited-list expression ","))))
+
+ (set-data-clause
+ (sequence
+ :info "xdata"
+ (either "xdata" "ydata" "zdata" "x2data" "y2data" "cbdata")
+ (maybe "time")))
+
+ (set-dtics-clause
+ (sequence
+ :info "xdtics"
+ (either "xdtics" "ydtics" "zdtics" "x2dtics" "y2dtics" "cbdtics")))
+
+ ;; TODO set xlabel etc.
+
+ (set-mtics-clause
+ (sequence
+ :info "xmtics"
+ (either "xmtics" "ymtics" "zmtics" "x2mtics" "y2mtics" "cbmtics")))
+
+ (set-range-clause
+ (sequence
+ :info "xrange"
+ (either "xrange" "yrange" "zrange" "trange" "urange" "vrange"
+ "rrange")
+ (either
+ "restore"
+ (sequence
+ "[" (maybe
+ (sequence
+ (maybe axis-range-component) ":"
+ (maybe axis-range-component)))
+ "]"
+ (maybe (either "reverse" "noreverse" "writeback"
"nowriteback"))))))
+
+ ;; TODO set xtics etc.
+
+ (set-xyplane-clause
+ (sequence
+ "xyplane" (either "at" "relative") expression))
+
+ (set-zero-clause
+ (sequence
+ "zero" expression))
+
+ (set-zeroaxis-clause
+ (sequence
+ :info "zeroaxis"
+ (either "xzeroaxis" "x2zeroaxis" "yzeroaxis" "y2zeroaxis"
"zzeroaxis")
+ linestyle-spec))
+
+
+ ;;; Other commands
+ (cd-command
+ (sequence "cd" string))
+
+ (call-command
+ (sequence "call" string (many expression)))
+
+ (simple-command
+ (either "clear" "exit" "quit" "pwd" "refresh" "replot" "reread" "reset"
+ "shell"))
+
+ (eval-command
+ (sequence "eval" expression))
+
+ (load-command
+ (sequence "load" string))
+
+ (lower-raise-command (sequence (either "lower" "raise") number))
+
+ (pause-command
+ (sequence
+ "pause"
+ (either
+ number
+ (sequence "mouse" (maybe endcondition (maybe "," endcondition))))
+ string))
+
+ (endcondition (either "keypress" "button1" "button2" "button3" "close"
"any"))
+
+ (save-command
+ (sequence
+ "save"
+ (either "functions" "variables" "terminal" "set")
+ string))
+
+ (system-command
+ (sequence "system" string))
+
+ (test-command
+ (sequence
+ "test"
+ (either
+ "terminal"
+ (sequence
+ "palette"
+ (maybe
+ (either "rgb" "rbg" "grb" "gbr" "brg" "bgr"))))))
+
+ (undefine-command
+ (sequence "undefine" (many name)))
+
+ (update-command
+ (sequence "update" string (maybe string))))
+
+ ;; This is the start symbol
+ 'command))))
+
+
+;; The following macros are used for debugging; load
+;; gnuplot-debug-context.el and then re-load this file to enable
+;; them. For normal use, they compile to no-ops.
+(eval-when-compile
+ (when (not (featurep 'gnuplot-debug-context))
+ (defmacro with-gnuplot-trace-buffer (&rest args) "No-op." '(progn nil))
+ (defmacro gnuplot-trace (&rest args) "No-op." '(progn nil))
+ (defmacro gnuplot-debug (&rest args) "No-op." '(progn nil))))
+
+
+
+;;;; Variables to be set via pattern matching
+(defvar gnuplot-completions nil
+ "List of possible gnuplot-mode completions at point.
+This is filled in by `gnuplot-match-pattern' when it reaches the
+token before point.")
+
+(defvar gnuplot-info-at-point nil
+ "Relevant page of the Gnuplot info manual for the construction at point.
+
+Set by `gnuplot-match-pattern' using information from
+`gnuplot-compiled-grammar'. `gnuplot-match-pattern' pushes ElDoc
+and info strings onto the stack as it runs, and scans the stack
+for the topmost entry when it reaches the token at point.")
+
+(defvar gnuplot-eldoc nil
+ "ElDoc documentation string for the Gnuplot construction at point.
+
+Set by `gnuplot-match-pattern'. See also `gnuplot-info-at-point'.")
+
+(defvar gnuplot-captures nil
+ "Alist of named capture groups for gnuplot-mode completion code.
+
+Each entry is of the form (NAME BEGIN END), where NAME is the
+name specified in the (capture NAME PATTERN) form in the
+`gnuplop-compiled-grammar' source, BEGIN is the tail of the token
+list beginning the capture group, and END is the tail of the
+token list just after the end of the capture group.")
+
+
+;;;; The pattern matching machine
+(defun gnuplot-match-pattern (inst tokens completing-p
+ &optional start-symbol)
+ "Parse TOKENS, setting completions, info and ElDoc information.
+
+This function parses TOKENS by simulating a stack machine with
+unlimited backtracking. If COMPLETING-P is non-nil, it stops
+before the token at point and collects a list of the next tokens
+that it would accept in `gnuplot-completions'. If COMPLETING-P is
+nil, it parses up to the token at point and sets `gnuplot-eldoc'
+and `gnuplot-info-at-point' based on the contents of the stack
+there."
+ (catch 'return
+ (let ((pc 0) ; Program counter
+ ;; Stack of return addresses (return PC), eldoc strings
+ ;; (eldoc STRING) and info pages (info STRING)
+ (stack '())
+ ;; Stack of backtracking records, (STACK TOKENS RESUME-PC CAPTURES)
+ (backtrack '())
+ ;; Match failure flag, set to `t' to cause backtracking
+ (fail nil)
+ ;; Flag set by JUMP and CALL instructions to stop PC advance
+ (jump nil))
+
+ (with-gnuplot-trace-buffer (erase-buffer))
+
+ (when start-symbol ; HACK FIXME
+ (while (not (equal (aref inst pc)
+ '(label start-symbol)))
+ (incf pc))
+ (incf pc))
+
+ (setq gnuplot-completions nil
+ gnuplot-eldoc nil
+ gnuplot-info-at-point nil
+ gnuplot-captures nil)
+
+ (flet ((advance
+ ()
+ (if (eq (pop tokens) gnuplot-token-at-point)
+ (gnuplot-scan-stack stack tokens)))
+ (fail () (setq fail t)))
+
+ ;; Main loop
+ (while t
+ (let* ((inst (aref inst pc))
+ (opcode (car inst))
+ (token (car tokens))
+ (end-of-tokens
+ (or (gnuplot-end-of-tokens-p tokens)
+ (and completing-p
+ ;; (<= (point) (gnuplot-token-end token))
+ (eq token gnuplot-token-at-point)))))
+ (gnuplot-trace "%s\t%s\t%s\n" pc inst (gnuplot-token-id token))
+
+ (case opcode
+ ;; (literal LITERAL NO-COMPLETE)
+ ((literal)
+ (let ((expect (cadr inst))
+ (no-complete (caddr inst)))
+ (cond (end-of-tokens
+ (unless no-complete
+ (gnuplot-trace "\tpushing \"%s\" to completions\n"
expect)
+ (push expect gnuplot-completions))
+ (fail))
+
+ ((not (equal (gnuplot-token-id token) expect))
+ (fail))
+
+ ;; otherwise succeed
+ (t (advance)))))
+
+ ;; (token-type TYPE)
+ ((token-type)
+ (let ((expect (cadr inst)))
+ (if (or end-of-tokens
+ (not (eq (gnuplot-token-type token) expect)))
+ (fail)
+ (advance))))
+
+ ;; (keyword REGEXP NAME): match any token whose ID
+ ;; regexp-matches REGEXP, use NAME for completions
+ ((keyword)
+ (let ((regexp (cadr inst))
+ (name (caddr inst)))
+ (cond (end-of-tokens
+ (gnuplot-trace "\tpushing \"%s\" to completions\n" name)
+ (push name gnuplot-completions)
+ (fail))
+
+ ((not (string-match-p regexp (gnuplot-token-id token)))
+ (fail))
+
+ ;; otherwise succeed
+ (t (advance)))))
+
+ ;; (any): match any token
+ ((any)
+ (if end-of-tokens
+ (fail)
+ (advance)))
+
+ ;; (jump OFFSET FIXED): jump to instruction at PC + OFFSET,
+ ;; or directly to OFFSET if FIXED is non-nil
+ ((jump)
+ (let ((offset (cadr inst))
+ (fixed (caddr inst)))
+ (setq pc (if fixed offset (+ pc offset))
+ jump t)))
+
+ ;; (call OFFSET FIXED): push the next instruction as a
+ ;; return location and jump like (jump), above
+ ((call)
+ (let ((offset (cadr inst))
+ (fixed (caddr inst)))
+ (push `(return ,(+ pc 1)) stack)
+ (setq pc (if fixed offset (+ pc offset))
+ jump t)))
+
+ ;; (return): return to address at topmost RETURN record on
+ ;; stack, or stop matching and return if stack is empty
+ ((return)
+ (while (and stack
+ (not (eq (caar stack) 'return)))
+ (pop stack))
+ (if (not stack) ; end of pattern
+ (throw 'return tokens)
+ (let* ((r (pop stack))
+ (r-pc (cadr r)))
+ (setq pc r-pc
+ jump t))))
+
+ ;; (choice OFFSET): push PC + OFFSET onto the stack of
+ ;; backtracking points and continue at next instruction
+ ((choice)
+ (let ((offset (cadr inst)))
+ (push `(,stack ,tokens ,(+ pc offset) ,gnuplot-captures)
+ backtrack)))
+
+ ;; (commit OFFSET): discard most recent backtrack point
+ ;; and jump to PC + OFFSET
+ ((commit)
+ (let ((offset (cadr inst)))
+ (if (not backtrack)
+ (error "no more backtrack points in commit"))
+ (pop backtrack)
+ (setq pc (+ pc offset)
+ jump t)))
+
+ ;; (fail): force this match to fail, going back to most
+ ;; recent backtrack point
+ ((fail)
+ (fail))
+
+ ;; (assert): run Lisp code and fail if it returns NIL
+ ((assert)
+ (let ((form (cadr inst)))
+ (if (not (eval form)) (fail))))
+
+ ;; (push TYPE VALUE): push an info page or eldoc string
+ ;; onto the stack
+ ((push)
+ (let* ((type (cadr inst))
+ (value (caddr inst)))
+ (push `(,type ,value ,tokens) stack)))
+
+ ;; (pop TYPE): pop something off the stack
+ ((pop)
+ (let ((type (cadr inst)))
+ (if (not (and stack
+ (eq (caar stack) type)))
+ (error "Expected a %s on the stack but found %s" type
stack))
+ (pop stack)))
+
+ ;; (save-start NAME): save current token pointer as
+ ;; beginning of capture group NAME
+ ((save-start)
+ (let ((name (cadr inst)))
+ (push `(,name ,tokens nil) gnuplot-captures)))
+
+ ;; (save-end NAME): save current token pointer as end of
+ ;; capture group NAME
+ ((save-end)
+ (let* ((name (cadr inst))
+ (record (assoc name gnuplot-captures)))
+ (if (not record)
+ (error "gnuplot-match-tokens: no open capture group named
%s" name)
+ (setf (caddr record) tokens)
+ (gnuplot-debug (gnuplot-dump-captures)))))
+
+ (t
+ (error "bad instruction: %s" inst)))
+
+ ;; Increment PC unless a jump occurred
+ (if jump
+ (setq jump nil)
+ (incf pc))
+
+ ;; Backtrack on failure
+ (when fail
+ (if (not backtrack) ; Out of backtracking stack
+ (throw 'return nil)
+ (gnuplot-trace "\t*fail*\t%s\n" (length backtrack))
+ ;; If we got as far as token-at-point before failing,
+ ;; scan the stack for eldoc and info strings
+ (when end-of-tokens
+ (gnuplot-scan-stack stack tokens))
+
+ (destructuring-bind
+ (bt-stack bt-tokens bt-pc bt-captures)
+ (pop backtrack)
+ (setq stack bt-stack
+ tokens bt-tokens
+ pc bt-pc
+ gnuplot-captures bt-captures
+ fail nil))))))))))
+
+(defun gnuplot-scan-stack (stack tokens)
+ "Scan STACK for the most recently pushed eldoc and info strings"
+ (gnuplot-trace "\t* scanning stack *\n")
+ (gnuplot-debug (gnuplot-backtrace))
+ (gnuplot-debug (gnuplot-dump-captures))
+
+ (while (and stack
+ (not (and gnuplot-info-at-point gnuplot-eldoc)))
+ (let* ((item (car stack))
+ (type (car item))
+ (position (caddr item))) ; must progress by at least one token
+ (if (and (memq type '(info eldoc))
+ (not (eq position tokens)))
+ (case type
+ ((info)
+ (when (not gnuplot-info-at-point)
+ (let ((info (cadr item)))
+ (setq gnuplot-info-at-point
+ (cond
+ ((eq info 'first-token)
+ (gnuplot-token-id (car position)))
+ ((functionp info) (funcall info))
+ (t info)))
+ (when gnuplot-info-at-point
+ (gnuplot-trace "\tset info to \"%s\"\n"
gnuplot-info-at-point)
+ (when (not gnuplot-eldoc)
+ (let ((eldoc
+ (car (gethash gnuplot-info-at-point
gnuplot-eldoc-hash))))
+ (when eldoc
+ (setq gnuplot-eldoc eldoc)
+ (gnuplot-trace "\tand set eldoc to \"%s\"\n"
eldoc))))))))
+
+ ((eldoc)
+ (when (not gnuplot-eldoc)
+ (let ((eldoc (cadr item)))
+ (setq gnuplot-eldoc
+ (if (functionp eldoc) (funcall eldoc) eldoc))
+ (gnuplot-trace "\tset eldoc to \"%s\"\n" gnuplot-eldoc)))))))
+ (pop stack)))
+
+(defun gnuplot-capture-group (name)
+ "Return capture group NAME from the most recent parse, as a list of tokens."
+ (let ((record (assoc name gnuplot-captures)))
+ (if (not record) nil
+ (let ((begin (cadr record))
+ (end (caddr record))
+ (accum '()))
+ (while (and begin (not (eq begin end)))
+ (push (pop begin) accum))
+ (nreverse accum)))))
+
+(defun gnuplot-capture-group->string (name)
+ (let ((tokens (gnuplot-capture-group name)))
+ (and tokens
+ (mapconcat 'gnuplot-token-id tokens " "))))
+
+
+;;;; Interface to the matching machine
+(defun gnuplot-parse-at-point (completing-p)
+ (let ((tokens (gnuplot-tokenize)))
+ (gnuplot-match-pattern gnuplot-compiled-grammar tokens completing-p)))
+
+(defun gnuplot-completions ()
+ (gnuplot-parse-at-point t)
+ gnuplot-completions)
+
+(defun gnuplot-completion-at-point ()
+ "Return completions of keyword preceding point."
+ (let* ((end (point))
+ (beg (max
+ (save-excursion (skip-syntax-backward "w_") (point))
+ (gnuplot-point-at-beginning-of-command)))
+ (word nil)
+ (completions (gnuplot-completions)))
+ (unless (= beg end)
+ (setq word (buffer-substring beg end)
+ completions (all-completions word completions)))
+
+ (when (= (length completions) 1)
+ (setq completions (list (concat (car completions) " ")))
+ (gnuplot-completions))
+
+ (if completions
+ (list beg end completions)
+ (message "No gnuplot keywords complete '%s'" word)
+ nil)))
+
+(defun gnuplot-eldoc-function ()
+ "Return the ElDoc string for the Gnuplot construction at point."
+ (gnuplot-parse-at-point nil)
+ gnuplot-eldoc)
+
+(defun gnuplot-help-function ()
+ "Pop up the extended documentation for the construction at point."
+ (interactive)
+ (gnuplot-parse-at-point nil)
+ (if gnuplot-info-at-point
+ (let ((eldoc
+ (cadr (gethash gnuplot-info-at-point gnuplot-eldoc-hash))))
+ (if eldoc (message eldoc)))))
+
+(define-key gnuplot-mode-map (kbd "C-c h") 'gnuplot-help-function)
+
+(defun gnuplot-info-at-point ()
+ "Open the relevant gnuplot info page for the construction at point."
+ (interactive)
+ (gnuplot-parse-at-point nil)
+ (and gnuplot-info-at-point
+ (info-other-window (format "(gnuplot)%s" gnuplot-info-at-point))))
+
+(define-key gnuplot-mode-map (kbd "C-c C-/") 'gnuplot-info-at-point)
+
+(add-hook
+ 'gnuplot-mode-hook
+ (lambda ()
+ (set (make-local-variable 'eldoc-documentation-function)
+ 'gnuplot-eldoc-function)))
+
+
+;;; Some context-sensitive hacks
+
+;; ElDoc strings for "using" specs, which depend on other information
+;; from the parsed command
+
+(defvar gnuplot-using-eldoc
+ '(("boxerrorbars" . "x:y:ydelta{:xdelta} | x:y:ylow:yhigh{:xdelta}")
+ ("boxes" . "x:y{:x_width}")
+ ("boxxyerrorbars" . "x:y:xdelta:ydelta | x:y:xlow:xhigh:ylow:yhigh")
+ ("candlesticks" . "x:box_min:whisker_min:whisker_high:box_high |
date:open:low:high:close")
+ ("circles" . "x:y:radius")
+ ("dots" . "x{:y{:z}}")
+ ("filledcurves" . "x:y | x:y1:y2")
+ ("financebars" . "date:open:low:high:close")
+ ("fsteps" . "y | x:y")
+ ("histeps" . "y | x:y")
+ ("histograms" . "y:yerr | y:ymin:ymax")
+ ("image" . "x:y:value")
+ ("rgbimage" . "x:y:r:g:b")
+ ("rgbalpha" . "x:y:r:g:b:a")
+ ("impulses" . "x{:y{:z}}")
+ ("labels" . "x:y:string")
+ ("lines" . "y | x:y")
+ ("steps" . "y | x:y")
+ ("vectors" . "x:y:xdelta:ydelta")
+ ("xerrorbars" . "x:y:xdelta | x:y:xlow:xhigh")
+ ("xyerrorbars" . "x:y:xdelta:ydelta | x:y:xlow:xhigh:ylow:yhigh")
+ ("yerrorbars" . "x:y:ydelta | x:y:ylow:yhigh")
+ ("yerrorlines" . "x:y:ydelta | x:y:ylow:yhigh")
+ ("xerrorlines" "x:y:xdelta | x:y:xlow:xhigh")
+ ("xyerrorlines" . "x:y:xdelta:ydelta | x:y:xlow:xhigh:ylow:yhigh"))
+ "Alist of ElDoc strings for Gnuplot \"using\" clauses in \"plot\" commands.")
+
+(defvar gnuplot-using-3d-eldoc
+ (append
+ '(("fsteps" . "z | x:y:z")
+ ("histeps" . "z | x:y:z")
+ ("histograms" . "y:yerr | y:ymin:ymax")
+ ("image" . "x:y:z:value")
+ ("rgbimage" . "x:y:z:r:g:b")
+ ("rgbalpha" . "x:y:z:r:g:b:a")
+ ("labels" . "x:y:z:string")
+ ("lines" . "z | x:y:z")
+ ("steps" . "z | x:y:z")
+ ("vectors" . "x:y:z:xdelta:ydelta:zdelta"))
+ gnuplot-using-eldoc)
+ "Alist of ElDoc strings for Gnuplot \"using\" clauses in \"splot\"
commands.")
+
+(defun gnuplot-find-using-eldoc ()
+ "Return ElDoc string for a Gnuplot \"using\" clause, based on plotting style.
+
+This will fail if the \"using\" clause comes before the \"with\"
+clause."
+ (let ((with-style (gnuplot-capture-group :with-style))
+ (3d-p (gnuplot-capture-group :splot-command))
+ (column-description nil))
+ (if with-style
+ (let ((with-style-string (gnuplot-token-id (car with-style))))
+ (setq column-description
+ (or (and 3d-p
+ (cdr (assoc with-style-string gnuplot-using-3d-eldoc)))
+ (cdr (assoc with-style-string gnuplot-using-eldoc))
+ "<columns>"))))
+ (format "using %s {'format'}" column-description)))
+
+;;; Needed for correctly parsing plot commands
+(defun gnuplot-guess-parametric-p (&optional start)
+ "Guess whether the command beginning at START is in parametric mode.
+
+Searches backward in current buffer for an \"(un)set parametric\"
+command."
+ (save-excursion
+ (and start (goto-char start))
+ (catch 'result
+ (while
+ (search-backward-regexp "reset\\|set\\s-+parametric" (point-min) t)
+ (gnuplot-beginning-of-command)
+ (cond ((looking-at "reset\\|unset\\s-+parametric") (throw 'result nil))
+ ((looking-at "set\\s-+parametric") (throw 'result t))))
+ nil)))
+
+
+
+;;;; All done!
+(provide 'gnuplot-context)
+
+;;; gnuplot-context.el ends here
\ No newline at end of file
diff --git a/gnuplot-debug-context.el b/gnuplot-debug-context.el
new file mode 100644
index 0000000..61f7123
--- /dev/null
+++ b/gnuplot-debug-context.el
@@ -0,0 +1,64 @@
+
+(defun gnuplot-unload ()
+ (interactive)
+ (mapatoms
+ (lambda (sym)
+ (when (string-match
+ "gnuplot"
+ (symbol-name sym))
+ (unintern sym obarray)))))
+
+(defun gnuplot-reload (&optional context)
+ (interactive "p")
+ (condition-case nil
+ (gnuplot-unload)
+ (error nil))
+ (require 'gnuplot)
+ (when context
+ (if (= context 16)
+ (require 'gnuplot-debug-context))
+ (require 'gnuplot-context)))
+
+(defmacro with-gnuplot-trace-buffer (&rest body)
+ `(with-current-buffer (get-buffer-create "gnuplot-trace")
+ ,@body))
+
+(defmacro gnuplot-debug (&rest args)
+ `(progn ,@args))
+
+(defmacro gnuplot-trace (&rest args)
+ `(with-gnuplot-trace-buffer (insert (format ,@args))))
+
+(defun gnuplot-backtrace ()
+ (with-gnuplot-trace-buffer
+ (insert "\n-- * backtrace: * --\n\n")
+ (dolist (x stack)
+ (insert (format "%s\n\n" x)))
+ (insert "\n-- end backtrace --\n\n")))
+
+(defun gnuplot-dump-code (&optional inst)
+ (interactive)
+ (let ((inst (or inst gnuplot-compiled-grammar)))
+ (with-gnuplot-trace-buffer
+ (insert "\n-- * compiled code: * --\n\n")
+ (dotimes (i (length inst))
+ (insert (format "%s\t%s\n" i (aref inst i))))
+ (insert "\n-- end compiled code --\n\n")
+ (pop-to-buffer (current-buffer)))))
+
+(defun gnuplot-dump-captures ()
+ (interactive)
+ (with-gnuplot-trace-buffer
+ (insert "\n-- * capture groups: * --\n\n")
+ (loop for c on gnuplot-captures
+ do
+ (let ((name (caar c))
+ (gnuplot-captures c))
+ (insert (format "%s\t%s\n"
+ name
+ (mapconcat 'gnuplot-token-id
+ (gnuplot-capture-group name)
+ " ")))))
+ (insert "\n-- end capture groups --\n\n")))
+
+(provide 'gnuplot-debug-context)
\ No newline at end of file
- [nongnu] branch elpa/gnuplot created (now 7138b13), ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot e3039c5 005/184: Again with the README.org, ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot eec13f0 007/184: Updtaed contact information for move to github, ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot 2f3d40e 037/184: Added experimental context-sensitive completion and help code., ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot b6c56b7 020/184: Modified .gitignore, ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot 171bbea 046/184: Numerous grammar tweaks. Implement `many1' repetition (regex `+')., ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot fca0deb 030/184: make-local-hook causes erros with GNU Emacs 24, ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot bef60ba 019/184: Create a gnuplot-comint buffer in gnuplot-show-gnuplot-buffer if none exists., ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot c3259fb 039/184: Merge branch 'context' of github.com:bruceravel/gnuplot-mode into context, ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot 674a21d 040/184: Merge remote-tracking branch 'origin/devel' into devel, ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot de13740 038/184: Added experimental context-sensitive completion and help code.,
ELPA Syncer <=
- [nongnu] elpa/gnuplot 23f2060 032/184: Merge branch 'master' into devel, ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot 78d691b 003/184: Updated readme, ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot e679a59 002/184: import everything, ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot 00cb492 010/184: Improved continuation line handling by indentation & gnuplot-send-line-*, ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot a375477 031/184: Merge pull request #7 from mcraveiro/master, ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot 566e92f 027/184: Fixed a dumb bug in gnuplot-indent-line., ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot aba40f1 034/184: Document the change to `gnuplot-make-regexp', ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot 72ccda3 017/184: Improved syntax parsing and highlighting, ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot 2387f12 016/184: Restored some XEmacs compatibility that I broke., ELPA Syncer, 2021/08/29
- [nongnu] elpa/gnuplot df865fc 013/184: Slight change to font-lock regexps, and use buffer-local variables, ELPA Syncer, 2021/08/29