1889 lines
76 KiB
EmacsLisp
1889 lines
76 KiB
EmacsLisp
;;; gnuplot.el --- Major-mode and interactive frontend for gnuplot -*- lexical-binding: t -*-
|
||
|
||
;; Copyright (C) 1998, 2011 Phil Type and Bruce Ravel, 1999-2012 Bruce Ravel
|
||
|
||
;; Author: Jon Oddie, Bruce Ravel, Phil Type
|
||
;; Maintainer: Maxime Tréca <maxime@gmail.com>, Daniel Mendler <mail@daniel-mendler.de>
|
||
;; Created: 1998
|
||
;; Package-Version: 20250724.1531
|
||
;; Package-Revision: 43e9674b8694
|
||
;; Keywords: data gnuplot plotting
|
||
;; URL: https://github.com/emacs-gnuplot/gnuplot
|
||
;; Package-Requires: ((emacs "28.1") (compat "30"))
|
||
|
||
;; 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 3 of the License, or
|
||
;; (at your option) any later version.
|
||
|
||
;; This program is distributed in the hope that it will be useful,
|
||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
;; GNU General Public License for more details.
|
||
|
||
;; You should have received a copy of the GNU General Public License
|
||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
|
||
;;; Commentary:
|
||
|
||
;; This is a major mode for composing gnuplot scripts and displaying
|
||
;; their results using gnuplot. It supports features of recent Gnuplot
|
||
;; versions (5.0 and up), but should also work fine with older
|
||
;; versions.
|
||
;;
|
||
;; Gnuplot-mode includes context-sensitive support for keyword
|
||
;; completion and, optionally, eldoc-mode help text. See the
|
||
;; commentary in gnuplot-context.el for more information. If you
|
||
;; don't find it useful, it can be turned off by customizing
|
||
;; `gnuplot-context-sensitive-mode'.
|
||
|
||
;;; Acknowledgements:
|
||
|
||
;; David Batty numerous corrections
|
||
;; Laurent Bonnaud suggestions regarding font-lock rules
|
||
;; Markus Dickebohm suggested `gnuplot-send-line-and-forward'
|
||
;; Stephen Eglan suggested the use of info-look and various fixes
|
||
;; Robert Fenk suggested respecting continuation lines
|
||
;; Michael Karbach suggested trimming the gnuplot process buffer
|
||
;; Alex Chan Libchen suggested font-lock for plotting words
|
||
;; Kuang-Yu Liu pointed out buggy dependence on font-lock
|
||
;; Hrvoje Niksic help with defcustom arguments for insertions
|
||
;; Andreas Rechtsteiner pointed out problem with C-c C-v
|
||
;; Michael Sanders help with the info-look interface
|
||
;; Jinwei Shen suggested functionality in comint buffer
|
||
;; Michael M. Tung prompted me to add pm3d support
|
||
;; Holger Wenzel suggested using `gnuplot-keywords-when'
|
||
;; Wolfgang Zocher pointed out problem with gnuplot-mode + speedbar
|
||
;; Jon Oddie indentation, inline images, context mode
|
||
;; Lars Hecking gnuplot distribution and installation materials
|
||
;; Maxime F. Treca package update, XEmacs deprecation
|
||
;; Daniel Mendler package update, support for recent Emacs
|
||
|
||
;;; Code:
|
||
|
||
(require 'compat)
|
||
(require 'cl-lib)
|
||
(require 'comint)
|
||
(require 'info)
|
||
(require 'info-look)
|
||
|
||
(defgroup gnuplot nil
|
||
"Gnuplot-mode for Emacs."
|
||
:prefix "gnuplot-"
|
||
:group 'processes
|
||
:group 'applications
|
||
:link '(emacs-library-link :tag "Lisp File" "gnuplot.el")
|
||
:link '(url-link :tag "Homepage" "https://github.com/emacs-gnuplot/gnuplot/")
|
||
:link '(info-link :tag "Info Manual" "(gnuplot)")
|
||
:link '(emacs-commentary-link :tag "Commentary" "gnuplot.el"))
|
||
|
||
(defcustom gnuplot-program "gnuplot"
|
||
"The name of the gnuplot executable."
|
||
:type 'string)
|
||
|
||
(defcustom gnuplot-program-args nil
|
||
"Whitespace-separated flags to pass to the gnuplot executable."
|
||
:type 'string)
|
||
|
||
(defcustom gnuplot-process-name "gnuplot"
|
||
"Name given to the gnuplot buffer and process."
|
||
:type 'string)
|
||
|
||
(defcustom gnuplot-gnuplot-buffer "plot.gp"
|
||
"The name of the gnuplot scratch buffer opened by `gnuplot-make-buffer'."
|
||
:type 'string)
|
||
|
||
(defcustom gnuplot-display-process 'window
|
||
"This controls how the gnuplot process buffer is displayed.
|
||
The values are
|
||
\\='frame display gnuplot process in a separate frame
|
||
\\='window display gnuplot process in this frame but in another window
|
||
nil `gnuplot-process' is in the current frame but not displayed"
|
||
:type '(radio (const :tag "Separate frame" frame)
|
||
(const :tag "Separate window" window)
|
||
(const :tag "Not displayed" nil)))
|
||
|
||
(defcustom gnuplot-info-display 'window
|
||
"Determines how `gnuplot-info-lookup-symbol' displays the info file.
|
||
The values are
|
||
\\='frame display info file in a separate frame
|
||
\\='window display info file in another window
|
||
nil display info file in the current window"
|
||
:type '(radio (const :tag "Separate frame" frame)
|
||
(const :tag "Separate window" window)
|
||
(const :tag "This window" nil)))
|
||
|
||
(defcustom gnuplot-echo-command-line-flag
|
||
(not (string-match "msvc" (emacs-version)))
|
||
"Non-nil means the gnuplot subprocess echoes any input.
|
||
This sets the fall-back value of `comint-process-echoes'.
|
||
If `gnuplot-mode' cannot figure out what version number of gnuplot
|
||
this is, then the value of this variable will be used for
|
||
`comint-process-echos'. It seems that gnuplot 3.5 wants this to be
|
||
nil and 3.7 wants it to be t. If lines that you send to gnuplot from
|
||
the `gnuplot-mode' buffer are not appearing at the gnuplot prompt in
|
||
the process buffer, try toggling it. Also see the document string for
|
||
`comint-process-echos'. If you change this, kill the gnuplot process
|
||
and start it again."
|
||
:type 'boolean)
|
||
|
||
(defcustom gnuplot-delay 0.02
|
||
"Amount of time to delay before sending a new line to gnuplot.
|
||
This is needed so that the the line is not written in the gnuplot
|
||
buffer in advance of its prompt. Increase this number if the
|
||
prompts and lines are displayed out of order."
|
||
:type 'number)
|
||
|
||
(defcustom gnuplot-buffer-max-size 1000
|
||
"The maximum size in lines of the gnuplot process buffer.
|
||
Each time text is written in the gnuplot process buffer, lines are
|
||
trimmed from the beginning of the buffer so that the buffer is this
|
||
many lines long. The lines are deleted after the most recent lines
|
||
were interpretted by gnuplot. Setting to 0 turns off this feature."
|
||
:type 'integer)
|
||
|
||
(defcustom gnuplot-quote-character "\'"
|
||
"Quotation character used for inserting quoted strings.
|
||
Gnuplot can use single or double quotes. If you prefer to have the
|
||
filename insertion function never insert quotes for you, set this
|
||
to the empty string."
|
||
:type '(radio (const :tag "double quote" "\"")
|
||
(const :tag "single quote" "\'")
|
||
(const :tag "none" "" )))
|
||
|
||
(defcustom gnuplot-basic-offset 4
|
||
"Number of columns to indent lines inside a do- or if-else-block.
|
||
|
||
This applies only to new-style do- and if-statements using
|
||
braces. Commands continued over a linebreak using a backslash
|
||
are always indented to line up with the second word on the line
|
||
beginning the continued command."
|
||
:type 'integer)
|
||
|
||
(defvar gnuplot-context-sensitive-mode nil)
|
||
(autoload 'gnuplot-context-sensitive-mode "gnuplot-context")
|
||
(autoload 'gnuplot-gui-set-options-and-insert "gnuplot-gui" nil '(gnuplot-mode))
|
||
(autoload 'gnuplot-gui-swap-simple-complete "gnuplot-gui" nil '(gnuplot-mode))
|
||
(autoload 'gnuplot-gui-toggle-popup "gnuplot-gui" nil '(gnuplot-mode))
|
||
|
||
(defcustom gnuplot-use-context-sensitive-completion t
|
||
"Non-nil if `gnuplot-context-sensitive-mode' should be enabled by default.
|
||
|
||
In context-sensitive mode, `gnuplot-mode' parses the current
|
||
command line to provide smarter completion and documentation
|
||
suggestions."
|
||
:type 'boolean
|
||
:set (lambda (sym value)
|
||
(set sym value)
|
||
(cond
|
||
(value
|
||
(add-hook 'gnuplot-mode-hook #'gnuplot-context-sensitive-mode nil nil)
|
||
(add-hook 'gnuplot-comint-mode-hook #'gnuplot-context-sensitive-mode nil nil))
|
||
(t
|
||
(remove-hook 'gnuplot-mode-hook #'gnuplot-context-sensitive-mode)
|
||
(remove-hook 'gnuplot-comint-mode-hook #'gnuplot-context-sensitive-mode)))
|
||
(dolist (buffer (buffer-list))
|
||
(with-current-buffer buffer
|
||
(when (derived-mode-p 'gnuplot-mode 'gnuplot-comint-mode)
|
||
(gnuplot-context-sensitive-mode (if value 1 0))))))
|
||
:link '(emacs-commentary-link "gnuplot-context"))
|
||
|
||
(defun gnuplot--set-display-mode (variable value &rest _args)
|
||
"Customize :set function for `gnuplot-inline-image-mode'.
|
||
Set VARIABLE to VALUE. ARGS is optional args."
|
||
(if (and (eq variable 'gnuplot-inline-image-mode)
|
||
value
|
||
(not (display-images-p)))
|
||
(progn
|
||
(message "Displaying images is not supported.")
|
||
(set variable nil))
|
||
(set variable value))
|
||
(gnuplot--setup-comint-for-image-mode))
|
||
|
||
(defcustom gnuplot-inline-image-mode (and (display-graphic-p)
|
||
(image-type-available-p 'png)
|
||
'inline)
|
||
"Whether to display Gnuplot output in Emacs.
|
||
|
||
Possible values are nil, `inline' and `dedicated'.
|
||
|
||
When this is nil, Gnuplot output is handled outside of Emacs in
|
||
the normal way. Otherwise, Emacs attempts to capture Gnuplot's
|
||
output and display it in a buffer. Output is inserted inline in
|
||
the Gnuplot interaction buffer it this is `inline', in a
|
||
separate dedicated buffer if it is `dedicated'.
|
||
|
||
Use Customize to set this variable, or the commands
|
||
`gnuplot-external-display-mode', `gnuplot-inline-display-mode',
|
||
and `gnuplot-dedicated-display-mode'."
|
||
:type '(radio
|
||
(const :tag "No" nil)
|
||
(const :tag "In Comint buffer" inline)
|
||
(const :tag "In dedicated buffer" dedicated))
|
||
:initialize #'custom-initialize-default
|
||
:set #'gnuplot--set-display-mode)
|
||
|
||
(defcustom gnuplot-image-format "png"
|
||
"Image format to use for displaying images within Emacs.
|
||
|
||
This will be sent directly to Gnuplot as a command of the form
|
||
\"set terminal <FORMAT>\". Common values are \"png\" and
|
||
\"svg\".
|
||
|
||
This only has an effect when `gnuplot-inline-image-mode' is
|
||
non-nil."
|
||
:type 'string
|
||
:initialize #'custom-initialize-default
|
||
:set #'gnuplot--set-display-mode)
|
||
|
||
(defcustom gnuplot-image-buffer "*gnuplot image*"
|
||
"Buffer name for dedicated gnuplot image output."
|
||
:type 'string)
|
||
|
||
(defcustom gnuplot-hidden-output-buffer " *gnuplot hidden*"
|
||
"Buffer name for hidden gnuplot output.
|
||
Send commands to GNUPLOT silently & without generating an extra prompt."
|
||
:type 'string)
|
||
|
||
|
||
;;; customizable hooks
|
||
|
||
(defgroup gnuplot-hooks nil
|
||
"Hook variables used by `gnuplot-mode'."
|
||
:prefix "gnuplot-"
|
||
:group 'gnuplot)
|
||
|
||
(defcustom gnuplot-mode-hook nil
|
||
"Hook run when `gnuplot-mode' is entered."
|
||
:type 'hook)
|
||
|
||
(defcustom gnuplot-after-plot-hook (list #'gnuplot-trim-comint-buffer)
|
||
"Hook run after gnuplot plots something.
|
||
This is the last thing done by the functions for plotting a line, a
|
||
region, a buffer, or a file."
|
||
:type 'hook)
|
||
|
||
(defcustom gnuplot-comint-mode-hook nil
|
||
"Hook run after setting up the gnuplot buffer in `gnuplot-comint-mode'."
|
||
:type 'hook)
|
||
|
||
|
||
|
||
;;; --- insertions variables and menus
|
||
|
||
(defgroup gnuplot-insertions nil
|
||
"Insert commands into gnuplot-scripts from a pull-down menu."
|
||
:prefix "gnuplot-insertions-"
|
||
:group 'gnuplot)
|
||
|
||
(defvar gnuplot--insertions-menu nil
|
||
"Menu for insertions in `gnuplot-mode'.
|
||
|
||
The insertions menu is composed of several sub-menus. The variables
|
||
describing the sub-menus are:
|
||
`gnuplot-insertions-adornments'
|
||
`gnuplot-insertions-plot-options'
|
||
`gnuplot-insertions-terminal'
|
||
`gnuplot-insertions-x-axis'
|
||
`gnuplot-insertions-y-axis'
|
||
`gnuplot-insertions-z-axis'
|
||
`gnuplot-insertions-x2-axis'
|
||
`gnuplot-insertions-y2-axis'
|
||
`gnuplot-insertions-parametric-plots'
|
||
`gnuplot-insertions-polar-plots'
|
||
`gnuplot-insertions-surface-plots'
|
||
These variables can be customized by the user. For example, there are
|
||
many terminal types which are not in the terminal submenu but which
|
||
may be compiled into your copy of gnuplot.
|
||
|
||
Each of these variables is a list whose first element is a string and
|
||
all the rest are vectors as described in the document string for
|
||
`easy-menu-define'. The callback used throughout these menus is
|
||
`gnuplot-insert' which inserts the appropriate set expression and,
|
||
optionally, looks up that item in the gnuplot info file.
|
||
|
||
The easiest way to customize the submenus is to use the custom
|
||
package. Just type \\[gnuplot-customize] and follow your nose.
|
||
|
||
You can also add new items to any of these sub-menus by adding to the
|
||
`with-eval-after-load' blocks in your .emacs file. Here is an example of
|
||
adding the \"regis\" terminal type to the terminal sub-menu:
|
||
|
||
(with-eval-after-load \\='gnuplot
|
||
(setq gnuplot-insertions-terminal
|
||
(append gnuplot-insertions-terminal
|
||
(list
|
||
[\"regis\"
|
||
(gnuplot-insert \"set terminal regis\")
|
||
t]))))")
|
||
|
||
(defcustom gnuplot-insertions-show-help-flag nil
|
||
"Non-nil means to display certain help messages automatically.
|
||
These messages are shown after menu insertion of gnuplot commands."
|
||
:type 'boolean)
|
||
|
||
(defcustom gnuplot-insertions-menu-flag t
|
||
"Non-nil means to place the insertion menu in the menubar.
|
||
Changing this will not effect a change in any currently existing
|
||
`gnuplot-mode' buffer. You will see the change the next time you
|
||
create a `gnuplot-mode' buffer."
|
||
:type 'boolean)
|
||
|
||
(defvar gnuplot-insertions-top
|
||
'("insert set expression" "---")
|
||
"Top part of insertions menu.
|
||
See the document string for `gnuplot--insertions-menu'")
|
||
|
||
(defcustom gnuplot-insertions-adornments ; this is icky...
|
||
'("adornments"
|
||
["arrow" (gnuplot-insert "set arrow ") t]
|
||
["bar" (gnuplot-insert "set bar") t]
|
||
["border" (gnuplot-insert "set border") t]
|
||
["boxwidth" (gnuplot-insert "set boxwidth ") t]
|
||
["format" (gnuplot-insert "set format ") t]
|
||
["grid" (gnuplot-insert "set grid") t]
|
||
["key" (gnuplot-insert "set key ") t]
|
||
["label" (gnuplot-insert "set label ") t]
|
||
["pointsize" (gnuplot-insert "set pointsize ") t]
|
||
["samples" (gnuplot-insert "set samples ") t]
|
||
["size" (gnuplot-insert "set size ") t]
|
||
["style" (gnuplot-insert "set style ") t]
|
||
["tics" (gnuplot-insert "set tics ") t]
|
||
["timefmt" (gnuplot-insert "set timefmt ") t]
|
||
["timestamp" (gnuplot-insert "set timestamp ") t]
|
||
["title" (gnuplot-insert "set title ") t]
|
||
["zeroaxis" (gnuplot-insert "set zeroaxis") t])
|
||
|
||
"Adornments submenu in the insertions menu.
|
||
See the document string for `gnuplot--insertions-menu'
|
||
Changing this will not effect a change in any currently existing
|
||
`gnuplot-mode' buffer. You will see the change the next time you
|
||
create a `gnuplot-mode' buffer."
|
||
:type '(list (string :tag "Title")
|
||
(repeat :inline t
|
||
(vector (string :tag "Name")
|
||
(function :tag "Callback")
|
||
(boolean :tag "Enabled" t)))))
|
||
|
||
(defcustom gnuplot-insertions-plot-options
|
||
'("plot options"
|
||
["autoscale" (gnuplot-insert "set autoscale ") t]
|
||
["clip" (gnuplot-insert "set clip ") t]
|
||
["encoding" (gnuplot-insert "set encoding ") t]
|
||
["locale" (gnuplot-insert "set locale ") t]
|
||
["logscale" (gnuplot-insert "set logscale ") t]
|
||
["multiplot" (gnuplot-insert "set multiplot") t]
|
||
["missing" (gnuplot-insert "set missing \"\"") t]
|
||
["palette" (gnuplot-insert "set palette ") t]
|
||
["pm3d" (gnuplot-insert "set pm3d ") t]
|
||
["offsets" (gnuplot-insert "set offsets ") t]
|
||
["output" (gnuplot-insert "set output ") t]
|
||
["zero" (gnuplot-insert "set zero ") t])
|
||
"Plot options submenu in the insertions menu.
|
||
See the document string for `gnuplot--insertions-menu'
|
||
Changing this will not effect a change in any currently existing
|
||
`gnuplot-mode' buffer. You will see the change the next time you
|
||
create a `gnuplot-mode' buffer."
|
||
:type '(list (string :tag "Title")
|
||
(repeat :inline t
|
||
(vector (string :tag "Name")
|
||
(function :tag "Callback")
|
||
(boolean :tag "Enabled" t)))))
|
||
|
||
(defcustom gnuplot-insertions-terminal
|
||
'("terminal"
|
||
["eepic" (gnuplot-insert "set terminal eepic") t]
|
||
["fig" (gnuplot-insert "set terminal fig") t]
|
||
["gpic" (gnuplot-insert "set terminal gpic") t]
|
||
["latex" (gnuplot-insert "set terminal latex") t]
|
||
["linux" (gnuplot-insert "set terminal linux") t]
|
||
["pbm" (gnuplot-insert "set terminal pbm") t]
|
||
["png" (gnuplot-insert "set terminal png") t]
|
||
["postscript" (gnuplot-insert "set terminal postscript") t]
|
||
["pslatex" (gnuplot-insert "set terminal pslatex") t]
|
||
["table" (gnuplot-insert "set terminal table") t]
|
||
["tek40xx" (gnuplot-insert "set terminal tek40xx") t]
|
||
["tkcanvas" (gnuplot-insert "set terminal tkcanvas") t]
|
||
["tpic" (gnuplot-insert "set terminal tpic") t]
|
||
["vgagl" (gnuplot-insert "set terminal vgagl") t] ; for pm3d patch
|
||
["vttek" (gnuplot-insert "set terminal vttek") t]
|
||
["x11" (gnuplot-insert "set terminal x11") t])
|
||
"Terminal submenu in the insertions menu.
|
||
See the document string for `gnuplot--insertions-menu'
|
||
Changing this will not effect a change in any currently existing
|
||
`gnuplot-mode' buffer. You will see the change the next time you
|
||
create a `gnuplot-mode' buffer."
|
||
:type '(list (string :tag "Title")
|
||
(repeat :inline t
|
||
(vector (string :tag "Name")
|
||
(function :tag "Callback")
|
||
(boolean :tag "Enabled" t)))))
|
||
|
||
(defcustom gnuplot-insertions-x-axis
|
||
'("x-axis"
|
||
["xdata" (gnuplot-insert "set xdata ") t]
|
||
["xlabel" (gnuplot-insert "set xlabel ") t]
|
||
["xrange" (gnuplot-insert "set xrange [:]") t]
|
||
["xtics" (gnuplot-insert "set xtics ") t]
|
||
["mxtics" (gnuplot-insert "set mxtics ") t]
|
||
["xzeroaxis" (gnuplot-insert "set xzeroaxis ") t]
|
||
["xdtics" (gnuplot-insert "set xdtics ") t]
|
||
["xmtics" (gnuplot-insert "set xmtics ") t])
|
||
"X-axis submenu in the insertions menu.
|
||
See the document string for `gnuplot--insertions-menu'
|
||
Changing this will not effect a change in any currently existing
|
||
`gnuplot-mode' buffer. You will see the change the next time you
|
||
create a `gnuplot-mode' buffer."
|
||
:type '(list (string :tag "Title")
|
||
(repeat :inline t
|
||
(vector (string :tag "Name")
|
||
(function :tag "Callback")
|
||
(boolean :tag "Enabled" t)))))
|
||
|
||
(defcustom gnuplot-insertions-x2-axis
|
||
'("x2-axis"
|
||
["x2data" (gnuplot-insert "set xdata ") t]
|
||
["x2label" (gnuplot-insert "set xlabel ") t]
|
||
["x2range" (gnuplot-insert "set xrange [:]") t]
|
||
["x2tics" (gnuplot-insert "set xtics ") t]
|
||
["mx2tics" (gnuplot-insert "set mxtics ") t]
|
||
["x2zeroaxis" (gnuplot-insert "set xzeroaxis ") t]
|
||
["x2dtics" (gnuplot-insert "set xdtics ") t]
|
||
["x2mtics" (gnuplot-insert "set xmtics ") t])
|
||
"X2-axis submenu in the insertions menu.
|
||
See the document string for `gnuplot--insertions-menu'
|
||
Changing this will not effect a change in any currently existing
|
||
`gnuplot-mode' buffer. You will see the change the next time you
|
||
create a `gnuplot-mode' buffer."
|
||
:type '(list (string :tag "Title")
|
||
(repeat :inline t
|
||
(vector (string :tag "Name")
|
||
(function :tag "Callback")
|
||
(boolean :tag "Enabled" t)))))
|
||
|
||
(defcustom gnuplot-insertions-y-axis
|
||
'("y-axis"
|
||
["ydata" (gnuplot-insert "set ydata ") t]
|
||
["ylabel" (gnuplot-insert "set ylabel ") t]
|
||
["ymtics" (gnuplot-insert "set ymtics ") t]
|
||
["yrange" (gnuplot-insert "set yrange [:]") t]
|
||
["ytics" (gnuplot-insert "set ytics ") t]
|
||
["yzeroaxis" (gnuplot-insert "set yzeroaxis ") t]
|
||
["ydtics" (gnuplot-insert "set ydtics ") t]
|
||
["mytics" (gnuplot-insert "set mytics ") t])
|
||
"Y-axis submenu in the insertions menu.
|
||
See the document string for `gnuplot--insertions-menu'
|
||
Changing this will not effect a change in any currently existing
|
||
`gnuplot-mode' buffer. You will see the change the next time you
|
||
create a `gnuplot-mode' buffer."
|
||
:type '(list (string :tag "Title")
|
||
(repeat :inline t
|
||
(vector (string :tag "Name")
|
||
(function :tag "Callback")
|
||
(boolean :tag "Enabled" t)))))
|
||
|
||
(defcustom gnuplot-insertions-y2-axis
|
||
'("y2-axis"
|
||
["y2data" (gnuplot-insert "set ydata ") t]
|
||
["y2label" (gnuplot-insert "set ylabel ") t]
|
||
["y2range" (gnuplot-insert "set yrange [:]") t]
|
||
["y2tics" (gnuplot-insert "set ytics ") t]
|
||
["my2tics" (gnuplot-insert "set mytics ") t]
|
||
["y2zeroaxis" (gnuplot-insert "set yzeroaxis ") t]
|
||
["y2mtics" (gnuplot-insert "set ymtics ") t]
|
||
["y2dtics" (gnuplot-insert "set ydtics ") t])
|
||
"Y2-axis submenu in the insertions menu.
|
||
See the document string for `gnuplot--insertions-menu'
|
||
Changing this will not effect a change in any currently existing
|
||
`gnuplot-mode' buffer. You will see the change the next time you
|
||
create a `gnuplot-mode' buffer."
|
||
:type '(list (string :tag "Title")
|
||
(repeat :inline t
|
||
(vector (string :tag "Name")
|
||
(function :tag "Callback")
|
||
(boolean :tag "Enabled" t)))))
|
||
|
||
(defcustom gnuplot-insertions-z-axis
|
||
'("z-axis"
|
||
["zdata" (gnuplot-insert "set zdata ") t]
|
||
["zlabel" (gnuplot-insert "set zlabel ") t]
|
||
["zrange" (gnuplot-insert "set zrange [:]") t]
|
||
["ztics" (gnuplot-insert "set ztics ") t]
|
||
["mztics" (gnuplot-insert "set mztics ") t]
|
||
["zdtics" (gnuplot-insert "set zdtics ") t]
|
||
["zmtics" (gnuplot-insert "set zmtics ") t])
|
||
"Z-axis submenu in the insertions menu.
|
||
See the document string for `gnuplot--insertions-menu'
|
||
Changing this will not effect a change in any currently existing
|
||
`gnuplot-mode' buffer. You will see the change the next time you
|
||
create a `gnuplot-mode' buffer."
|
||
:type '(list (string :tag "Title")
|
||
(repeat :inline t
|
||
(vector (string :tag "Name")
|
||
(function :tag "Callback")
|
||
(boolean :tag "Enabled" t)))))
|
||
|
||
(defcustom gnuplot-insertions-parametric-plots
|
||
'("parametric plots"
|
||
["parametric" (gnuplot-insert "set parametric") t]
|
||
["isosamples" (gnuplot-insert "set isosamples ") t]
|
||
["dummy" (gnuplot-insert "set dummy ") t]
|
||
["trange" (gnuplot-insert "set trange [:]") t]
|
||
["urange" (gnuplot-insert "set urange [:]") t]
|
||
["vrange" (gnuplot-insert "set vrange [:]") t])
|
||
"Parametric plots submenu in the insertions menu.
|
||
See the document string for `gnuplot--insertions-menu'
|
||
Changing this will not effect a change in any currently existing
|
||
`gnuplot-mode' buffer. You will see the change the next time you
|
||
create a `gnuplot-mode' buffer."
|
||
:type '(list (string :tag "Title")
|
||
(repeat :inline t
|
||
(vector (string :tag "Name")
|
||
(function :tag "Callback")
|
||
(boolean :tag "Enabled" t)))))
|
||
|
||
(defcustom gnuplot-insertions-polar-plots
|
||
'("polar plots"
|
||
["polar" (gnuplot-insert "set polar") t]
|
||
["angles" (gnuplot-insert "set angles ") t]
|
||
["rrange" (gnuplot-insert "set rrange [:]") t])
|
||
"Polar plots submenu in the insertions menu.
|
||
See the document string for `gnuplot--insertions-menu'
|
||
Changing this will not effect a change in any currently existing
|
||
`gnuplot-mode' buffer. You will see the change the next time you
|
||
create a `gnuplot-mode' buffer."
|
||
:type '(list (string :tag "Title")
|
||
(repeat :inline t
|
||
(vector (string :tag "Name")
|
||
(function :tag "Callback")
|
||
(boolean :tag "Enabled" t)))))
|
||
|
||
(defcustom gnuplot-insertions-surface-plots
|
||
'("surface plots"
|
||
["clabel" (gnuplot-insert "set clabel ") t]
|
||
["cntrparam" (gnuplot-insert "set cntrparam ") t]
|
||
["contour" (gnuplot-insert "set contour") t]
|
||
["dgrid3d" (gnuplot-insert "set dgrid3d ") t]
|
||
["hidden3d" (gnuplot-insert "set hidden3d ") t]
|
||
["mapping" (gnuplot-insert "set mapping ") t]
|
||
["surface" (gnuplot-insert "set surface ") t]
|
||
["view" (gnuplot-insert "set view ") t])
|
||
"Surface plots submenu in the insertions menu.
|
||
See the document string for `gnuplot--insertions-menu'
|
||
Changing this will not effect a change in any currently existing
|
||
`gnuplot-mode' buffer. You will see the change the next time you
|
||
create a `gnuplot-mode' buffer."
|
||
:type '(list (string :tag "Title")
|
||
(repeat :inline t
|
||
(vector (string :tag "Name")
|
||
(function :tag "Callback")
|
||
(boolean :tag "Enabled" t)))))
|
||
|
||
(defvar gnuplot-insertions-bottom
|
||
'("---"
|
||
["Display of info with insertion" gnuplot-toggle-info-display
|
||
:style toggle :selected gnuplot-insertions-show-help-flag]
|
||
["Display GUI popup with insertion" gnuplot-gui-toggle-popup
|
||
:active t
|
||
:style toggle :selected gnuplot-gui-popup-flag])
|
||
"Bottom part of the insertions menu.
|
||
This part contains the toggle buttons for displaying info or
|
||
opening an argument-setting popup.")
|
||
|
||
(defvar gnuplot-recently-sent nil
|
||
"This is a record of the most recent kind of text sent to gnuplot.
|
||
It takes as its value nil, `line', `region', `buffer', or `file'. It is
|
||
useful for functions included in `gnuplot-after-plot-hook'.")
|
||
|
||
(defvar gnuplot-buffer nil
|
||
"The name of the buffer displaying the gnuplot process.")
|
||
|
||
(defvar gnuplot-process nil
|
||
"Variable holding the process handle.")
|
||
|
||
(defvar gnuplot--comint-recent-buffer nil
|
||
"The most recently plotted gnuplot script buffer.
|
||
This is used by the function that plot from the comint buffer. It is
|
||
reset every time something is plotted from a script buffer.")
|
||
|
||
(defvar gnuplot--process-frame nil
|
||
"The frame for displaying the gnuplot process.
|
||
This is used when `gnuplot-display-process' is equal to `frame'.")
|
||
|
||
(defvar gnuplot--info-frame nil)
|
||
|
||
;; with info-look, there is no need to carry this list around -- it
|
||
;; can be generated on the fly appropriate to the currently installed
|
||
;; version of gnuplot.info
|
||
(defvar gnuplot--info-keywords 'pending
|
||
"A list of keywords used in GNUPLOT.
|
||
These are set by `gnuplot--set-keywords-list' from the values in
|
||
`info-lookup-cache'.")
|
||
|
||
|
||
;;; --- key bindings and menus
|
||
|
||
(defvar-keymap gnuplot-mode-map
|
||
:doc "Keymap used by `gnuplot-mode'."
|
||
:parent prog-mode-map
|
||
"C-c C-b" #'gnuplot-send-buffer-to-gnuplot
|
||
"C-c C-o" #'gnuplot-gui-set-options-and-insert
|
||
"C-c C-e" #'gnuplot-show-comint-buffer
|
||
"C-c C-f" #'gnuplot-send-file-to-gnuplot
|
||
"C-c C-d" #'gnuplot-info-lookup-symbol
|
||
"C-c C-i" #'gnuplot-insert-filename
|
||
"C-c C-j" #'gnuplot-forward-script-line
|
||
"C-c C-k" #'gnuplot-kill-comint-buffer
|
||
"C-c C-l" #'gnuplot-send-line-to-gnuplot
|
||
"C-c C-n" #'gnuplot-negate-option
|
||
"C-c C-r" #'gnuplot-send-region-to-gnuplot
|
||
"C-M-x" #'gnuplot-send-line-to-gnuplot
|
||
"C-c C-v" #'gnuplot-send-line-and-forward
|
||
"C-c C-z" #'gnuplot-customize
|
||
"}" #'gnuplot-electric-insert
|
||
"M-TAB" #'completion-at-point
|
||
"S-<mouse-2>" #'gnuplot-gui-set-options-and-insert)
|
||
|
||
(defvar gnuplot--display-options-menu
|
||
(cl-flet ((make-image-setter (type)
|
||
`[,(concat (upcase type) " images")
|
||
(lambda () (interactive) (gnuplot-set-image-format ,type))
|
||
:style toggle
|
||
:selected (eq gnuplot-image-format ,type)]))
|
||
`("Display plot output"
|
||
["Externally" gnuplot-external-display-mode
|
||
:style toggle
|
||
:selected (null gnuplot-inline-image-mode)]
|
||
["In Comint buffer" gnuplot-inline-display-mode
|
||
:active (display-images-p)
|
||
:style toggle
|
||
:selected (eq gnuplot-inline-image-mode 'comint)]
|
||
["In dedicated buffer" gnuplot-dedicated-display-mode
|
||
:style toggle
|
||
:selected (eq gnuplot-inline-image-mode 'dedicated)]
|
||
"---"
|
||
,@(mapcar #'make-image-setter (list "png" "jpeg" "svg"))
|
||
["Other image type..." gnuplot-set-image-format])))
|
||
|
||
(easy-menu-define gnuplot-mode-menu gnuplot-mode-map
|
||
"Menu used in `gnuplot-mode'."
|
||
`("Gnuplot"
|
||
["Send line to gnuplot" gnuplot-send-line-to-gnuplot t]
|
||
["Send line & move forward" gnuplot-send-line-and-forward (not (eobp))]
|
||
["Send region to gnuplot" gnuplot-send-region-to-gnuplot
|
||
(gnuplot--mark-active)]
|
||
["Send buffer to gnuplot" gnuplot-send-buffer-to-gnuplot t]
|
||
["Send file to gnuplot" gnuplot-send-file-to-gnuplot t]
|
||
"---"
|
||
,gnuplot--display-options-menu
|
||
["Contextual completion and help" gnuplot-context-sensitive-mode
|
||
:style toggle
|
||
:selected gnuplot-context-sensitive-mode]
|
||
["Echo area help (eldoc-mode)" eldoc-mode
|
||
:active gnuplot-context-sensitive-mode
|
||
:style toggle
|
||
:selected eldoc-mode]
|
||
"---"
|
||
["Insert filename at point" gnuplot-insert-filename t]
|
||
["Negate set option" gnuplot-negate-option t]
|
||
["Keyword help" gnuplot-info-lookup-symbol]
|
||
["Quick help for thing at point" gnuplot-context-help-at-point
|
||
gnuplot-context-sensitive-mode]
|
||
["Info documentation on thing at point"
|
||
gnuplot-context-info-at-point
|
||
gnuplot-context-sensitive-mode]
|
||
["Show gnuplot process buffer" gnuplot-show-comint-buffer t]
|
||
["Set arguments at point" gnuplot-gui-set-options-and-insert t]
|
||
["Swap plot/splot/fit lists in GUI" gnuplot-gui-swap-simple-complete t]
|
||
"---"
|
||
["Customize gnuplot" gnuplot-customize t]
|
||
"---"
|
||
["Kill gnuplot" gnuplot-kill-comint-buffer t]))
|
||
|
||
|
||
;;; --- syntax colorization, syntax table
|
||
|
||
(defvar gnuplot-mode-abbrev-table)
|
||
(defvar gnuplot-mode-syntax-table
|
||
(let ((table (make-syntax-table)))
|
||
(modify-syntax-entry ?* "." table)
|
||
(modify-syntax-entry ?+ "." table)
|
||
(modify-syntax-entry ?- "." table)
|
||
(modify-syntax-entry ?/ "." table)
|
||
(modify-syntax-entry ?% "." table)
|
||
(modify-syntax-entry ?= "." table)
|
||
(modify-syntax-entry ?: "." table)
|
||
(modify-syntax-entry ?& "." table )
|
||
(modify-syntax-entry ?^ "." table )
|
||
(modify-syntax-entry ?| "." table )
|
||
(modify-syntax-entry ?& "." table )
|
||
(modify-syntax-entry ?? "." table )
|
||
(modify-syntax-entry ?~ "." table )
|
||
(modify-syntax-entry ?_ "w" table )
|
||
(modify-syntax-entry ?\" "." table)
|
||
(modify-syntax-entry ?\' "." table)
|
||
(modify-syntax-entry ?` "." table)
|
||
(modify-syntax-entry ?\\ "." table)
|
||
|
||
table)
|
||
|
||
"Syntax table in use in `gnuplot-mode' buffers.
|
||
This is the same as the standard syntax table except that ` and _
|
||
are word characters, and math operators are punctuation
|
||
characters.")
|
||
|
||
;; Macro to generate efficient regexps for keyword matching
|
||
;;
|
||
;; These regular expressions treat the gnuplot vocabulary as complete
|
||
;; words. Although gnuplot will recognise unique abbreviations, these
|
||
;; regular expressions will not.
|
||
(defmacro gnuplot--make-regexp (list)
|
||
"Macro to generate efficient regexps for keyword matching from LIST."
|
||
`(regexp-opt ,list 'words))
|
||
|
||
;; Lists of gnuplot keywords for syntax coloring etc.
|
||
(defvar gnuplot--keywords-builtin-functions
|
||
'("abs" "acosh" "acos" "arg" "asinh" "asin" "atan" "atanh" "atan2" "besj1"
|
||
"besj0" "besy1" "besy0" "ceil" "column" "cosh" "cos" "erfc" "erf" "exp"
|
||
"floor" "gamma" "ibeta" "igamma" "imag" "int" "inverf" "invnorm" "lgamma"
|
||
"log" "log10" "norm" "rand" "real" "sgn" "sinh" "sin" "sqrt" "tanh" "tan"
|
||
"tm_hour" "tm_mday" "tm_min" "tm_mon" "tm_sec" "tm_wday" "tm_yday" "tm_year"
|
||
"valid" "EllipticPi" "EllipticE" "EllipticK" "words" "word" "value"
|
||
"timecolumn" "substr" "strstrt" "strptime" "strlen" "stringcolumn"
|
||
"strftime" "sprintf" "lambertw" "gprintf" "exists" "defined" "columnhead")
|
||
|
||
"List of GNUPLOT built-in functions, as strings.
|
||
|
||
These are highlighted using `font-lock-function-name-face'.")
|
||
|
||
(defvar gnuplot--keywords-plotting
|
||
'("axes" "every" "index" "lw" "lt" "ls" "linestyle" "linetype" "linewidth"
|
||
"notitle" "pt" "ps" "pointsize" "pointtype" "smooth" "thru" "title" "using"
|
||
"with" "noautoscale" "volatile" "matrix" "nonuniform" "binary" "fillstyle"
|
||
"linecolor" "pointinterval" "nosurface" "nocontours" "nohidden3d")
|
||
"List of GNUPLOT keywords associated with plotting, as strings.
|
||
|
||
These are highlighted using `font-lock-type-face'.
|
||
This list does not include plotting styles -- for that, see
|
||
`gnuplot--keywords-plotting-styles'")
|
||
|
||
(defvar gnuplot--keywords-plotting-styles
|
||
'("boxerrorbars" "boxes" "boxxyerrorbars" "candlesticks" "dots" "errorbars"
|
||
"financebars" "fsteps" "histeps" "impulses" "lines" "linespoints" "points"
|
||
"steps" "vector" "xerrorbars" "xyerrorbars" "yerrorbars" "vectors"
|
||
"filledcurves" "labels" "rgbalpha" "rgbimage" "image" "circles" "pm3d"
|
||
"histograms" "xyerrorlines" "xerrorlines" "errorlines" "yerrorlines")
|
||
|
||
"List of GNUPLOT plotting styles, as strings.
|
||
|
||
These are highlighted using `font-lock-function-name-face'.")
|
||
|
||
(defvar gnuplot--keywords-misc
|
||
'("bind" "cd" "clear" "exit" "fit" "help" "history" "load" "pause" "print"
|
||
"pwd" "quit" "replot" "save" "set" "show" "unset" "if" "else" "do" "update"
|
||
"undefine" "test" "system" "raise" "lower" "eval" "shell" "reset" "reread"
|
||
"refresh" "call")
|
||
"List of GNUPLOT miscellaneous commands, as strings.
|
||
|
||
These are highlighted using `font-lock-constant-face'.")
|
||
|
||
(defvar gnuplot--keywords-negatable-options
|
||
'("arrow" "autoscale" "border" "clabel" "clip" "contour" "dgrid3d" "grid"
|
||
"hidden3d" "historysize" "key" "label" "linestyle" "logscale" "mouse"
|
||
"multiplot" "mx2tics" "mxtics" "my2tics" "mytics" "mztics" "offsets" "polar"
|
||
"surface" "timestamp" "title" "x2dtics" "x2mtics" "x2tics" "x2zeroaxis"
|
||
"xdtics" "xmtics" "xtics" "xzeroaxis" "y2dtics" "y2mtics" "y2tics"
|
||
"y2zeroaxis" "ydtics" "ymtics" "ytics" "yzeroaxis" "zdtics" "zmtics" "ztics"
|
||
"zzeroaxis")
|
||
|
||
"List of gnuplot options which can be negated using `gnuplot-negate-option'.")
|
||
|
||
(defvar gnuplot--negatable-options-regexp
|
||
(gnuplot--make-regexp gnuplot--keywords-negatable-options))
|
||
|
||
;; Set up colorization for gnuplot.
|
||
(defvar gnuplot-font-lock-keywords
|
||
`(; stuff in brackets
|
||
("\\[\\([^]]+\\)\\]" (1 'font-lock-constant-face))
|
||
|
||
;; variable/function definitions
|
||
("\\(\\(\\sw\\|\\s_\\)+\\s-*\\((\\s-*\\(\\sw\\|\\s_\\)*\\s-*\\(,\\s-*\\sw*\\)*\\s-*)\\)?\\s-*=\\)[^=]"
|
||
(1 'font-lock-variable-name-face))
|
||
|
||
;; built-in function names
|
||
(,(gnuplot--make-regexp gnuplot--keywords-builtin-functions)
|
||
(0 'font-lock-function-name-face))
|
||
|
||
;; reserved words associated with plotting
|
||
(,(gnuplot--make-regexp gnuplot--keywords-plotting)
|
||
(0 'font-lock-type-face))
|
||
(,(gnuplot--make-regexp gnuplot--keywords-plotting-styles)
|
||
(0 'font-lock-function-name-face))
|
||
|
||
;; (s)plot -- also thing (s)plotted
|
||
("\\<s?plot\\>" (0 'font-lock-keyword-face))
|
||
;; ("\\<s?plot\\s-+\\([^'\" ]+\\)[) \n,\\\\]"
|
||
;; (1 'font-lock-variable-name-face))
|
||
|
||
;; other common commands
|
||
(,(gnuplot--make-regexp gnuplot--keywords-misc)
|
||
(0 'font-lock-constant-face))
|
||
("!.*$" (0 'font-lock-constant-face))))
|
||
|
||
(defvar gnuplot-font-lock-defaults
|
||
'(gnuplot-font-lock-keywords
|
||
nil ; Use syntactic fontification
|
||
t ; Use case folding
|
||
nil ; No extra syntax
|
||
;; calls `gnuplot--beginning-of-continuation'
|
||
;; to find a safe place to begin syntactic highlighting
|
||
beginning-of-defun))
|
||
|
||
;; Some corner cases in Gnuplot's comment and string syntax are
|
||
;; difficult to handle accurately using Emacs's built-in syntax tables
|
||
;; and parser:
|
||
;;
|
||
;; - strings can continue over several lines, but only by using a
|
||
;; backslash to escape the newline
|
||
;;
|
||
;; - double-quoted strings can contain escaped quotes, \", and escaped
|
||
;; backslashes, \\; but in single-quoted strings the quote is
|
||
;; escaped by doubling it, '', and backslash is only special at
|
||
;; end-of-line
|
||
;;
|
||
;; - either type of string can end at newline without needing a
|
||
;; - closing delimiter
|
||
;;
|
||
;; - comments continue over continuation lines
|
||
;;
|
||
;; The following syntax-propertize rules should accurately mark string
|
||
;; and comment boundaries using the "generic string fence" and
|
||
;; "generic comment fence" syntax properties.
|
||
(defalias 'gnuplot--syntax-propertize
|
||
(syntax-propertize-rules
|
||
;; Double quoted strings
|
||
((rx
|
||
(group "\"")
|
||
(* (or (seq "\\" anything)
|
||
(not (any "\"" "\n"))))
|
||
(group (or "\"" "\n" buffer-end)))
|
||
(1 "|") (2 "|"))
|
||
|
||
;; Single quoted strings
|
||
((rx
|
||
(group "'")
|
||
(* (or (seq "\\" "\n")
|
||
"''"
|
||
(not (any "'" "\n"))))
|
||
(group (or "'" "\n" buffer-end)))
|
||
(1 "|") (2 "|"))
|
||
|
||
;; Comments
|
||
((rx
|
||
(group "#")
|
||
(* (or (seq "\\" "\n")
|
||
any))
|
||
(or (group "\n") buffer-end))
|
||
(1 "!") (2 "!"))))
|
||
|
||
(defun gnuplot--syntax-propertize-extend-region (start end)
|
||
"Expand the region to `syntax-propertize' for strings and comments.
|
||
|
||
Region range is START to END.
|
||
Ensures that the region being searched begins and ends outside of
|
||
any lines continued with a backslash.
|
||
|
||
This function is added to `syntax-propertize-extend-region-functions'
|
||
in `gnuplot-mode' buffers."
|
||
(let ((continuation-start
|
||
(min start
|
||
(gnuplot--point-at-beginning-of-continuation start)))
|
||
(continuation-end
|
||
(max end
|
||
(gnuplot--point-at-end-of-continuation end))))
|
||
(if (and (= continuation-start start)
|
||
(= continuation-end end))
|
||
nil
|
||
(cons continuation-start continuation-end))))
|
||
|
||
;; Parsing utilities to tell if we are inside a string or comment
|
||
(defun gnuplot--in-string (&optional where)
|
||
"Return non-nil if the text at WHERE is within a string.
|
||
|
||
If WHERE is omitted, defaults to text at point.
|
||
This is a simple wrapper for `syntax-ppss'."
|
||
(save-excursion
|
||
(let ((parse-state (syntax-ppss where)))
|
||
(nth 3 parse-state))))
|
||
|
||
(defun gnuplot--in-comment (&optional where)
|
||
"Return non-nil if the text at WHERE is within a comment.
|
||
|
||
If WHERE is omitted, defaults to text at point.
|
||
This is a simple wrapper for `syntax-ppss'."
|
||
(save-excursion
|
||
(let ((parse-state (syntax-ppss where)))
|
||
(nth 4 parse-state))))
|
||
|
||
(defun gnuplot--in-string-or-comment (&optional where)
|
||
"Return non-nil if the text at WHERE is within a string or comment.
|
||
|
||
If WHERE is omitted, defaults to text at point.
|
||
This is a simple wrapper for `syntax-ppss'."
|
||
|
||
(save-excursion
|
||
(let ((parse-state (syntax-ppss where)))
|
||
(or (nth 3 parse-state)
|
||
(nth 4 parse-state)))))
|
||
|
||
|
||
;;; --- functions for sending commands to gnuplot
|
||
|
||
(defun gnuplot--split-string (string)
|
||
"Break STRING at each carriage return, returning a list of lines."
|
||
(let ((list ()) (line "") (index 0))
|
||
(while (< index (length string))
|
||
(if (char-equal (elt string index) ?\n)
|
||
(setq list (append list (list line))
|
||
line "")
|
||
(setq line (concat line (char-to-string (elt string index)))))
|
||
(setq index (1+ index)))
|
||
list))
|
||
|
||
;; -- the calls to `sleep-for' are to allow enough time for gnuplot
|
||
;; to write to the buffer before the next line is inserted
|
||
;; -- note that the input string is split into lines and each line is
|
||
;; sent to gnuplot individually. this is a bit slow, but it puts
|
||
;; each line on the comint history.
|
||
(defun gnuplot-send-string-to-gnuplot (string text)
|
||
"Sends STRING to the gnuplot program.
|
||
If no gnuplot process exists, a new one is created. TEXT indicates
|
||
the type of text being sent to gnuplot and is typically one of
|
||
nil, `line', `region', `buffer', or `file'. TEXT may be useful for
|
||
functions in `gnuplot-after-plot-hook'. `gnuplot-after-plot-hook' is
|
||
called by this function after all of STRING is sent to gnuplot."
|
||
(gnuplot--make-comint-buffer) ; make sure a gnuplot buffer exists
|
||
(setq gnuplot--comint-recent-buffer (current-buffer))
|
||
|
||
;; Create a gnuplot frame if needed
|
||
(when (and (equal gnuplot-display-process 'frame)
|
||
(not (frame-live-p gnuplot--process-frame)))
|
||
(let ((frame (selected-frame)))
|
||
(setq gnuplot--process-frame (make-frame))
|
||
(select-frame gnuplot--process-frame)
|
||
(switch-to-buffer gnuplot-buffer)
|
||
(delete-other-windows)
|
||
(select-frame frame)))
|
||
|
||
(let ((list (gnuplot--split-string string)))
|
||
(with-current-buffer (get-buffer gnuplot-buffer)
|
||
(goto-char (point-max))
|
||
;; bruce asks: what is this next line for?
|
||
(set-marker (process-mark gnuplot-process) (point-marker))
|
||
(sleep-for (* 10 gnuplot-delay))
|
||
(while list
|
||
(insert (car list))
|
||
(comint-send-input)
|
||
(sleep-for gnuplot-delay)
|
||
(setq list (cdr list))
|
||
(goto-char (point-max))))
|
||
|
||
(cond ((equal gnuplot-display-process 'window)
|
||
(gnuplot--display-and-recenter-comint-buffer))
|
||
((equal gnuplot-display-process 'frame)
|
||
;;(raise-frame gnuplot--process-frame)
|
||
(with-selected-frame gnuplot--process-frame
|
||
(gnuplot--display-and-recenter-comint-buffer))))
|
||
|
||
(setq gnuplot-recently-sent text)
|
||
(run-hooks 'gnuplot-after-plot-hook)))
|
||
|
||
(defun gnuplot--display-and-recenter-comint-buffer ()
|
||
"Make sure the gnuplot comint buffer is displayed.
|
||
Move point to the end if necessary."
|
||
(save-selected-window
|
||
(select-window (display-buffer (get-buffer gnuplot-buffer)))
|
||
(goto-char (point-max))
|
||
(unless (pos-visible-in-window-p (point) (selected-window)) (recenter 5))))
|
||
|
||
(defun gnuplot-send-region-to-gnuplot (&optional begin end text)
|
||
"Sends a selected region to the gnuplot program.
|
||
If BEGIN and END are not specified, point and mark are used. TEXT
|
||
indicates the type of text being sent to gnuplot. This will be
|
||
`region' unless explicitly set by a function calling this one. Other
|
||
typical values are of nil, `line', `buffer', or `file'. TEXT may be
|
||
useful for function in `gnuplot-after-plot-hook'."
|
||
(interactive "r" gnuplot-mode)
|
||
(let (string (txt (or text 'region)))
|
||
(setq string (buffer-substring-no-properties begin end))
|
||
(unless (equal (substring string -1) "\n")
|
||
(setq string (concat string "\n")))
|
||
(gnuplot-send-string-to-gnuplot string txt)))
|
||
|
||
(defun gnuplot-send-line-to-gnuplot ()
|
||
"Sends the current line to the gnuplot program.
|
||
Respects continuation lines.
|
||
This sets `gnuplot-recently-sent' to `line'."
|
||
(interactive nil gnuplot-mode)
|
||
(let (start end)
|
||
(save-excursion
|
||
;; go to start of continued command, or beginning of line
|
||
;; if this is not a continuation of a previous line
|
||
(gnuplot--beginning-of-continuation)
|
||
(setq start (point))
|
||
(end-of-line)
|
||
(while (save-excursion
|
||
(backward-char)
|
||
(looking-at "\\\\")) ; go to end of last continuation line
|
||
(end-of-line 2))
|
||
(beginning-of-line 2)
|
||
(setq end (point)))
|
||
(unless (string-match "\\`\\s-*\\'"
|
||
(buffer-substring-no-properties start end))
|
||
(gnuplot-send-region-to-gnuplot start end 'line))
|
||
end))
|
||
|
||
;; I chose a very easy to type but slightly non-mnemonic key-binding
|
||
;; for this (C-c C-v). It seems like the kind of thing one would want
|
||
;; to do repeatedly without incurring RSI. 8^)
|
||
(defun gnuplot-send-line-and-forward (&optional num)
|
||
"Call `gnuplot-send-line-to-gnuplot' and move forward 1 line.
|
||
You can use a numeric prefix to send more than one line. Blank lines and
|
||
lines with only comments are skipped when moving forward.
|
||
NUM is optional arg."
|
||
(interactive "p" gnuplot-mode)
|
||
(let (end)
|
||
(while (> num 0)
|
||
(setq end (gnuplot-send-line-to-gnuplot))
|
||
(goto-char end)
|
||
(backward-char 1)
|
||
(gnuplot-forward-script-line 1)
|
||
(setq num (1- num)))))
|
||
|
||
(defun gnuplot-send-line-and-newline ()
|
||
"Call `gnuplot-send-line-to-gnuplot' and insert a new line."
|
||
(interactive nil gnuplot-mode)
|
||
(end-of-line)
|
||
(gnuplot-send-line-to-gnuplot)
|
||
(insert "\n"))
|
||
|
||
(defun gnuplot-forward-script-line (&optional num)
|
||
"Move forward my NUM script lines.
|
||
Blank lines and commented lines are not included in the NUM count."
|
||
(interactive "p" gnuplot-mode)
|
||
(while (> num 0)
|
||
(and (not (eobp)) (forward-line 1))
|
||
(while (and (not (eobp))
|
||
(or (looking-at "^\\s-*$")
|
||
(looking-at "^\\s-*#")))
|
||
(forward-line 1))
|
||
(setq num (1- num))))
|
||
|
||
(defun gnuplot-send-buffer-to-gnuplot ()
|
||
"Sends the entire buffer to the gnuplot program.
|
||
This sets `gnuplot-recently-sent' to `buffer'."
|
||
(interactive nil gnuplot-mode)
|
||
(gnuplot-send-region-to-gnuplot (point-min) (point-max) 'buffer))
|
||
|
||
(defun gnuplot-send-file-to-gnuplot ()
|
||
"Sends a selected file to the gnuplot program using the \"load\" command.
|
||
This sets `gnuplot-recently-sent' to `file'."
|
||
(interactive)
|
||
(let ((string (read-file-name "Name of file to send to gnuplot > " nil nil t)))
|
||
(setq string (concat "load '" (expand-file-name string) "'\n"))
|
||
(message "%S" string)
|
||
(gnuplot--make-comint-buffer) ; make sure a gnuplot buffer exists
|
||
(gnuplot-send-string-to-gnuplot string 'file)))
|
||
|
||
(defun gnuplot-plot-from-comint ()
|
||
"Send the contents of a script to gnuplot from the process buffer.
|
||
This inserts the contents of the most recently used gnuplot script
|
||
into the process buffer and sends those lines to gnuplot. It does
|
||
this by copying the script line by line."
|
||
(interactive nil gnuplot-comint-mode)
|
||
(unless (buffer-live-p gnuplot--comint-recent-buffer)
|
||
(error "Script buffer has been deleted"))
|
||
(let (string list (buffer (current-buffer)))
|
||
(set-buffer gnuplot--comint-recent-buffer)
|
||
(setq string (buffer-substring-no-properties (point-min) (point-max))
|
||
string (concat string "\n")
|
||
list (gnuplot--split-string string))
|
||
(set-buffer buffer)
|
||
(while list
|
||
(insert (car list))
|
||
(comint-send-input)
|
||
(sleep-for gnuplot-delay)
|
||
(setq list (cdr list)))
|
||
(comint-send-input)))
|
||
|
||
(defun gnuplot-save-and-plot-from-comint ()
|
||
"Send a current script to gnuplot from the process buffer.
|
||
This sends the most recently used gnuplot script to gnuplot using the
|
||
\"load\" command. This function first saves the script buffer to a
|
||
file, prompting for a filename if one is not associated with the script
|
||
buffer. Then it sends a load command to gnuplot using the name of the
|
||
file visited by the script buffer."
|
||
(interactive nil gnuplot-comint-mode)
|
||
(unless (buffer-live-p gnuplot--comint-recent-buffer)
|
||
(error "Script buffer has been deleted"))
|
||
(let (fname)
|
||
(with-current-buffer gnuplot--comint-recent-buffer
|
||
(save-buffer)
|
||
(setq fname (buffer-file-name)))
|
||
(goto-char (point-max))
|
||
(insert (format "load '%s'" fname))
|
||
(comint-send-input)))
|
||
|
||
(defun gnuplot-pop-to-recent-buffer ()
|
||
"Switch to the most recently-plotted gnuplot script buffer."
|
||
(interactive)
|
||
(when (buffer-live-p gnuplot--comint-recent-buffer)
|
||
(pop-to-buffer gnuplot--comint-recent-buffer)))
|
||
|
||
(defun gnuplot-trim-comint-buffer ()
|
||
"Trim lines from the beginning of the *gnuplot* buffer.
|
||
This keeps that buffer from growing excessively in size. Normally,
|
||
this function is attached to `gnuplot-after-plot-hook'"
|
||
(when (> gnuplot-buffer-max-size 0)
|
||
(with-current-buffer gnuplot-buffer
|
||
(let ((gnuplot-lines (count-lines (point-min) (point-max))))
|
||
(dotimes (_n (- gnuplot-lines gnuplot-buffer-max-size))
|
||
(goto-char (point-min))
|
||
(delete-region (line-beginning-position) (1+ (line-end-position))))
|
||
(goto-char (point-max))))))
|
||
|
||
|
||
;;; --- functions controlling the gnuplot process
|
||
|
||
(defvar-keymap gnuplot-comint-mode-map
|
||
:doc "Keymap used by `gnuplot-comint-mode'."
|
||
:parent comint-mode-map
|
||
"C-M-p" #'gnuplot-plot-from-comint
|
||
"C-M-f" #'gnuplot-save-and-plot-from-comint
|
||
"C-d" #'gnuplot-delchar-or-maybe-eof
|
||
"M-TAB" #'completion-at-point
|
||
"C-c C-d" #'gnuplot-info-lookup-symbol
|
||
"C-c C-i" #'gnuplot-insert-filename
|
||
"C-c C-n" #'gnuplot-negate-option
|
||
"C-c C-z" #'gnuplot-customize
|
||
"C-c C-e" #'gnuplot-pop-to-recent-buffer)
|
||
|
||
(easy-menu-define
|
||
gnuplot-comint-mode-menu gnuplot-comint-mode-map
|
||
"Menu used in `gnuplot-comint-mode'."
|
||
`("Gnuplot"
|
||
["Plot most recent gnuplot buffer" gnuplot-plot-from-comint
|
||
(buffer-live-p gnuplot--comint-recent-buffer)]
|
||
["Save and plot most recent gnuplot buffer" gnuplot-save-and-plot-from-comint
|
||
(buffer-live-p gnuplot--comint-recent-buffer)]
|
||
"---"
|
||
,gnuplot--display-options-menu
|
||
["Contextual completion and help" gnuplot-context-sensitive-mode
|
||
:style toggle
|
||
:selected gnuplot-context-sensitive-mode]
|
||
["Echo area help (eldoc-mode)" eldoc-mode
|
||
:active gnuplot-context-sensitive-mode
|
||
:style toggle
|
||
:selected eldoc-mode]
|
||
"---"
|
||
["Insert filename at point" gnuplot-insert-filename t]
|
||
["Negate set option" gnuplot-negate-option t]
|
||
["Keyword help" gnuplot-info-lookup-symbol]
|
||
["Quick help for thing at point" gnuplot-context-help-at-point
|
||
gnuplot-context-sensitive-mode]
|
||
["Info documentation on thing at point"
|
||
gnuplot-context-info-at-point
|
||
gnuplot-context-sensitive-mode]
|
||
["Switch to recent gnuplot script buffer" gnuplot-pop-to-recent-buffer
|
||
(buffer-live-p gnuplot--comint-recent-buffer)]
|
||
"---"
|
||
["Customize gnuplot" gnuplot-customize t]
|
||
"---"
|
||
["Kill gnuplot" gnuplot-kill-comint-buffer t]))
|
||
|
||
;; Major mode `gnuplot-comint-mode' for the interaction buffer
|
||
(define-derived-mode gnuplot-comint-mode comint-mode "Gnuplot interaction"
|
||
"Major mode for interacting with a gnuplot process in a buffer.
|
||
|
||
This sets font-lock and keyword completion in the comint/gnuplot
|
||
buffer."
|
||
:interactive nil
|
||
:syntax-table gnuplot-mode-syntax-table
|
||
:abbrev-table gnuplot-mode-abbrev-table
|
||
|
||
(setq-local font-lock-defaults gnuplot-font-lock-defaults
|
||
parse-sexp-lookup-properties t
|
||
syntax-propertize-function #'gnuplot--syntax-propertize)
|
||
|
||
(add-hook 'kill-buffer-hook #'gnuplot--close-down nil t)
|
||
(add-hook 'comint-output-filter-functions
|
||
#'comint-postoutput-scroll-to-bottom
|
||
nil t)
|
||
(add-hook 'comint-output-filter-functions
|
||
#'gnuplot--protect-prompt-fn
|
||
nil t)
|
||
(add-hook 'completion-at-point-functions #'gnuplot-completion-at-point-info-look nil t))
|
||
|
||
(defun gnuplot--make-comint-buffer ()
|
||
"Switch to the gnuplot program buffer or create one if none exists."
|
||
(unless (and gnuplot-process (eq (process-status gnuplot-process) 'run)
|
||
(buffer-live-p gnuplot-buffer))
|
||
(setq gnuplot-buffer (apply #'make-comint gnuplot-process-name gnuplot-program nil
|
||
(and gnuplot-program-args (split-string gnuplot-program-args)))
|
||
gnuplot-process (get-buffer-process gnuplot-buffer))
|
||
(set-process-query-on-exit-flag gnuplot-process nil)
|
||
(with-current-buffer gnuplot-buffer
|
||
(gnuplot-comint-mode)
|
||
(when gnuplot-inline-image-mode
|
||
(sleep-for (* 10 gnuplot-delay))
|
||
(gnuplot--setup-comint-for-image-mode)))))
|
||
|
||
(defvar gnuplot--prompt-regexp
|
||
(regexp-opt '("gnuplot> " "multiplot> "))
|
||
"Regexp for recognizing the GNUPLOT prompt.")
|
||
|
||
(defun gnuplot--protect-prompt-fn (_string)
|
||
"Prevent the Gnuplot prompt from being deleted or overwritten.
|
||
STRING is the text as originally inserted in the comint buffer."
|
||
(save-excursion
|
||
(goto-char (point-max))
|
||
(beginning-of-line)
|
||
(let ((b (point)) e)
|
||
(when (re-search-forward gnuplot--prompt-regexp (point-max) t)
|
||
(setq e (point))
|
||
(put-text-property b e 'rear-nonsticky '(read-only intangible face))
|
||
(put-text-property b e 'intangible t)
|
||
;;(put-text-property b e 'read-only t)
|
||
))))
|
||
|
||
(defun gnuplot--close-down ()
|
||
"Tidy up when deleting the gnuplot buffer."
|
||
(if (and gnuplot-process
|
||
(eq (process-status gnuplot-process) 'run))
|
||
(kill-process gnuplot-process))
|
||
(setq gnuplot-process nil
|
||
gnuplot-buffer nil))
|
||
|
||
(defun gnuplot-delchar-or-maybe-eof (arg)
|
||
"Delete ARG characters forward, or (if at eob) send an EOF to subprocess.
|
||
This is very similar to `comint-delchar-or-maybe-eof'."
|
||
(interactive "p" gnuplot-comint-mode)
|
||
(if (eobp)
|
||
(gnuplot-kill-comint-buffer)
|
||
(delete-char arg)))
|
||
|
||
(defun gnuplot-kill-comint-buffer ()
|
||
"Kill the gnuplot process and its display buffers."
|
||
(interactive)
|
||
(if (and gnuplot-process
|
||
(eq (process-status gnuplot-process) 'run))
|
||
(kill-process gnuplot-process))
|
||
(when (and gnuplot-buffer (get-buffer gnuplot-buffer))
|
||
(if (one-window-p) ()
|
||
(delete-window (get-buffer-window gnuplot-buffer)))
|
||
(kill-buffer gnuplot-buffer))
|
||
(setq gnuplot-process nil
|
||
gnuplot-buffer nil))
|
||
|
||
(defun gnuplot-show-comint-buffer ()
|
||
"Switch to the buffer containing the gnuplot process.
|
||
When `gnuplot-display-process' is nil this will switch to
|
||
the gnuplot process buffer. When that variable is non-nil, the
|
||
gnuplot process buffer will be displayed in a window."
|
||
(interactive)
|
||
(unless (and gnuplot-buffer (get-buffer gnuplot-buffer))
|
||
(gnuplot--make-comint-buffer))
|
||
(cond ((equal gnuplot-display-process 'window)
|
||
(switch-to-buffer-other-window gnuplot-buffer))
|
||
((equal gnuplot-display-process 'frame)
|
||
(or (frame-live-p gnuplot--process-frame)
|
||
(setq gnuplot--process-frame (make-frame)))
|
||
(raise-frame gnuplot--process-frame)
|
||
(select-frame gnuplot--process-frame)
|
||
(switch-to-buffer gnuplot-buffer))
|
||
(t
|
||
(switch-to-buffer gnuplot-buffer))))
|
||
|
||
|
||
;;; Support for displaying plotted images within Emacs
|
||
|
||
(defvar gnuplot--inline-image-filename nil
|
||
"Name of the current Gnuplot output file.")
|
||
|
||
(defun gnuplot-external-display-mode ()
|
||
"Display image in external."
|
||
(interactive nil gnuplot-mode gnuplot-comint-mode)
|
||
(gnuplot--set-display-mode 'gnuplot-inline-image-mode nil))
|
||
|
||
(defun gnuplot-inline-display-mode ()
|
||
"Display image in inline."
|
||
(interactive nil gnuplot-mode gnuplot-comint-mode)
|
||
(gnuplot--set-display-mode 'gnuplot-inline-image-mode 'inline))
|
||
|
||
(defun gnuplot-dedicated-display-mode ()
|
||
"Display image in dedicated."
|
||
(interactive nil gnuplot-mode gnuplot-comint-mode)
|
||
(gnuplot--set-display-mode 'gnuplot-inline-image-mode 'dedicated))
|
||
|
||
(defun gnuplot-set-image-format (format)
|
||
"Display image in FORMAT."
|
||
(interactive "sGnuplot image format: " gnuplot-mode gnuplot-comint-mode)
|
||
(gnuplot--set-display-mode 'gnuplot-image-format format)
|
||
(unless gnuplot-inline-image-mode
|
||
(message "Setting will take effect when plots are displayed in Emacs")))
|
||
|
||
(defun gnuplot--setup-comint-for-image-mode ()
|
||
"Setup comint for image."
|
||
(when (and (buffer-live-p gnuplot-buffer) (get-buffer-process gnuplot-buffer))
|
||
(with-current-buffer gnuplot-buffer
|
||
(if gnuplot-inline-image-mode
|
||
(progn
|
||
(gnuplot-send-hiding-output
|
||
(format "set terminal %s\n" gnuplot-image-format))
|
||
(gnuplot--inline-image-set-output)
|
||
(add-hook 'comint-output-filter-functions
|
||
#'gnuplot--insert-inline-image-output nil t))
|
||
(gnuplot-send-hiding-output "set terminal pop\n")
|
||
(remove-hook 'comint-output-filter-functions
|
||
#'gnuplot--insert-inline-image-output t)))))
|
||
|
||
(defun gnuplot--inline-image-set-output ()
|
||
"Set Gnuplot's output file to `gnuplot--inline-image-filename'."
|
||
(let ((tmp (make-temp-file "gnuplot")))
|
||
(setq gnuplot--inline-image-filename tmp)
|
||
(gnuplot-send-hiding-output (format "set output '%s'\n" tmp))))
|
||
|
||
(defvar gnuplot--inhibit-filter nil)
|
||
|
||
(defun gnuplot--insert-inline-image-output (_string)
|
||
"Insert Gnuplot graphical output STRING in the gnuplot-comint buffer.
|
||
|
||
Called via `comint-preoutput-filter-functions' hook when
|
||
`gnuplot-inline-image-mode' is enabled. Checks the status of the
|
||
file `gnuplot--inline-image-filename'; if it exists and has
|
||
nonzero size, inserts it as an inline image, stores a new
|
||
temporary filename in `gnuplot--inline-image-filename', and
|
||
updates Gnuplot with the appropriate \"set output\" command."
|
||
(unless gnuplot--inhibit-filter ; Prevent recursively entering this filter
|
||
(let ((gnuplot--inhibit-filter t)) ; (causing an infinite loop)
|
||
(save-excursion
|
||
(goto-char (point-max))
|
||
(beginning-of-line)
|
||
(when (looking-at gnuplot--prompt-regexp)
|
||
(let* ((filename gnuplot--inline-image-filename)
|
||
(size (nth 7 (file-attributes filename))))
|
||
(when (and size (> size 0))
|
||
(gnuplot-send-hiding-output "set output\n") ; Flush output file
|
||
(sit-for 0.1) ; Hack: wait for Gnuplot IO to finish
|
||
(cl-ecase gnuplot-inline-image-mode
|
||
((nil) nil)
|
||
(inline
|
||
(ignore-errors
|
||
(let ((image (create-image filename)))
|
||
(beginning-of-line)
|
||
(insert-image image)
|
||
(insert "\n")
|
||
(gnuplot--inline-image-set-output))))
|
||
(dedicated
|
||
(with-current-buffer (get-buffer-create gnuplot-image-buffer)
|
||
(let ((inhibit-read-only t))
|
||
(erase-buffer)
|
||
(insert-file-contents filename)
|
||
(ignore-errors (normal-mode))
|
||
(display-buffer (current-buffer))
|
||
(gnuplot--inline-image-set-output))))))))))))
|
||
|
||
(defun gnuplot-send-hiding-output (string)
|
||
"Send STRING to the running Gnuplot process invisibly."
|
||
(with-current-buffer gnuplot-buffer
|
||
(add-hook 'comint-preoutput-filter-functions
|
||
#'gnuplot--discard-output nil t))
|
||
(with-current-buffer (get-buffer-create gnuplot-hidden-output-buffer)
|
||
(erase-buffer))
|
||
(comint-send-string (get-buffer-process gnuplot-buffer) string))
|
||
|
||
(defun gnuplot--discard-output (string)
|
||
"Temporary preoutput filter for hiding Gnuplot output & prompt.
|
||
Accumulates output STRING in a buffer until it finds the next prompt,
|
||
then removes itself from `comint-preoutput-filter-functions'."
|
||
(with-current-buffer
|
||
(get-buffer-create gnuplot-hidden-output-buffer)
|
||
(insert string)
|
||
(when (looking-back gnuplot--prompt-regexp (point-min))
|
||
(with-current-buffer gnuplot-buffer
|
||
(remove-hook 'comint-preoutput-filter-functions
|
||
#'gnuplot--discard-output t))))
|
||
"")
|
||
|
||
|
||
;;; --- miscellaneous functions: insert file name, indentation, negation
|
||
|
||
(defun gnuplot-insert-filename ()
|
||
"Insert a filename at point, prompting for name in the minibuffer.
|
||
This inserts a filename relative to the buffer's default directory.
|
||
Uses completion and the value of `gnuplot-quote-character'.
|
||
Bound to \\[gnuplot-insert-filename]"
|
||
(interactive nil gnuplot-mode gnuplot-comint-mode)
|
||
(insert gnuplot-quote-character
|
||
(file-relative-name (read-file-name "Filename > " "")
|
||
default-directory)
|
||
gnuplot-quote-character))
|
||
|
||
;; Adjust indentation for the line containing point
|
||
(defun gnuplot-indent-line ()
|
||
"Set indentation in gnuplot buffer.
|
||
For most lines, set indentation to previous level of indentation.
|
||
Add additional indentation for continuation lines."
|
||
(interactive nil gnuplot-mode)
|
||
(let (indent)
|
||
(if (gnuplot--in-string (line-beginning-position))
|
||
;; Continued strings begin at left margin
|
||
(setq indent 0)
|
||
(save-excursion
|
||
(if (gnuplot--continuation-line-p)
|
||
;; This is a continuation line. Indent to the same level as
|
||
;; the second word on the line beginning this command (i.e.,
|
||
;; the first non-whitespace character after whitespace)
|
||
(progn
|
||
(gnuplot--beginning-of-continuation)
|
||
(back-to-indentation)
|
||
(re-search-forward "\\S-+\\s-+" (line-end-position) 'end-at-limit)
|
||
(setq indent (current-column)))
|
||
|
||
;; Not a continuation line; indent according to block
|
||
;; nesting depth
|
||
(save-excursion
|
||
(condition-case nil
|
||
(progn
|
||
(beginning-of-line)
|
||
(skip-syntax-forward "-" (line-end-position))
|
||
(if (looking-at "\\s)") (forward-char))
|
||
(backward-up-list)
|
||
(gnuplot--beginning-of-continuation)
|
||
(setq indent (+ gnuplot-basic-offset (current-indentation))))
|
||
(error
|
||
(setq indent 0)))))))
|
||
|
||
;; Set indentation
|
||
(save-excursion
|
||
(indent-line-to indent))
|
||
|
||
;; Move point after indentation when at beginning of line
|
||
(when (< (current-column) indent)
|
||
(move-to-column indent))))
|
||
|
||
(defun gnuplot-electric-insert (BRACE)
|
||
"Adjust indentation on inserting a close BRACE.
|
||
The blink-paren fix is stolen from cc-mode"
|
||
(interactive "*p" gnuplot-mode)
|
||
(let ((old-blink-paren blink-paren-function)
|
||
(blink-paren-function nil))
|
||
(self-insert-command BRACE)
|
||
(gnuplot-indent-line)
|
||
(when old-blink-paren (funcall old-blink-paren))))
|
||
|
||
;;
|
||
;; Functions for finding the start and end of continuation blocks
|
||
;;
|
||
|
||
;; Check if line containing point is a continuation
|
||
(defun gnuplot--continuation-line-p ()
|
||
"Return t if the line containing point is a continuation of the previous line."
|
||
(save-excursion
|
||
(condition-case ()
|
||
(progn
|
||
(end-of-line 0)
|
||
(backward-char)
|
||
(looking-at "\\\\"))
|
||
(error nil))))
|
||
|
||
;; Move point to start of continuation block
|
||
(defun gnuplot--beginning-of-continuation ()
|
||
"Move point to the beginning of the continuation lines containing point.
|
||
|
||
If not in a continuation line, move point to beginning of line."
|
||
(beginning-of-line)
|
||
(while (gnuplot--continuation-line-p)
|
||
(beginning-of-line 0)))
|
||
|
||
;; Move point to end of continuation block
|
||
(defun gnuplot--end-of-continuation ()
|
||
"Move point to the end of the continuation lines containing point.
|
||
|
||
If there are no continuation lines, move point to `end-of-line'."
|
||
(end-of-line)
|
||
(unless (bobp)
|
||
(catch 'eob
|
||
(while (save-excursion (backward-char)
|
||
(looking-at "\\\\"))
|
||
(end-of-line 2)
|
||
(if (eobp) (throw 'eob nil))))))
|
||
|
||
;; Save-excursion wrappers for the above to return point at beginning
|
||
;; or end of continuation
|
||
(defun gnuplot--point-at-beginning-of-continuation (&optional pos)
|
||
"Return value of point at beginning of the continued block containing point.
|
||
|
||
If there are no continuation lines, returns `line-beginning-position'.
|
||
If specify POS, move POS befere execution."
|
||
(save-excursion
|
||
(when pos (goto-char pos))
|
||
(gnuplot--beginning-of-continuation)
|
||
(point)))
|
||
|
||
(defun gnuplot--point-at-end-of-continuation (&optional pos)
|
||
"Return value of point at the end of the continued block containing point.
|
||
|
||
If there are no continuation lines, returns `line-end-position'.
|
||
If specify POS, move POS before execution."
|
||
(save-excursion
|
||
(when pos (goto-char pos))
|
||
(gnuplot--end-of-continuation)
|
||
(point)))
|
||
|
||
(defun gnuplot--beginning-of-defun (&optional arg)
|
||
"We also treat a block of continuation lines as a `defun'.
|
||
ARG is optional arg."
|
||
(unless arg (setq arg 1))
|
||
(if (> arg 0)
|
||
(catch 'bob ; go to beginning of ARGth prev. defun
|
||
(dotimes (_n arg)
|
||
(when (= (point)
|
||
(gnuplot--point-at-beginning-of-continuation))
|
||
(forward-line -1)
|
||
(if (bobp) (throw 'bob t))
|
||
(while (looking-at "^\\s-*$")
|
||
(forward-line -1)
|
||
(if (bobp) (throw 'bob t))))
|
||
(gnuplot--beginning-of-continuation))
|
||
t)
|
||
|
||
(catch 'eob ; find beginning of (-ARG)th following defun
|
||
(dotimes (_n (- arg))
|
||
(gnuplot--end-of-continuation)
|
||
(forward-line)
|
||
(if (eobp) (throw 'eob t))
|
||
(while (looking-at "^\\s-*$")
|
||
(forward-line)
|
||
(if (eobp) (throw 'eob t)))))))
|
||
|
||
;; Movement to start or end of command, including multiple commands
|
||
;; separated by semicolons
|
||
(defun gnuplot--beginning-of-command ()
|
||
"Move point to beginning of command containing point."
|
||
(let ((limit (gnuplot--point-at-beginning-of-continuation)))
|
||
(while
|
||
(and
|
||
(search-backward ";" limit 'lim)
|
||
(gnuplot--in-string-or-comment)))
|
||
(skip-chars-forward ";")
|
||
(skip-syntax-forward "-")))
|
||
|
||
(defun gnuplot--end-of-command ()
|
||
"Move point to end of command containing point."
|
||
(let ((limit (gnuplot--point-at-end-of-continuation)))
|
||
(while
|
||
(and
|
||
(search-forward ";" limit 'lim)
|
||
(gnuplot--in-string-or-comment)))
|
||
(skip-chars-backward ";")
|
||
(skip-syntax-backward "-")))
|
||
|
||
(defun gnuplot--point-at-beginning-of-command ()
|
||
"Return position at the beginning of command containing point."
|
||
(save-excursion (gnuplot--beginning-of-command) (point)))
|
||
|
||
(defun gnuplot--point-at-end-of-command ()
|
||
"Return position at the end of command containing point."
|
||
(save-excursion (gnuplot--end-of-command) (point)))
|
||
|
||
(defun gnuplot-negate-option ()
|
||
"Append \"no\" to or remove \"no\" from the set option on the current line.
|
||
This checks if the set option is one which has a negated form.
|
||
|
||
Negatable options are defined in `gnuplot--keywords-negatable-options'."
|
||
(interactive nil gnuplot-mode gnuplot-comint-mode)
|
||
(let ((begin (gnuplot--point-at-beginning-of-command))
|
||
(end (gnuplot--point-at-end-of-command))
|
||
(regex gnuplot--negatable-options-regexp))
|
||
(save-excursion
|
||
(goto-char begin)
|
||
(skip-syntax-forward "-" end)
|
||
(if (looking-at "\\(un\\)?set\\s-+")
|
||
(cond ((looking-at "unset")
|
||
(delete-char 2))
|
||
((looking-at (concat "set\\s-+\\(" regex "\\)"))
|
||
(insert "un"))
|
||
(t
|
||
(message "There is not a negatable set option on this line")))
|
||
(message "There is not a set option on this line")))))
|
||
|
||
(defun gnuplot-customize ()
|
||
"Customize `gnuplot-mode'."
|
||
(interactive nil gnuplot-mode gnuplot-comint-mode)
|
||
(customize-group "gnuplot"))
|
||
|
||
|
||
;;; --- help from the info file, keyword list + completion, insert function
|
||
|
||
(defun gnuplot--setup-info-look ()
|
||
"Setup info-look in the gnuplot buffer.
|
||
Also set the variable `gnuplot--info-keywords'."
|
||
;; TODO Update info layout
|
||
(let ((doc-spec
|
||
'(("(gnuplot)Command_Index" nil "[_a-zA-Z0-9]+")
|
||
("(gnuplot)Options_Index" nil "[_a-zA-Z0-9]+")
|
||
("(gnuplot)Function_Index" nil "[_a-zA-Z0-9]+")
|
||
("(gnuplot)Terminal_Index" nil "[_a-zA-Z0-9]+"))))
|
||
(info-lookup-add-help
|
||
:mode 'gnuplot-mode :topic 'symbol
|
||
:regexp "[a-zA-Z][_a-zA-Z0-9]*"
|
||
:doc-spec doc-spec)
|
||
(info-lookup-add-help
|
||
:mode 'gnuplot-comint-mode :topic 'symbol
|
||
:regexp "[a-zA-Z][_a-zA-Z0-9]*"
|
||
:doc-spec doc-spec))
|
||
|
||
(let ((there (bufferp (get-buffer "*info*"))))
|
||
(info-lookup-setup-mode 'symbol 'gnuplot-mode)
|
||
(or there (and (get-buffer "*info*") (kill-buffer "*info*")))
|
||
;; why are these buffers here? I think that the general
|
||
;; user will not want them lying around
|
||
(and (get-buffer "info dir") (kill-buffer "info dir"))
|
||
(and (get-buffer "info dir<2>") (kill-buffer "info dir<2>")))
|
||
(setq gnuplot--info-keywords (gnuplot--set-keywords-list)))
|
||
|
||
(defun gnuplot--set-keywords-list ()
|
||
"Set `gnuplot--info-keywords' from `info-lookup-cache'.
|
||
Return a list of keywords."
|
||
(let* ((list (cdr (assoc 'symbol info-lookup-cache)))
|
||
(list (cdr (cdr (assoc 'gnuplot-mode list))))
|
||
(list (car list))
|
||
(store ()) item)
|
||
(while list
|
||
(setq item (car (car list))
|
||
item (format "%s" item) ; keep this line for the sake of
|
||
store (append (list item) store) ; info-look.el w/o my patch
|
||
list (cdr list)))
|
||
(delete "nil" store)
|
||
store ))
|
||
|
||
|
||
;;;; Completion at point and Eldoc.
|
||
|
||
;; There are two alternative completion-at-point mechanisms: the old
|
||
;; one using info-look and the new one (enabled by default) which
|
||
;; parses the command line to provide smarter completions.
|
||
|
||
;; Older completion method using info-look
|
||
(defun gnuplot-completion-at-point-info-look ()
|
||
"Return completions of keyword preceding point.
|
||
|
||
Uses the cache of keywords generated by `info-lookup'. See
|
||
`gnuplot--setup-info-look'. If non-nil, the return value is in the form
|
||
\(BEGIN END COMPLETIONS) where BEGIN and END are buffer
|
||
positions and COMPLETIONS is a list."
|
||
|
||
(when (eq gnuplot--info-keywords 'pending)
|
||
(gnuplot--setup-info-look))
|
||
(list (condition-case _err
|
||
(save-excursion (backward-sexp 1) (point))
|
||
(error (point)))
|
||
(point) gnuplot--info-keywords))
|
||
|
||
|
||
(defun gnuplot-info-lookup-symbol (symbol &optional mode)
|
||
"Wrapper for `info-lookup-symbol'.
|
||
Takes SYMBOL and MODE as arguments exactly as
|
||
`info-lookup-symbol'. After doing the info lookup, calls
|
||
`gnuplot--adjust-info-display' to display the info buffer
|
||
according to the value of `gnuplot-info-display'."
|
||
(interactive
|
||
(progn
|
||
(when (eq gnuplot--info-keywords 'pending)
|
||
(gnuplot--setup-info-look))
|
||
(info-lookup-interactive-arguments 'symbol))
|
||
gnuplot-mode gnuplot-comint-mode)
|
||
(when (eq gnuplot--info-keywords 'pending)
|
||
(gnuplot--setup-info-look))
|
||
(unless symbol (setq symbol "Commands"))
|
||
(save-window-excursion
|
||
(info-lookup-symbol symbol mode))
|
||
(gnuplot--adjust-info-display))
|
||
|
||
(defun gnuplot--adjust-info-display ()
|
||
"Displays the *info* buffer in a window or frame.
|
||
Specified by the value of `gnuplot-info-display'.
|
||
If `gnuplot-info-display' is `window', then the window will be
|
||
shrunk to the size of the info entry if it is smaller than half
|
||
the height of the frame.
|
||
|
||
The *info* buffer should already exist when this function is
|
||
called."
|
||
(cl-case gnuplot-info-display
|
||
(window
|
||
(switch-to-buffer-other-window "*info*")
|
||
;; Adjust window height only if the frame is split
|
||
;; horizontally, so as not to mess up the minibuffer
|
||
;; we can't use shrink-window-if-larger-than-buffer here
|
||
;; because it doesn't work with Info mode's narrowing
|
||
(with-selected-window (get-buffer-window "*info*")
|
||
(unless (window-full-height-p)
|
||
(enlarge-window
|
||
(min (- (count-lines (point-min) (point-max)) (window-height) -1)
|
||
(- (/ (frame-height) 2) (window-height)))))))
|
||
|
||
(frame
|
||
(unless (frame-live-p gnuplot--info-frame)
|
||
(setq gnuplot--info-frame (make-frame)))
|
||
(select-frame gnuplot--info-frame)
|
||
(raise-frame gnuplot--info-frame)
|
||
(switch-to-buffer "*info*"))
|
||
|
||
(t
|
||
(switch-to-buffer "*info*"))))
|
||
|
||
(defun gnuplot-insert (string)
|
||
"Insert STRING at point and display help for for STRING.
|
||
Help is not shown if `gnuplot-insertions-show-help-flag' is nil. The
|
||
help shown is for STRING unless STRING begins with the word \"set\" or
|
||
\"show\", in which case help is shown for the thing being set or
|
||
shown."
|
||
(insert string)
|
||
(let ((topic string) term)
|
||
(when (string-match
|
||
"\\(set\\|show\\)[ \t]+\\([^ \t]+\\)\\(\\s-+\\([^ \t]+\\)\\)?"
|
||
string)
|
||
(setq topic (downcase (match-string 2 string))
|
||
term (match-string 4 string))
|
||
(if (equal topic "terminal") (setq topic (downcase term))))
|
||
(cond ((bound-and-true-p gnuplot-gui-popup-flag)
|
||
(gnuplot-gui-set-options-and-insert))
|
||
(gnuplot-insertions-show-help-flag
|
||
(when (eq gnuplot--info-keywords 'pending)
|
||
(gnuplot--setup-info-look))
|
||
(gnuplot-info-lookup-symbol topic)))))
|
||
|
||
(defun gnuplot-toggle-info-display ()
|
||
"Toggle info display."
|
||
(interactive nil gnuplot-mode)
|
||
(setq gnuplot-insertions-show-help-flag (not gnuplot-insertions-show-help-flag))
|
||
(message (if gnuplot-insertions-show-help-flag
|
||
"Help will be displayed after insertions."
|
||
"Help no longer displayed after insertions.")))
|
||
|
||
(defun gnuplot--setup-insertions-menu ()
|
||
"Initial setup of insertions menu."
|
||
(when (and gnuplot-insertions-menu-flag (not gnuplot--insertions-menu))
|
||
(easy-menu-define gnuplot--insertions-menu gnuplot-mode-map
|
||
"Insertions menu used in Gnuplot-mode"
|
||
`("Insertions"
|
||
,@gnuplot-insertions-top
|
||
,gnuplot-insertions-adornments
|
||
,gnuplot-insertions-plot-options
|
||
,gnuplot-insertions-terminal
|
||
,gnuplot-insertions-x-axis
|
||
,gnuplot-insertions-y-axis
|
||
,gnuplot-insertions-z-axis
|
||
,gnuplot-insertions-x2-axis
|
||
,gnuplot-insertions-y2-axis
|
||
,gnuplot-insertions-parametric-plots
|
||
,gnuplot-insertions-polar-plots
|
||
,gnuplot-insertions-surface-plots
|
||
,@gnuplot-insertions-bottom))))
|
||
|
||
(defun gnuplot--mark-active ()
|
||
"Return non-nil if the mark is active and it is not equal to point."
|
||
(condition-case nil
|
||
(and (mark) (/= (mark) (point)))
|
||
(error nil)))
|
||
|
||
|
||
;;; --- autoloaded functions: gnuplot-mode and gnuplot-make-buffer
|
||
|
||
;;;###autoload
|
||
(define-derived-mode gnuplot-mode prog-mode "Gnuplot"
|
||
"Major mode for editing and executing GNUPLOT scripts.
|
||
This was written with version 4.6 of gnuplot in mind, but should
|
||
work with newer and older versions.
|
||
|
||
Report bugs at https://github.com/emacs-gnuplot/gnuplot/issues
|
||
|
||
------O------
|
||
|
||
Gnuplot-mode includes two different systems for keyword completion and
|
||
documentation lookup: a newer one, `gnuplot-context-sensitive-mode' ,
|
||
which is enabled by default, and a older one which extracts keywords
|
||
from gnuplot's Info file. Both systems allow looking up documentation
|
||
in the Info file. With the context-sensitive mode active,
|
||
`gnuplot-mode' can also provide Eldoc syntax hints as you type.
|
||
|
||
------O------
|
||
|
||
There are several known shortcomings of `gnuplot-mode', version 0.5g
|
||
and up. Many of the shortcomings involve the graphical interface
|
||
\(refered to as the GUI) to setting arguments to plot options. Here is
|
||
a list:
|
||
|
||
1. Currently there is no way for `gnuplot-mode' to know if information
|
||
sent to gnuplot was correctly plotted.
|
||
2. \"plot\", \"splot\", and \"fit\" are handled in the GUI, but are
|
||
a bit flaky. Their arguments may not be read correctly from
|
||
existing text, and continuation lines (common for plot and splot)
|
||
are not supported.
|
||
3. The GUI does not know how to read from continuation lines.
|
||
4. Comma separated position arguments to plot options are
|
||
unsupported in the GUI. Colon separated datafile modifiers (used
|
||
for plot, splot, and fit) are not supported either. Arguments
|
||
not yet supported by the GUI generate messages printed in grey
|
||
text.
|
||
5. The GUI handling of \"hidden3d\" is flaky and \"cntrparam\" is
|
||
unsupported."
|
||
(setq-local comment-start "# "
|
||
comment-end ""
|
||
comment-column 32
|
||
comment-start-skip "#[ \t]*"
|
||
indent-line-function #'gnuplot-indent-line
|
||
beginning-of-defun-function #'gnuplot--beginning-of-defun
|
||
end-of-defun-function #'gnuplot--end-of-continuation
|
||
syntax-propertize-function #'gnuplot--syntax-propertize
|
||
font-lock-defaults gnuplot-font-lock-defaults
|
||
font-lock-multiline t
|
||
parse-sexp-lookup-properties t
|
||
comint-process-echoes gnuplot-echo-command-line-flag)
|
||
(add-hook 'completion-at-point-functions #'gnuplot-completion-at-point-info-look nil t)
|
||
(add-hook 'syntax-propertize-extend-region-functions
|
||
#'gnuplot--syntax-propertize-extend-region nil t)
|
||
(setq gnuplot--comint-recent-buffer (current-buffer))
|
||
(gnuplot--setup-insertions-menu))
|
||
|
||
;;;###autoload
|
||
(defun gnuplot-make-buffer ()
|
||
"Open a new buffer in `gnuplot-mode'.
|
||
When invoked, it switches to a new, empty buffer visiting no file
|
||
and then starts `gnuplot-mode'.
|
||
|
||
It is convenient to bind this function to a global key sequence. For
|
||
example, to make the F10 key open a gnuplot script buffer, put the
|
||
following in your .emacs file:
|
||
(global-set-key [(f10)] \\='gnuplot-make-buffer)"
|
||
(interactive)
|
||
(switch-to-buffer gnuplot-gnuplot-buffer)
|
||
(gnuplot-mode))
|
||
|
||
;;;###autoload
|
||
(defun run-gnuplot ()
|
||
"Run an inferior Gnuplot process."
|
||
(interactive)
|
||
(gnuplot-show-comint-buffer))
|
||
|
||
;;;###autoload
|
||
(progn
|
||
(add-to-list 'auto-mode-alist '("\\.gp\\'" . gnuplot-mode))
|
||
(add-to-list 'interpreter-mode-alist '("gnuplot" . gnuplot-mode)))
|
||
|
||
(provide 'gnuplot)
|
||
;;; gnuplot.el ends here
|