Files
emacs/lisp/apdl-mode/apdl-mode.el
2025-12-25 11:44:13 +01:00

3640 lines
141 KiB
EmacsLisp

;;; apdl-mode.el --- Major mode for the scripting language APDL -*- lexical-binding: t -*-
;; Copyright (C) 2006 - 2025 H. Dieter Wilhelm GPL V3
;; Author: H. Dieter Wilhelm <dieter@duenenhof-wilhelm.de>
;; Package-Version: 20250508.908
;; Package-Revision: 4883ab085811
;; Package-Requires: ((emacs "25.1"))
;; Keywords: languages, convenience, tools, Ansys, APDL
;; URL: https://github.com/dieter-wilhelm/apdl-mode
;; Maintainer: H. Dieter Wilhelm
;; Parts of this mode were originally base on octave-mod.el: Copyright
;; (C) 1997 Free Software Foundation, Inc. Author: Kurt Hornik
;; <Kurt.Hornik@wu-wien.ac.at> Author: John Eaton
;; <jwe@bevo.che.wisc.edu>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; This code is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published
;; by the Free Software Foundation; either version 3, or (at your
;; option) any later version.
;;
;; This 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.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Commentary:
;; The GNU-Emacs major mode for the programming language APDL
;; APDL (Ansys Parametric Design Language) is the solver scripting
;; language of the FEA (Finite Element Analysis) suite Ansys (ANalysis
;; SYStem, registered TM https://www.ansys.com).
;; APDL-Mode (formerly ANSYS-Mode) represents, in conjunction with the
;; GNU-Emacs editor, an advanced APDL environment with features like
;; keyword completion, code templates, solver communication (GNU-Linux
;; only), license reporting, dedicated keybindings, etc.
;; Nowadays - with the advent of modern GUIs - I find APDL-Mode also
;; useful for studying solver (.dat) files which were created by
;; WorkBench. Likewise for writing WorkBench `Command' snippets and
;; inspecting longer snippets from other sources. Accessing swiftly the
;; Ansys APDL reference documentation alone is worth using APDL-Mode!
;; ------------------------------
;; First usage:
;; Please type `M-x apdl' to open a buffer under APDL-Mode. From this
;; buffer you can investigate the menu entries `APDL' and `Ansys' and
;; testing some APDL code.
;; The APDL-Mode help you'll find with typing `C-c C-h' together with a
;; brief tutorial.
;;; History:
;; Created: 2006-02
;; Please check the accompanying NEWS.org.
;;; Code:
(require 'apdl-keyword)
(require 'apdl-initialise)
(require 'apdl-process)
(require 'apdl-template)
(require 'apdl-wb-template)
(require 'outline)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; --- constants ---
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defconst apdl-parameter-substitution-commands-regexp
"/TITLE\\|/STITLE\\|/COM\\|/AXLAB\\|/GCOLUMN\\|/TLABEL\\|/AN3D"
"Regexp of command names which have a string behind them.")
(defconst apdl-string-commands-regexp
"C\\*\\*\\*\\|/TITLE\\|/STITLE\\|/COM\\|/AXLAB\\|\
/GCOLUMN\\|/TLABEL\\|\\*ABBR\\|/AN3D"
"Regexp of command names which have a string behind them.")
(defconst apdl-variable-defining-commands ; association list
'(
;; some math apdl commands like *KRON or *MULT define new
;; variables, but not at the front of their argument list! -> not
;; implemented
("\\*ask\\w*" . "*ASK")
("\\<cm\\>" . "CM")
("\\<cmblock\\w*" . "CMBLOCK")
("\\*dim\\w*"."\\*DIM")
("/dir\\w*" . "/DIRECTORY")
("\\*dmat\\w*" . "*DMAT") ;math apdl
("\\*do\\>" . "\\*DO")
("\\*dow\\w*" . "\\*DOWHILE")
("\\*get\\w*". "\\*GET")
("/inq\\w*"."/INQUIRE")
("\\*mfu\\w*"."*MFUN")
("\\*mop\\w*"."*MOPER")
("\\<path\\w*"."PATH")
("\\<page\\w*" "PAGET")
("\\<pdef\\w*"."PDEF")
("\\*sma\\w*" . "*SMAT") ; math apdl
("\\*sre\\w*"."*SREAD")
("\\*set.?"."*SET") ; Ansys inconsistency *SET works only with one
; additional character
("\\*top\\w*"."*TOPER")
("\\*vec\\w*" . "*VEC") ; math apdl
("\\*vge\\w*"."*VGET") ; Not true in 14.0 variable must be
; dimensiond with *dim
("\\*vfu\\w*"."*VFUN")
("\\*vit\\w*"."*VITRP")
("\\*vop\\w*"."*VOPER")
("\\*vsc\\w*"."*VSCFUN")
("\\*vfi\\w*"."*vfill"))
"Alist for commands which define user variables.
In the form of (regexp . command_string), intentionally excluded
is the \"=\" assignment command.")
(defconst apdl-use-variables
'("ARG[1-9]" "AR[1][0-9]")
"Variable containing the APDL *USE variables regexp.
ARG[1-9] and AR[1][0-9] are macro local variables and can be
passed to the *USE command. Additionally AR[2-9][0-9] are pure
macro local variables.")
(defconst apdl-format-commands-regexp
"\\*[mM][sS][gG]\\|\\*[vV][rR][eE]\\|\\*[vV][wW][rR]\\|\\*[mM][wW][rR]"
"Regexp of command names which have one or more format lines.")
(defconst apdl-maintainer-address
"Dieter Wilhelm <dieter@duenenhof-wilhelm.de>" ; bug-gnu-emacs@gnu.org
"Address of current maintainer of the APDL-Mode.")
(defconst apdl-comment-char ?!
"The APDL comment character.")
;; \sCODE,code
;; -:whitespace
;; <:commentstart
;; whitespace +
;; $
;; comment
;; digits
;; "^\\s-*\\($\\|\\s<\\|[+[:digit:]-]\\)"
(defconst apdl-non-code-line-regexp "^\\s-*\\($\\|\\s<\\|[+[:digit:]-]\\)"
"Regexp indicating a comment -, number - or an empty line.
A comment line contrasting a \"code comment\" which follows code
to be analysed from the Ansys solver/interpreter. A \"number
line\" is a line beginning with a number e. g. from an element
block or with a `+' or `-' sign.")
(defconst apdl-condensed-input-line-regexp ".*\\$"
"Regexp indicating a condensed input line.")
(defconst apdl-comment-start-skip "\\S<+\\S-*"
"Regexp to match the start of an APDL comment up to its body.
Used for the variable `comment-start-skip'.")
;; --- defcustoms ---
(require 'custom)
(defgroup APDL nil
"Customisation group for the APDL-Mode."
:version "20.5.0"
:link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
:link '(url-link :tag "Online documentation"
"https://dieter-wilhelm.github.io/apdl-mode ")
:link '(url-link :tag "Code on GitHub"
"https://github.com/dieter-wilhelm/apdl-mode")
:group 'Languages)
;; two minutes was too long, 2021-08-12
(defcustom apdl-parameter-help-duration "30"
"Duration for showing the `apdl-show-command-parameters' overlay.
The value is a string expressing a relative time span like \"2
hours 35 minutes\" or a number of seconds (\"30\") from now.
Acceptable time formats are those recognised by the function
`timer-duration'."
:type '(string number)
:group 'APDL)
(defcustom apdl-hide-region-before-string "![ ... hidden"
"String to mark the beginning of an invisible region.
This string is not really placed in the text, it is just shown in an
overlay"
:type '(string)
:group 'hide-region)
(defcustom apdl-hide-region-after-string " region ... ]"
"String to mark the beginning of an invisible region.
This string is not really placed in the text, it is just shown in an overlay"
:type '(string)
:group 'hide-region)
(defcustom apdl-hide-region-propertize-markers t
"If non-nil, add text properties (colour) to the region markers."
:type 'boolean
:group 'hide-region)
(defcustom apdl-highlighting-level 2
"This variable sets the level of highlighting.
There are three levels available, please see the variable
`font-lock-maximum-decoration'. Level 0 means a minimalist level
optimised for speed and working with very large files (like
solver input files from WorkBench), 1 and 2. Level 0 highlights
only the minimum (unambiguous) length of APDL command names and
variable definitions with the '=' operator. Level 1 highlights
complete command names, together with functions, elements,
deprecated elements, undocumented commands, strings from string
commands and the APDL operators. Level 2 is the same as 1,
except that all defined user variables and unambiguous command
names (also interpreter-ignored characters behind them) are
highlighted as well. The user variables are highlighted
\"statically\" only, newly defined variables are only taken into
account after `apdl-display-variables'
\(\\[apdl-display-variables]) is called, this updating is done
dynamically i. e. during editing when the variable
`apdl-dynamic-highlighting-flag' is set to t."
:type 'integer
:group 'APDL
:link '(variable-link 'font-lock-maximum-decoration))
;; link is only linked in the customisation buffer, sadly not it's
;; documentation string!
(defcustom apdl-dynamic-highlighting-flag t
"Non-nil means that APDL-Mode highlights user defined variables.
Warning: This option is computational expensive and --depending
on the file size and your hardware --it might make your editing
experience rather sluggish. Currently dynamic highlighting of
user variables is only implemented for files with the extensions
either \".mac\" \".inp\" or \".ans\". To take effect after
setting this variable you might have to restart `apdl-mode'."
:type 'boolean
:group 'APDL)
(defcustom apdl-indicate-empty-lines-flag nil
"Non-nil means indicate empty lines on window systems.
Do this visually at the end of an APDL buffer in the left
fringe. You have to reload function `apdl-mode' for this
variable to take effect."
:type 'boolean
:group 'APDL)
(defcustom apdl-comment-padding " "
"Padding string that `comment-dwim' puts between comment chars and text.
Extra spacing between the comment character(s) and the comment
text makes the comment easier to read. This padding is not
effective for code comments (comments behind code)."
:type 'string
:group 'APDL)
(defcustom apdl-comment-add 1
"How many additional comment characters are inserted by \\[comment-dwim].
This determines the default value of the numeric argument of
`comment-dwim'. It should generally stay 0, except for a few
modes like Lisp where it can be convenient to set it to 1 so that
regions are commented with two semi-colons."
:type 'integer
:group 'APDL)
;; nowadays (2021-08-16) 25 seems ugly and disconnected to the code
(defcustom apdl-code-comment-column 15
"Column where APDL code comments (behind code) are placed."
:type 'integer
:group 'APDL)
(defcustom apdl-auto-indent-flag t
"Non-nil means indent line when typing the SPC key.
The space character is also inserted."
:type 'boolean
;; :options '(t nil) ; not necessary with boolean in Customise
:group 'APDL)
(defcustom apdl-indent-comment-suffix ""
"String placed after the APDL comment char in an code comment.
See `apdl-indent-comment-string'."
:type 'string
:group 'APDL)
(defcustom apdl-ruler-wide-flag nil
"Non-nil means show a 80 characters wide temporary ruler.
Nil means show a narrower temporary ruler with 50 characters."
:type 'boolean
:group 'APDL)
(defcustom apdl-require-spaces-flag nil
"Non-nil means \\[insert-parentheses] inserts whitespace before ().
When there is a region marked then function `insert-parentheses'
inserts the parentheses around the active region."
:type 'boolean
:group 'APDL)
(defcustom apdl-blink-matching-block-flag t
"Non-nil means blinking of matching APDL block keywords.
Skip temporary to the matching beginning of the block when
inserting a newline after an *ELSE or *END keyword."
:type 'boolean
:group 'APDL)
(defcustom apdl-blink-matching-delay .7
"Time in seconds for skipping to a matching block.
See also the variable `apdl-blink-matching-block-flag'."
:type 'number
:group 'APDL)
(defcustom apdl-block-offset 2
"Indentation column(s) for statements in a block structure."
:type 'integer
;; :options only for types hook, plist and alist
:group 'APDL)
(defcustom apdl-outline-string "@"
"String specifying outline headings (see `outline-regexp').
Together with the Ansys comment sign '!' at a line beginning.
Per default, the outline heading looks like '!@', subheadings
'!@@' and so forth."
:type 'string
:group 'APDL)
(defcustom apdl-mode-hook '(apdl-outline-minor-mode)
"Normal hook run before entering APDL-Mode.
A hook is a variable which holds a collection of functions."
:type 'hook
:options '(apdl-show-paren-mode apdl-outline-minor-mode
apdl-ruler-mode apdl-auto-insert-mode)
:group 'APDL)
(require 'align)
(defcustom apdl-align-rules-list
'(
(apdl-align-=
(regexp . "\\(\\s-*\\)=")
(modes . '(apdl-mode))
(justify . t)
(tab-stop . nil))
(apdl-align-text-column
(regexp . "=\\(\\s-*[0-9]+\\|\\s-*\\)")
(modes . '(apdl-mode))
(justify . t)
(tab-stop . nil))
(apdl-align-comment
(regexp . "[0-9.)]+\\(\\s-*\\)\\!")
(modes . '(apdl-mode))
(tab-stop . nil)))
"Rules for aligning APDL variable definitions."
:type align-rules-list-type
:group 'apdl-mode)
;; (put 'my-align-rules-list 'risky-local-variable t)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; --- variables ---
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar apdl-overlay-str ""
"Variable to store previous overlay string.")
(defvar apdl-hide-region-overlays nil
"Variable to store the regions we put an overlay on.")
(defvar apdl-help-overlay nil
"Overlay for displaying the Ansys parameter help.")
(defvar apdl-timer nil
"Timer variable to set up a timer for overlay clearing.
Please have a look at the function `apdl-manage-overlay'.")
(defvar apdl-indent-comment-string
(concat (char-to-string apdl-comment-char) apdl-indent-comment-suffix)
"String to insert when creating an APDL code comment.")
(defvar apdl-user-variables nil
"Variable containing the user variables and line No of first occurrence.
The list is used for the display of these
variables (`apdl-display-variables').")
(defvar apdl-user-variable-regexp nil
"Variable containing the user variables regexp.
The regexp is used for the
fontification (`apdl-highlight-variable') of these variables.")
(defvar apdl-is-unix-system-flag nil
"Non-nil means the computer runs a Unix system.
Any of GNU-Linux, aix, berkeley-unix, hpux, irix, lynxos 3.0.1 or
usg-unix-v.")
(defvar apdl-previous-major-mode ""
"The buffer's previous major mode (before APDL-Mode).")
(defvar apdl-mode-abbrev-table nil
"Abbreviation definition table for the APDL-Mode.
All APDL abbrevs start with a grave accent \"`\". \"`?\" lists
the currently defined abbreviations.")
(defvar apdl-parameter-help-position) ; for the compiler
(defvar-local apdl-parameter-help-position 1
"Cursor position in -show-command-parameters.")
;;; --- constants ---
(defconst apdl-continuation-line-regexp ".*?&\\s-*$"
"Regexp indicating a continuation line (of the *MSG command).")
(defconst apdl-else-keywords
'("\\*[eE][lL][sS][eE][iI][fF]" "\\*[eE][lL][sS][eE]"
"\\*[cC][yY][cC][lL][eE]")
"Regexps describing APDL block else keywords.")
(defconst apdl-end-keywords
'("\\*[eE][nN][dD][dD][oO]" "\\*[eE][nN][dD][iI][fF]"
"\\*[eE][nN][dD]")
"Regexps describing APDL end keywords.")
(defconst apdl-number-line-regexp
"^\\s-*[(+-]?[[:digit:]]"
"Regexp describing an APDL number line.
Used for skipping pure number lines and CMBLOCK format strings")
(defconst apdl-block-else-regexp
(concat "\\("
(mapconcat #'identity apdl-else-keywords "\\|")
"\\)\\>")
"Regexp containing the APDL else keywords.")
(defconst apdl-block-end-regexp
(concat "\\("
(mapconcat #'identity apdl-end-keywords "\\|")
"\\)\\>")
"Regexp containing the APDL end keywords.")
(defconst apdl-block-begin-or-end-regexp
(concat apdl-block-begin-regexp "\\|" apdl-block-end-regexp)
"Regexp containing APDL begin and end keywords.")
(defconst apdl-block-else-or-end-regexp
(concat apdl-block-else-regexp "\\|" apdl-block-end-regexp)
"Regexp containing the APDL else or end keywords.")
(defconst apdl-block-match-alist
'(("*IF" . ("THEN" "*ELSE" "*ELSEIF" "*ENDIF"))
("*DO" . ("*ENDDO"))
("*DOWHILE" . ("*ENDDO"))
("*CREATE" . ("*END")))
"Alist with APDL's matching block keywords.
It has APDL's begin keywords as keys and a list of the
corresponding else or end keywords as associated values.")
(defconst apdl-column-ruler-wide
(propertize
(concat
"0 10 20 30 40 50 60 \
70 80\n"
"| | | | | | | | | | | | | | \
| | |\n")
'font-lock-face 'bold)
"Contains the string for the wide ruler.
Ruler strings are displayed above the current line with
\\[apdl-column-ruler].")
(defconst apdl-column-ruler-narrow
(propertize
(concat
"0 10 20 30 40 50\n"
"| | | | | | | | | | |\n")
'font-lock-face 'bold)
"Narrow ruler string.
Ruler strings are displayed above the current line with \\[apdl-column-ruler].")
(when (> emacs-major-version 21) ; insert-pair C-c %
;;(add-to-list 'insert-pair-alist '(?\* ?\*)) ; why do we need **?
;; (add-to-list 'insert-pair-alist '(?\$ ?\$)) ; why do we need $$?
(add-to-list 'insert-pair-alist '(?\% ?\%)))
(defconst apdl-mode-map ;keybindings, keyboard shortcuts
(let ((map (make-sparse-keymap)))
(define-key map "`" 'apdl-abbrev-start) ; ``?' lists abbrevs
(define-key map "\M-?" 'apdl-show-command-parameters)
(define-key map "\C-\M-i" 'apdl-complete-symbol)
;; --- changed standard Emacs keybindings ---
(define-key map " " 'apdl-electric-space) ; needed for abbrevs
(define-key map "\M-j" 'apdl-indent-format-line)
(define-key map "\n" 'apdl-reindent-then-newline-and-indent)
;; end block indentation
;; --- especially interesting for continuation lines and condensed
;; --- input
(define-key map "\M-a" 'apdl-command-start)
(define-key map "\M-e" 'apdl-command-end)
;; -- adaption of mark-paragraph
(define-key map "\M-h" 'apdl-mark-paragraph)
;; --- command movement --- (like defuns), skip comments and empty
;; --- lines
(define-key map "\M-n" 'apdl-next-code-line)
(define-key map "\M-p" 'apdl-previous-code-line)
;; --- block movements ---
(define-key map "\C-\M-b" 'apdl-previous-block-start-and-conditional)
(define-key map "\C-\M-d" 'apdl-down-block)
(define-key map "\C-\M-f" 'apdl-next-block-end)
(define-key map "\C-\M-h" 'apdl-mark-block) ; formerly mark defun
(define-key map "\C-\M-n" 'apdl-skip-block-forward)
(define-key map "\C-\M-p" 'apdl-skip-block-backwards)
(define-key map "\C-\M-u" 'apdl-up-block)
;; --- further block keys ---
(define-key map "\C-c]" 'apdl-close-block)
(define-key map "\C-c}" 'apdl-number-block-end)
(define-key map "\C-c{" 'apdl-number-block-start)
;; --- pairs
(define-key map [?\M-\"] 'insert-pair)
(define-key map "\C-c[" 'insert-pair)
(define-key map "\C-c'" 'insert-pair)
(define-key map "\C-c%" 'insert-pair)
;; (define-key map [?\C-c?\C-%] 'insert-pair)
;; (define-key map [?\C-c?\C-[] 'insert-pair)
;; (define-key map [?\C-c?\C-'] 'insert-pair)
;; --- miscellaneous ---
;; for emacs < 28
(when (version< "28" emacs-version)
(define-key map (kbd "TAB")
`(menu-item "" outline-cycle
:filter ,(lambda (cmd)
(when (apdl-on-heading-p) cmd))))
(when (fboundp 'outline-cycle-buffer) ; sooth compiler version < emacs-28
(define-key map (kbd "<backtab>") #'outline-cycle-buffer)))
;; above is not set by outline-minor-mode!! Borrowed from
;; outline.el emacs-28.1
(define-key map [?\C-c?\C-+] 'apdl-zoom-in)
(define-key map [?\C-c?\C--] 'apdl-zoom-out)
(define-key map [?\C-c?\C-<] 'apdl-move-left)
(define-key map [?\C-c?\C->] 'apdl-move-right)
(define-key map [?\C-c?\C-^] 'apdl-move-up)
(define-key map [?\C-c?\C-_] 'apdl-move-down)
(define-key map "\C-x4k" 'apdl-delete-other-window)
(define-key map "\C-c\C-a" 'apdl-align)
(define-key map "\C-c\C-b" 'apdl-browse-apdl-help)
(define-key map "\C-c\C-c" 'apdl-send-to-ansys)
(define-key map "\C-c\C-d" 'apdl-do)
(define-key map "\C-c\C-e" 'apdl-display-error-file)
(define-key map "\C-c\C-f" 'apdl-fit)
;; (define-key map "\C-c\C-g" 'apdl-start-graphics) ; reserved
(define-key map "\C-c\C-h" 'apdl-mode-help) ; reserved, C-h no
;; (define-key map "\C-c\C-i" 'apdl-iso-view) ; reserved: C-tab
;; (define-key map "\C-c\C-i" 'apdl-if)
(define-key map "\C-c\C-j" 'apdl-send-to-apdl-and-proceed) ; same as ESS
;; was: (define-key map "\C-c\C-j" (if (boundp 'apdl-job) 'apdl-job))
(define-key map "\C-c\C-k" 'apdl-kill-ansys)
(define-key map "\C-c\C-l" 'apdl-license-status)
(define-key map "\C-c\C-m" 'apdl-start-ansys) ; == C-c RET!!
(define-key map "\C-c\C-n" 'apdl-no-of-processors)
(define-key map "\C-c\C-o" 'apdl-display-out-file)
(define-key map "\C-c\C-p" 'apdl-start-pzr-box) ; pan-zoom-rotate
(define-key map "\C-c\C-q" 'apdl-query-apdl-command)
(define-key map "\C-c\C-r" 'apdl-replot)
(define-key map "\C-c\C-s" 'apdl-display-skeleton)
(define-key map "\C-c\C-t" 'apdl-license)
(define-key map "\C-c\C-u" 'apdl-copy-or-send-above)
(define-key map "\C-c\C-v" 'apdl-display-variables)
(define-key map "\C-c\C-w" 'apdl-display-wb-skeleton) ; or aim:
; runwb2--aim?
(define-key map "\C-c\C-x" 'apdl-start-classics)
(define-key map "\C-c\C-y" 'apdl-start-batch-run)
;; (define-key map "\C-c\C-z" 'apdl-start-anslic_admin)
;; redundant with C-c C-l
(define-key map "\C-c\C-z" 'apdl-user-license-status)
;; (define-key map "\C-c\C-z" 'apdl-start-aim)
;; (define-key map [f1] 'describe-mode) ; [f1] reserved for user
map)
"Keymap for the APDL-Mode.")
;; borrowed from outline.el 2021-09
(defun apdl-on-heading-p (&optional invisible-ok)
"Return t if point is on a (visible) heading line.
If INVISIBLE-OK is non-nil, an invisible heading line is ok too."
(save-excursion
(beginning-of-line)
(and (bolp) (or invisible-ok (not (outline-invisible-p)))
(looking-at outline-regexp))))
(defun apdl-toggle-mode nil ; -FIXME- this toggles also all ansys
; minor-hooks?
"Restore the buffer's previous major mode, if possible."
(interactive)
(if (or (string= apdl-previous-major-mode "apdl-mode")
(string= apdl-previous-major-mode ""))
(error "There was no previous major mode except \"APDL-Mode\"")
;; buffers opened with auto-mode
(funcall apdl-previous-major-mode)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- font locking stuff ---
(defvar apdl-command-regexp)
(defvar apdl-command-regexp)
(defvar apdl-deprecated-element-regexp)
(defvar apdl-undocumented-command-regexp)
(defvar apdl-get-function-regexp)
(defvar apdl-command-regexp-1)
(defvar apdl-command-regexp-2a)
(defvar apdl-command-regexp-2b)
(defvar apdl-command-regexp-2c)
(defvar apdl-element-regexp)
(defvar apdl-parametric-function-regexp)
(defvar apdl-dynamic-prompt)
(defvar apdl-completions)
(defface apdl-arg-face
'((((min-colors 88) (class color) (background light))
:foreground "red1")
(((class color) (background light))
:foreground "red")
(((min-colors 88) (class color) (background dark))
:foreground "yellow1")
(((class color) (background dark))
:foreground "yellow")
(t
:weight bold))
"Face for highlighting local variables AR(G), _return, ..."
:group 'apdl-faces)
(defvar apdl-arg-face 'apdl-arg-face
"Face name to use for local vars AR(G), _return, ...")
(let (;; = variable defs + reserved _names
;; we need something behind the = otherwise it's a cleanup
;; variables + reserved _names (max. 32 chars long)
(variable_r
"^\\s-*\\([[:alpha:]_][[:alnum:]_]\\{0,31\\}\\)\\s-*=")
;; reserved vars consisting of a single "_" are valid in Ansys 12.1
(reserved_vars_r
"\\_<\\(_[[:alnum:]_]\\{0,31\\}\\>\\)"))
;; font-lock-keyword-face is the default face
(defconst apdl-font-lock-keywords
`(
(,variable_r 1 font-lock-variable-name-face); overwriting commands
(,(concat "\\(?:^\\|\\$\\)\\s-*\\("
apdl-command-regexp
"\\)") 1 font-lock-keyword-face)))
(defconst apdl-font-lock-keywords-1
`(
;; /eof is special: it crashes Ansys in interactive mode
;; -TODO- /eof is highlighted only first in line not behind $
("\\(?:^\\|\\$\\)\\s-*\\(/[eE][oO][fF].*\\)" 1 'trailing-whitespace t)
;; deprecated ansys * comment with 12.1 fini * bla : returns "* no
;; longer valid as comment character - please use !" * bla :
;; returns a warning *bla is not a command bla = 3 * 4 : returns
;; still 3!
("[[:alnum:]_]+\\s-+\\(\\*.*$\\)" 1 font-lock-comment-face prepend)
;; ^[:alnum:] to avoid spurious
;; asterisk command fontification
;; some string faces
("\\(?:^\\|\\$\\)\\s-*\\(?:/TIT\\|/TITL\\|/TITLE\\)\\s-*,\\(.*\\)$" 1
font-lock-doc-face t) ; titles
("\\(?:^\\|\\$\\)\\s-*/[cC][oO][mM].?\\(.\\{0,75\\}\\)"
1 font-lock-doc-face t)
;; highlight message of comment command /COM (no comment (!)
;; is possible behind /COM), no separating comma necessary
(apdl-higlight-percent-and-ampersand (0 'font-lock-type-face t))
;; /SYS command sends string to OP,no parameter substitution!
("^\\s-*/[sS][yY][sS]\\s-*,\\(.\\{1,75\\}\\)$" 1
font-lock-doc-face t)
;; TODO: c*** should get fontification from command regexp
("^\\s-*\\([cC]\\*\\*\\*\\)[ ,]?\\(.\\{1,75\\}\\)"
(1 font-lock-keyword-face t) (2 font-lock-doc-face t))
;; only 75 characters possible no separator necessary
("\\<\\(ARG[1-9]\\|AR[1][0-9]\\)\\>" . apdl-arg-face)
;; elements
(,apdl-deprecated-element-regexp . font-lock-warning-face)
(,apdl-element-regexp . font-lock-builtin-face)
;; reserved vars consisting of a single "_" are valid in A. 12.1
(,reserved_vars_r 1 font-lock-warning-face)
("_RETURN" 0 apdl-arg-face append)
;; = variable defs (with reserved _names), overwriting commands
(,variable_r 1
font-lock-variable-name-face) ; variables (max. 32 chars long)
(,(concat "\\(?:^\\|\\$\\)\\s-*\\("
apdl-undocumented-command-regexp
"\\)\\(\\w*\\)") . font-lock-constant-face)
;; get- and parametric-functions
(,(concat "\\<\\("
apdl-get-function-regexp
"\\)(") 1 font-lock-function-name-face)
(,(concat "\\<\\("
apdl-parametric-function-regexp
"\\)(") 1 font-lock-function-name-face)
;; command keywords first
(,(concat "\\(?:^\\|\\$\\)\\s-*\\("
apdl-command-regexp-1
"\\)\\>") 1 font-lock-keyword-face)
;; some operators
("\\$" . 'font-lock-type-face) ; condensed input line
(":" . 'font-lock-type-face) ; colon loops only
;; deprecated *go labels (max 8 chars including the colon) only at
;; the line beginning because they might clash with 'colon' loops
;; GOTO Labels, branching
("^\\s-*:\\([[:alnum:]_]\\{1,7\\}\\)" 1 font-lock-type-face)))
;; C-u C-x = -- describe char
;; order of execution
;; syntactic overwriting nothing fontification
;; strings and /eof overwriting syntactic fonts and command face
;; respectively
;; /eof warning: overwriting keyword face
;; * comments (must overwrite comments behind it)
;; strings in string commands
;; ?pairs of %VAR% with valid variable symbols
;; %X % with format specifier
;; *msg formatting
;; & only at line endings
;; c*** overwriting everything even %VAR%!
;; /sys command no parameter substitution
;; keep previous stuff
;; *use variables in warning face
;; = defs (overwriting commands)
;; : $ operators
;; elements
;; commands
;; experimental user variables
(defconst apdl-font-lock-keywords-2
`(
;; /eof is special: it crashes Ansys in interactive mode
;; -TODO- /eof is highlighted only first in line not behind $
("\\(?:^\\|\\$\\)\\s-*\\(/[eE][oO][fF].*\\)" 1 'trailing-whitespace t)
;; deprecated ansys * comment with 12.1 fini * bla : returns "* no
;; longer valid as comment character - please use !" * bla :
;; returns a warning *bla is not a command bla = 3 *4 : returns
;; still 3!
("[[:alnum:]_]+\\s-+\\(\\*.*$\\)" 1 font-lock-comment-face prepend)
;; ^[:alnum:] to avoid spurious
;; asterisk command fontification
;; some string faces
("\\(?:^\\|\\$\\)\\s-*\\(?:/TIT\\|/TITL\\|/TITLE\\)\\s-*,\\(.*\\)$" 1
font-lock-doc-face t) ; titles
("\\(?:^\\|\\$\\)\\s-*/[cC][oO][mM].?\\(.\\{0,75\\}\\)" 1
font-lock-doc-face t)
;; highlight message of comment command /COM (no comment (!)
;; is possible behind /COM), no separating comma necessary
;; multi line format constructs
("^\\s-*\\(?:\\*[mM][sS][gG]\\|\\*[vV][rR][eE]\\|\
\\*[vV][wW][rR]\\|\\*[mM][wW][rR]\\).*\n\\(\\(?:.*&\\s-*\n\\)+.*\\)" ; format
; constructs
(1 font-lock-doc-face t))
;; ("&\\s-*$" 0 font-lock-type-face t) ; format continuation char
;; ("%" 0 font-lock-type-face prepend) ; single % acts as a format
;; specifier and pair %.% is a parameter substitution
(apdl-higlight-percent-and-ampersand (0 'font-lock-type-face t))
;; ("%\\|&\\s-*$" (0 'font-lock-type-face t))
;; /SYS command sends string to OP,no parameter substitution!
("^\\s-*/[sS][yY][sS]\\s-*,\\(.\\{1,75\\}\\)$" 1
font-lock-doc-face t)
;; -TODO-: c*** should get fontification from command regexp
("^\\s-*\\([cC]\\*\\*\\*\\)[ ,]?\\(.\\{1,75\\}\\)"
(1 font-lock-keyword-face t) (2 font-lock-doc-face t))
;; only 75 characters possible no separator necessary
;; *use variables, local macro call arguments
;; ("\\<\\(ARG[1-9]\\|AR[1][0-9]\\)\\>" . font-lock-warning-face)
("\\<\\(ARG[1-9]\\|AR[1][0-9]\\)\\>" . apdl-arg-face)
;; elements
(,apdl-deprecated-element-regexp . font-lock-warning-face)
(,apdl-element-regexp . font-lock-builtin-face)
;; reserved vars consisting of a single "_" are valid in A. 12.1
(,reserved_vars_r 1 font-lock-warning-face)
("_RETURN" 0 apdl-arg-face append)
;; = variable defs (with reserved _names), overwriting commands
(,variable_r 1
font-lock-variable-name-face) ; variables (max. 32 chars long)
(,(concat "\\(?:^\\|\\$\\)\\s-*\\("
apdl-undocumented-command-regexp
"\\)\\(\\w*\\)") . font-lock-constant-face)
;; get- and parametric-functions
(,(concat "\\<\\("
apdl-get-function-regexp
"\\)(") 1 font-lock-function-name-face)
(,(concat "\\<\\("
apdl-parametric-function-regexp
"\\)(") 1 font-lock-function-name-face)
;; command keywords first -2a no characters appended
(,(concat "\\(?:^\\|\\$\\)\\s-*\\("
apdl-command-regexp-2a
"\\)\\>") 1 font-lock-keyword-face)
(,(concat "\\(?:^\\|\\$\\)\\s-*\\("
apdl-command-regexp-2b
"\\)\\(\\w*\\)") (1 font-lock-keyword-face)
(2 'font-lock-constant-face))
(,(concat "\\(?:^\\|\\$\\)\\s-*\\("
apdl-command-regexp-2c
"\\)\\(\\w*\\)") (1 font-lock-keyword-face)
(2 'font-lock-constant-face))
;; user variables
(apdl-highlight-variable . font-lock-variable-name-face)
;; some operators
("\\$" . 'font-lock-type-face) ; condensed input line
(":" . 'font-lock-type-face) ; colon loops only
;; deprecated *go labels (max 8 chars including the colon) only at
;; the line beginning because they might clash with 'colon' loops
;; GOTO Labels, branching
("^\\s-*:\\([[:alnum:]_]\\{1,7\\}\\)" 1 font-lock-type-face)))
;; testing
(defconst apdl-font-lock-keywords-3
'(
("%" (0 font-lock-builtin-face keep))
("^/com.*" (0 font-lock-string-face prepend))
("bla" (0 font-lock-variable-name-face prepend)))))
(defconst apdl-font-lock-keyword-list
'(
apdl-font-lock-keywords
apdl-font-lock-keywords-1
apdl-font-lock-keywords-2
;; testing
; apdl-font-lock-keywords-3
))
(defconst apdl-mode-syntax-table ; FIXME check APDL operators and
;; allowed variable characters
(let ((table (make-syntax-table)))
(modify-syntax-entry ?\r " " table)
(modify-syntax-entry ?\t " " 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) ; apdl-mode abbreviation specifier,
;; not an operator but "word".
(modify-syntax-entry ?_ "_" table) ; in APDL symbol component
(modify-syntax-entry ?: "_" table) ; APDL label specifier, not an operator
;; * and ** are operators! But we also want completion of * and / commands
;; took care about this in -complete-symbol
(modify-syntax-entry ?* "." table)
;; with algebraic operators but blink-matching- needs this
(modify-syntax-entry ?/ "." table) ; APDL slash commands
(modify-syntax-entry ?\! "<" table) ; APDL comment character
(modify-syntax-entry ?\n ">" table)
(modify-syntax-entry ?\" "w" table) ; `"' is *not* a string
; delimiter for APDL
(modify-syntax-entry ?' "\"" table); (modify-syntax-entry ?' "." table)
;; Normally APDL string delimiter, but might clash
;; with usages of genitives etc.!
(modify-syntax-entry ?~ "_" table) ; APDL connection commands,
; not an operator
table)
"Syntax table in use in `apdl-mode' buffers.")
(defconst apdl-mode-menu
(list
"APDL"
["Show the Short Command Help" apdl-show-command-parameters
:help "Display a short help for the APDL command near the
cursor with its parameters (apdl-show-command-parameters)"]
["Browse the APDL Keyword Help" apdl-browse-apdl-help
:help "Open the original APDL documentation for a command or
element name near the cursor (apdl-browse-apdl-help)"
:active (or apdl-current-ansys-version apdl-ansys-help-path)]
["Interactively Browse Keywords" (apdl-browse-apdl-help t)
:help "Complete a command, element name or other subjects and
browse its original APDL documentation
(apdl-browse-apdl-help)."
:active (or apdl-current-ansys-version apdl-ansys-help-path)]
["Browse the Ansys APDL Guide" apdl-browse-ansys-apdl-manual
:help "Read the original Ansys Parametric Design Language
Guide in a browser (apdl-browse-ansys-apdl-manual)"
;; :active (file-readable-p apdl-ansys-help-path) ; now also online :-)
]
["Browse Ansys Main Help Page" apdl-start-ansys-help-page
:help "Start the Ansys main help site
(apdl-start-ansys-help-page)."]
["Browse Ansys Customer Portal" apdl-start-ansys-customer-portal-site
:help "Start the Ansys Customer Portal site
(apdl-start-ansys-customer-portal-site)."]
"--"
["Preview Macro Template" apdl-display-skeleton
:help "Preview an APDL code template in another window"]
(list
"Insert Macro Template"
["*IF ... *ENDIF" apdl-if
:help "Insert interactively an *if .. *endif construct"]
["*DO ... *ENDDO" apdl-do
:help "Insert interactively a *do .. *enddo loop"]
["*IF ... *ELSEIF" apdl-if-then
:help "Insert interactively an *if,then .. \
(*elseif .. *else ..) *endif construct."]
["MP" apdl-mp
:help "Insert interactively an mp statement."]
["Header" apdl-skeleton-header
:help "Insert interactively the file header template"]
["Insert Pi" apdl-insert-pi
:help "Insert the variable definition \"Pi = acos(-1) !
3.1415...\" at point and indent this line."]
"--"
["Mark Paragraph" apdl-mark-paragraph
:help "Mark a paragraph, make a region out of it."]
["Comment/Un- Region" comment-dwim
:help "Comment out region or uncomment region, without a
marked region start or realign a code comment in the current
line."]
["Complete APDL Keyword" apdl-complete-symbol
:help "Complete an APDL command, element or function name"]
["Send/Copy Region or Paragraph" apdl-send-to-ansys
:label (if
(or apdl-classics-flag (apdl-process-running-p))
"Send region or paragraph to Ansys"
"Copy region or paragraph to clipboard")
:help "In case of a running solver/interpreter send marked
region or - by default - the current paragraph to the
interpreter, otherwise copy these lines to the system clipboard"]
["Copy/Send above Code to Ansys" apdl-copy-or-send-above
:label (if
(or apdl-classics-flag (apdl-process-running-p))
"Send above Code to Ansys"
"Copy above Code")
:help "Either copy the code up to the beginning of file or,
when a run is active, send it to the solver/interpreter"]
["Close Logical Block" apdl-close-block
:help "Close an open control block with the corresponding end
command"]
;; ["Insert Parentheses" insert-parentheses
;; :help "Insert a pair of parentheses enclosing marked region
;; (insert-parentheses)"] ; -FIXME- redundant, necessary for Emacs-23.1
["Align region or paragraph" apdl-align
:help "Align APDL variable definitions in a marked region or
the current paragraph (apdl-align)"]
["Display Variable Definitions" apdl-display-variables
:help "Display all user variable definitions from the current
file in another window (apdl-display-variables)"]
"--"
["Configuration" apdl-skeleton-configuration
:help "Configuration code template"]
["Get- and Fortran functions" apdl-skeleton-get-and-fortran-function
:help "Get- and Fortran functions template"]
["View Settings" apdl-skeleton-view-settings
:help "View settings like focus point, magnification, ..."]
["Coordinate Sys. Display" apdl-skeleton-coordinates
:help "Template for creating and handling coordinate
systems"]
["Working Plane Operations"
apdl-skeleton-working-plane
:help "Template for creating and handling the working
plane"]
["Multi plot Commands" apdl-skeleton-multi-plot
:help "Graphic commands which show multiple entities
simultaneously"]
["Numbering Controls"
apdl-skeleton-numbering-controls
:help "Commands for numbering and colouring model entities"]
["Symbol Controls" apdl-skeleton-symbols
:help "Graphic commands which show boundary conditions,
surface loads and other symbols"]
["Geometry/Data Import/Export"
apdl-skeleton-import-export
:help "Commands for importing and exporting data and models (e.g. IGES)"]
["Control flow constructs" apdl-skeleton-looping
:help "Commands for controlling loops (*do) and the program
flow (*if)"]
["Symmetry Expansions" apdl-skeleton-symmetry-expansion
:help "Commands for expanding the view of symmetric models
to their full view"]
["Element Definitions" apdl-skeleton-element-definition
:help "2D, 3D, Element definitions and their keyoptions"]
["Material Definitions" apdl-skeleton-material-definition
:help "Various material definitions: Steel, alu, rubber, ..."]
["Modelling" apdl-skeleton-geometry
:help "Operations for geometric modelling"]
["Meshing Controls" apdl-skeleton-meshing
:help "Meshing control commands: Shapes, sizes, ..."]
["Contact Pair Definition" apdl-skeleton-contact-definition
:help "Full definition of flexible-flexible contact pairs"]
["Rigid Contact" apdl-skeleton-contact-rigid
:help "Definition of the rigid target contact side"]
["Contact Template" apdl-skeleton-contact-template
:help "Minimal working contact example"]
["Boundary Conditions" apdl-skeleton-bc
:help "Commands for establishing boundary conditions"]
["Buckling Analysis Type" apdl-skeleton-buckling
:help "Commands for establishing a buckling analysis"]
["Listings, Information, Statistics"apdl-skeleton-information
:help "Parameter listings, graphic options, system
information, run statistics"]
["Solving" apdl-skeleton-solve
:help "Ansys solver (/solu) commands and solver options"]
["Post1 Postprocessing" apdl-skeleton-post1
:help "General postprocessor (/post1) commands"]
["Array Operations" apdl-skeleton-array
:help "Dimensioning, looping, changing array parameters"]
["Path plot operations" apdl-skeleton-path-plot
:help "Commands for establishing paths and plotting entities
on paths"]
["Output to file" apdl-skeleton-output-to-file
:help "Commands for writing data to a file"]
["Element Table Operations" apdl-skeleton-element-table
:help "Commands for establishing and manipulation element
tables"]
["Post26 Postprocessing" apdl-skeleton-post26
:help "Time history (/post26) postprocessing commands"]
["Components" apdl-skeleton-component
:help "Components (Named selections in WorkBench) template"]
["Selections" apdl-skeleton-select
:help "How to select stuff template"]
"--"
["Outline template" apdl-skeleton-outline-template
:help "Empty skeleton of the structure of an APDL simulation,
outlining headers and sections"]
["Beam template" apdl-skeleton-beam-template
:help "Insert a minimal template for a beam simulation"]
["Structural template" apdl-skeleton-structural
:help "Insert a minimal template for a structural simulation"]
["2D structural template" apdl-skeleton-2d-structural
:help "Insert a minimal template for a 2D structural simulation"]
["Contact template" apdl-skeleton-contact
:help "Insert a minimal template for a structural contact
simulation"]
["Compilation of templates" apdl-skeleton
:help "Insert a compilation of selected templates"])
["Preview WorkBench Template" apdl-display-wb-skeleton
:help "Preview an WorkBench Command (APDL) template in
another window"]
(list
"Insert WorkBench Template"
["*IF ... *ENDIF" apdl-if
:help "Insert interactively an *if .. *endif construct"]
["*DO ... *ENDDO" apdl-do
:help "Insert interactively a *do .. *enddo loop"]
["*IF ... *ELSEIF" apdl-if-then
:help "Insert interactively an *if,then .. (*elseif .. *else
..) *endif construct."]
["Do loop" apdl-wbt-do
:help "Insert a do loop."]
["Header" apdl-wbt-if
:help "Insert an if loop."]
["Insert Pi" apdl-insert-pi
:help "Insert the variable definition \"Pi = acos(-1) !
3.1415...\" at point and indent this line."]
"--"
["Post: Press-fit calclationss" apdl-wbt-post-2d-press-fit_calcs
:help "Post: Calculate the maximum torque and other
parameters from a plane stress press-fit simulation."]
["Post: /post26 harmonic results" apdl-wbt-harmonic-acceleration-result
:help "Post: /post26 harmonic acceleration results.
Visualisation and file output of frequency and vector sum
amplitude."]
["Post: /post26 general results" apdl-wbt-post26-output
:help "Post: /post26 output template"]
)
"--"
(list
"Navigate Code Lines"
["Previous Code Line" apdl-previous-code-line
:help "Goto previous apdl code line"]
["Next Code Line" apdl-next-code-line
:help "Goto next code line"]
["Beginning of (Continuation) Command" apdl-command-start
:help "Go to the beginning of the current command"]
["End of (Continuation) Command" apdl-command-end
:help "Go to the end of the current command"]
"--"
["Split Format Line at Point" apdl-indent-format-line
:help "Split current line, if in a comment continue the
comment, if in an APDL format line insert the continuation
character before splitting the line"])
(list
"Work with Logical Blocks"
["Next Block End" apdl-next-block-end
:help "Go to the end of the current or next control block
(*do, *if, ...)"]
["Previous Block Start" apdl-previous-block-start-and-conditional
:help "Go to the beginning of the current or next control
block (*do, *if, ...)"]
["Down Block" apdl-down-block
:help "Move down one control block level"]
["Up Block" apdl-up-block
:help "Move up one control block level"]
["Skip Block Forward" apdl-skip-block-forward
:help "Skip to the end of the next control block"]
["Skip Block Backwards" apdl-skip-block-backwards
:help "Skip to the beginning of previous control block"]
["Hide Number Blocks" apdl-hide-number-blocks
:help "Hide all APDL number blocks (EBLOCK, NBLOCK,
CMBLOCK)"]
["Unhide Number Blocks" apdl-unhide-number-blocks
:help "Unhide all APDL number blocks (EBLOCK, NBLOCK,
CMBLOCK)"]
["Beginning of N. Block" apdl-number-block-start
:help "Go to the beginning of an APDL number blocks
(EBLOCK, NBLOCK, CMBLOCK)"]
["End of Number Block" apdl-number-block-end
:help "Go to the end of an APDL number blocks (EBLOCK,
NBLOCK, CMBLOCK)"]
"--"
["Close Block" apdl-close-block
:help "Close the current APDL control block with the
respective closing command"]
["Mark Block" apdl-mark-block
:help "Mark the current control block"]
["Hide Region" apdl-hide-region
:help "Hide a marked region and display a hidden region
message"]
["Unhide Regions" apdl-unhide-number-blocks
:help "Unhide all hidden regions"]
["Insert Temporary Ruler" apdl-column-ruler
:help "Show a temporary ruler above the current line"])
"--"
["Mark Paragraph" apdl-mark-paragraph
:help "Mark a paragraph, make a region out of it."]
["Comment/Un- Region" comment-dwim
:help "Comment out region or uncomment region, without a
marked region start or realign a code comment in the current
line."]
["Complete APDL Keyword" apdl-complete-symbol
:help "Complete an APDL command, element or function name"]
["Send/Copy Region or Paragraph" apdl-send-to-ansys
:label (if
(or apdl-classics-flag (apdl-process-running-p))
"Send region or paragraph to Ansys"
"Copy region or paragraph to clipboard")
:help "In case of a running solver/interpreter send marked
region or - by default - the current paragraph to the
interpreter, otherwise copy these lines to the system clipboard"]
["Copy/Send above Code to Ansys" apdl-copy-or-send-above
:label (if
(or apdl-classics-flag (apdl-process-running-p))
"Send above Code to Ansys"
"Copy above Code")
:help "Either copy the code up to the beginning of file or,
when a run is active, send it to the solver/interpreter"]
["Close Logical Block" apdl-close-block
:help "Close an open control block with the corresponding end
command"]
;; ["Insert Parentheses" insert-parentheses
;; :help "Insert a pair of parentheses enclosing marked region
;; (insert-parentheses)"] ; -FIXME- redundant, necessary for Emacs-23.1
["Align region or paragraph" apdl-align
:help "Align APDL variable definitions in a marked region or
the current paragraph (apdl-align)"]
["Display Variable Definitions" apdl-display-variables
:help "Display all user variable definitions from the current
file in another window (apdl-display-variables)"]
"--"
(list
"Helper Modes"
["Ruler Mode" ruler-mode
:style toggle :selected ruler-mode
:help "Toggle display of ruler in header line (Ruler mode)."]
["Outline Minor Mode" outline-minor-mode
:style toggle :selected outline-minor-mode
:help "Outline Mode is for hiding and selectively displaying
headlines and their sub level contents"]
["Show Paren Mode" show-paren-mode :style toggle
:selected show-paren-mode
:help "Show Paren Mode highlights matching parenthesis"]
["Delete Selection Mode" delete-selection-mode
:style toggle :selected delete-selection-mode
:help
"Delete Selection Mode replaces the selection with typed
text"]
["Electric Pair Mode" electric-pair-mode
:style toggle :selected electric-pair-mode
:help
"Electric Pair Mode insert corresponding closing delimiters"
:visible (version< "24" emacs-version)])
"--"
["APDL-Mode Documentation" apdl-mode-help
:help "Display the APDL-Mode Documentation in Emacs' Info Viewer."]
["Help on APDL-Mode" describe-mode
:help "Open an Emacs window describing APDL-Mode's keybindings / shortcuts"]
["Customise APDL-Mode" (customize-group "APDL")
:help "Open a special customisation window for changing the
values and inspecting the documentation of its customisation
variables"]
["List Mode Abbreviations" (list-abbrevs t)
:help
"Display a list of all abbreviation definitions for logical
blocks"]
["Submit Bug Report" apdl-submit-bug-report
:help "Open a mail template for an APDL-Mode bug report"]
["Reload APDL-Mode" apdl-reload-apdl-mode
:help "Unloading and reloading the mode definitions for
testing purposes and restarting
apdl-mode (apdl-reload-apdl-mode), this is only active if
'apdl-mode.el' is found in Emacs' load-path!"
:active (file-exists-p "apdl-mode.el")]
"--"
["Exit APDL-Mode" apdl-toggle-mode
:help "Switch to the previous major mode of the file"
:label (concat "Exit APDL-Mode Version: " apdl-mode-version)])
"APDL menu items for APDL-Mode.")
;;
;; -------------------------- MAPDL Menu--------------------------
;;
(defconst apdl-task-menu
(list
"MAPDL"
["Specify License Server or - File" apdl-license-file
:label (if apdl-license-file
"Change License Server or - File"
"Specify License Server or - File [not set]")
;; :visible apdl-is-unix-system-flag
:help "Change the license server specification (for an
solver/interpreter run or the license status), either naming the
license server machine (with port) or the actual license file"]
;; We do not need this anywhere, any longer 2021-09!
;; ["Specify the License Interconnect Servers" apdl-ansysli-servers
;; :label (if apdl-ansysli-servers
;; "Change License Interconnect Servers"
;; "Specify License Interconnect Servers [not set]")
;; :visible apdl-is-unix-system-flag
;; :help "Change the interconnect server specification (for an
;; solver/ interpreter run)"]
["Installation Directory" apdl-ansys-install-directory
:label (if apdl-ansys-install-directory
(concat "Change the Installation Directory ["
apdl-current-ansys-version "]")
"Set the Ansys Installation Directory!")
:help "For certain functionality you need to set the
installation directory of Ansys, the path up to the version
number vXXX (apdl-ansys-install-directory)"]
;; -lmutil-program or -ansys-program
["Change MAPDL License Type" apdl-license
:label (concat "Change License Type [" apdl-license "]")
:help "Specify the license type for an solver/interpreter run
(apdl-license)"
:active (or (and apdl-lmutil-program
(file-executable-p apdl-lmutil-program)
apdl-license-file)
(and apdl-ansys-program
(file-executable-p apdl-ansys-program)
apdl-license-file))
]
["Change Job Name of Run" apdl-job
:label (concat "Change Job Name [" apdl-job "]")
;; :visible apdl-is-unix-system-flag
:help "Specify the job name for an solver/interpreter
run (apdl-job)"
:active (and apdl-ansys-program
(file-executable-p apdl-ansys-program)
apdl-license-file)
]
["Change the No of Processors" apdl-no-of-processors
:label (format "Change the Number of Processors [%d]"
apdl-no-of-processors)
;; :visible apdl-is-unix-system-flag
:help "Specify the number of processors to use for the Ansys
run definition (apdl-no-of-processors)"
:active (and apdl-ansys-program
(file-executable-p apdl-ansys-program)
apdl-license-file)]
"--"
["Start the Ansys Help Viewer" apdl-start-ansys-help
:help "Start the Ansys Help Viewer
(apdl-start-ansys-help). If there is no local help installed or
you configured online help you will be directed to the main
online help page."
;; we can start the help viewer without -license-file, v211
;; 2021-09
:active (file-executable-p apdl-ansys-help-program)]
["License Server Status" apdl-license-status
:help "Show the license server status, the number of licenses
available and used (apdl-license-status)"
:active (and apdl-lmutil-program
(file-executable-p apdl-lmutil-program)
apdl-license-file)]
["License User Status" apdl-user-license-status
:help "Show the license user status, the licenses
used (apdl-user-license-status)"
:active (and apdl-lmutil-program
(file-executable-p apdl-lmutil-program)
apdl-license-file
apdl-username)]
["Start Ansys WorkBench" apdl-start-wb
:active (and apdl-ansys-wb
(file-executable-p apdl-ansys-wb))
:help "Start Ansys WorkBench (apdl-start-wb)"]
["Ansys MAPDL Product Launcher" apdl-start-launcher
:active (and apdl-ansys-launcher
(file-executable-p apdl-ansys-launcher))
:help "Start the Ansys Mechanical APDL Product Launcher
(apdl-start-launcher)"]
["Ansys MAPDL Batch Run" apdl-start-batch-run
:active (and apdl-ansys-program
(file-executable-p apdl-ansys-program)
apdl-license-file)
:help "Start an Ansys Mechanical APDL batch run
(apdl-start-batch-run)"]
["Ansys MAPDL Classics GUI" apdl-start-classics
:active (and apdl-ansys-program
(file-executable-p apdl-ansys-program)
apdl-license-file)
;; :visible apdl-is-unix-system-flag
:help "Start the Ansys Classics MAPDL
GUI (apdl-start-classics)"]
["Start Interactive Solver/Interpreter" apdl-start-ansys
:help "Start an interactive MAPDL solver/interpreter run
under Linux (apdl-start-ansys)"
:active (and apdl-is-unix-system-flag
(file-executable-p apdl-ansys-program)
apdl-license-file
(not (apdl-process-running-p)))]
"--"
;; ;; not supported any longer 2020-03
;; ["Connect to Classics" apdl-toggle-classics
;; :label (if apdl-classics-flag
;; "Switch off sending to Classics MAPDL"
;; "Switch on sending to Classics MAPDL")
;; :active (and apdl-is-unix-system-flag (not (apdl-process-running-p)))
;; :help "Check whether an Ansys Classic is running and toggle sending output
;; to it (apdl-toggle-classics)"]
["Send/Copy Region or Paragraph" apdl-send-to-ansys
:label (if
(or apdl-classics-flag (apdl-process-running-p))
"Send region or paragraph to MAPDL"
"Copy region or paragraph to clipboard")
:help "In case of a running solver/interpreter send the
marked region or by default the current paragraph to the
interpreter, otherwise copy these lines to the system
clipboard (apdl-send-to-ansys)"]
["Send/Copy Line or Region" apdl-send-to-apdl-and-proceed
:label (if (or apdl-classics-flag (apdl-process-running-p))
"Send line or region to MAPDL"
"Copy line or region to clipboard")
:help "In case of a running solver/interpreter send the
marked region or by default the current line to the interpreter,
otherwise copy these lines to the system
clipboard (apdl-send-to-apdl-and-proceed)"]
["Copy/Send above Code to Ansys" apdl-copy-or-send-above
:label (if (or apdl-classics-flag (apdl-process-running-p))
"Send above Code to MAPDL"
"Copy above Code to clipboard")
:help "Either copy the code up to the beginning of file or,
when a run is active, send it to the
solver/interpreter (apdl-copy-or-send-above)"]
(list
"Send Graphics Command"
:active (apdl-process-running-p)
["Start Graphics Screen" apdl-start-graphics
:help "Open the graphics screen for the interactive MAPDL
mode (apdl-start-graphics)"
:active (apdl-process-running-p)]
["Start Pan/Zoom/Rot. Dialog" apdl-start-pzr-box
:help "Open the Pan/Zoom/Rotate dialog of the Ansys GUI
(apdl-start-pzr-box)"
:active (or apdl-classics-flag (apdl-process-running-p))]
["Replot" apdl-replot
:help "Replot the Ansys graphics window (apdl-replot)"
:active (or apdl-classics-flag (apdl-process-running-p))]
["Fit Graphics into screen" apdl-fit
:help "Fit the Ansys graphics into the window (apdl-fit)"
:active (or apdl-classics-flag (apdl-process-running-p))]
["Show Graphics in iso-view" apdl-iso-view
:help "Show the current Ansys graphic windows in isometric
view (apdl-iso-view)"
:active (or apdl-classics-flag (apdl-process-running-p))]
["Zoom In" apdl-zoom-in
:help "Zoom into the graphics (apdl-zoom-in)"
:active (or apdl-classics-flag (apdl-process-running-p))]
["Zoom Out" apdl-zoom-out
:help "Zoom out of the graphics (apdl-zoom-out)"
:active (or apdl-classics-flag (apdl-process-running-p))]
["Move Up" apdl-move-up
:help "Move graphics objects up (apdl-move-up)"
:active (or apdl-classics-flag (apdl-process-running-p))]
["Move Down" apdl-move-down
:help "Move graphics objects down (apdl-move-down)"
:active (or apdl-classics-flag (apdl-process-running-p))]
["Move Right" apdl-move-right
:help "Move graphics objects to the right (apdl-move-right)"
:active (or apdl-classics-flag (apdl-process-running-p))]
["Move Left" apdl-move-left
:help "Move graphics objects to the left (apdl-move-left)"
:active (or apdl-classics-flag (apdl-process-running-p))])
["Send MAPDL Command Interactively" apdl-query-apdl-command
:help "Send interactively an APDL command to a running MAPDL
solver interpreter process (apdl-query-apdl-command)"
:active (or apdl-classics-flag (apdl-process-running-p))]
"--"
["Display MAPDL Run Status" apdl-process-status
:help "Display the status of the Ansys MAPDL
solver/interpreter run (apdl-process-status)"
:active (apdl-process-running-p)]
["Display MAPDL Batch Status" apdl-batch-process-status
:help "Display the status of the Ansys MAPDL
solver/interpreter batch run (apdl-batch-process-status)"
:active (process-status apdl-batch-process)
]
["Exit MAPDL Run" apdl-exit-ansys
:help "Exit the active MAPDL solver/interpreter
run (apdl-exit-ansys)"
:visible (apdl-process-running-p)]
["Display MAPDL Out File" apdl-display-out-file
:help "Display in another window in auto-revert-tail-mode the
MAPDL out file (*.out) in the current working
directory (apdl-display-out-file)"
:active (file-readable-p (car (apdl-file-list "\\.out$")))]
["Display MAPDL Error File" apdl-display-error-file
:help "Display in another window in auto-revert-tail-mode the
MAPDL error file (*.err) in the current working
directory (apdl-display-error-file)"
:active (file-readable-p (car (apdl-file-list "\\.err$")))]
["Write MAPDL Stop File" apdl-abort-file
;; we can deactivate the locking mechanism with the env variable
;;ANSYS_LOCK=OFF :active (file-readable-p (concat
;;default-directory apdl-job ".lock"))
:help "Write a file: JOB.abt containing the word
\"nonlinear\" for orderly stopping the solver in the current
working directory (apdl-abort-file)"]
"--"
["Kill MAPDL Run" apdl-kill-ansys
:help "Kill the current MAPDL run (apdl-kill-ansys)"
:active (apdl-process-running-p)]
["List all Emacs' Processes" list-processes
:help "Show all active processes under Emacs, like shells,
etc. (list-processes)"]
["View Emacs' Messages" view-echo-area-messages
:help "Display Emacs' latest messages for debugging and
checking purposes"])
"Ansys menu items for APDL-Mode.")
;;; --- predicates ---
(defun apdl-in-asterisk-comment-p ()
"Return t if the cursor is inside an APDL asterisk comment."
(save-excursion
(let ((lbp (line-beginning-position)))
(if (search-backward " *" lbp t)
t
nil))))
(defun apdl-in-string-command-line-p ()
"Return t if in an APDL string command line."
(save-excursion
(back-to-indentation)
(looking-at apdl-string-commands-regexp)))
(defun apdl-number-line-p ()
"Return t if in an APDL number block."
(save-excursion
(beginning-of-line)
(and (not (apdl-in-format-construct-p))
(looking-at apdl-number-line-regexp)))) ; "(" is for CMBLOCK
; format string
(defun apdl-default-command-p ()
"Return t if in an APDL default command line.
The current code is reusing the previous APDL command with a line
beginning with a comma."
(save-excursion
(beginning-of-line)
(looking-at "^\\s-*,")))
(defun apdl-in-indentation-p ()
"Return t if in an indentation."
(if (and (eolp) (bolp)) ; take care of empty lines
nil
(let ((p (point)))
(save-excursion
(back-to-indentation)
(if (<= p (point)) t nil)))))
(defun apdl-first-line-p ()
"Return t if at the first line."
(save-excursion
(beginning-of-line)
(bobp)))
(defun apdl-last-line-p ()
"Return t if at the last line."
(save-excursion
(end-of-line)
(eobp)))
(defun apdl-continuation-line-p ()
"Return t if in a continuation line of certain commands."
(save-excursion
(beginning-of-line)
(if (looking-at apdl-continuation-line-regexp) t nil)))
(defun apdl-in-format-command-line-p ()
"Return t if in an APDL format command line, nil otherwise.
See the constant variable `apdl-format-commands-regexp' which
includes the commands which need formatting lines."
(save-excursion
(beginning-of-line)
(if (looking-at
(concat "^\\s-*\\(" apdl-format-commands-regexp
"\\)")) t nil)))
(defun apdl-in-format-construct-p ()
"Return t if in an APDL format construct.
Otherwise nil, i.e. return nil when in a format command line."
(cond ((apdl-continuation-line-p) t)
((apdl-first-line-p) nil)
(t (save-excursion
(forward-line -1)
(if (or
(apdl-continuation-line-p)
(apdl-in-format-command-line-p)) t nil)))))
(defun apdl-condensed-input-line-p ()
"Return t if in an APDL condensed (... $ ...) input line."
(save-excursion
(beginning-of-line)
(if (apdl-in-format-construct-p)
nil
(if (looking-at apdl-condensed-input-line-regexp)
t
nil))))
(defun apdl-code-line-p ()
"Return t if in an APDL code line, nil otherwise.
A code line is the complementary to the regexp
`apdl-non-code-line-regexp'."
(save-excursion
(beginning-of-line)
(if (looking-at apdl-non-code-line-regexp) nil t)))
(defun apdl-not-in-code-line-p ()
"Return t if not in an APDL code line, nil otherwise.
A code line is the complementary to the regexp
`apdl-non-code-line-regexp'."
(save-excursion
(beginning-of-line)
(looking-at apdl-non-code-line-regexp)))
(defun apdl-at-end-of-text-p ()
"Return t if the cursor is at the end of text in a line."
(if (looking-at "\\s-*$") t nil))
(defun apdl-at-end-of-code-p ()
"Return t if the cursor is at the end of code in a line.
This means at the end of code before whitespace or an APDL
comment."
(if (looking-at "\\s-*$\\|\\s-*!") t nil))
(defun apdl-is-unix-system-p ()
"Return t when we are on a Unix system.
gnu/linux, aix, berkeley-unix, hpux, irix, lynxos 3.0.1,
usg-unix-v. Ansys supports only GNU-Linux 64 and Windows 64 for
the entire Ansys platform with some support of legacy Unixes (AIX
IBM, HP-UX HP, SGI, Solaris SUN) for standalone apps will be
provided so I won't restrict some aspects of APDL-Mode to
GNU-Linux."
(not
(or (string= system-type "gnu") ; gnu with the hurd kernel
(string= system-type "darwin") ; mac
(string= system-type "ms-dos")
(string= system-type "windows-nt")
(string= system-type "cygwin"))))
;; FIXME DEFSUBSTs with DEFUNs (apdl-position) inside aren't
;; particularly speedy, are they?
(defsubst apdl-in-comment-p ()
"Return t if the cursor is inside an APDL comment.
The cursor is either in a code comment or comment line."
(save-excursion
(nth 4 (parse-partial-sexp (apdl-position 'bol)
(point))))) ; nth -- nth element of list
(defsubst apdl-in-comment-line-p ()
"Return t if the cursor is in a comment line."
(save-excursion
(back-to-indentation)
(looking-at "!")))
(defsubst apdl-in-string-p () ; FIXME:are there strings defined in ansys?
"Return t if the cursor is inside an APDL string."
(save-excursion
(nth 3 (parse-partial-sexp (apdl-position 'bol) (point)))))
(defsubst apdl-in-empty-line-p()
"Return t if the cursor is in an empty (whitespace) line."
(save-excursion
(beginning-of-line)
(looking-at "^[ \n\t]*$")))
(defsubst apdl-not-in-string-or-comment-p()
"Return t if the cursor is not inside a string or comment."
(let ((pps (parse-partial-sexp (apdl-position 'bol) (point))))
(not (or (nth 3 pps) (nth 4 pps)))))
(defsubst apdl-in-string-or-comment-p ()
"Return t if the cursor is not inside a string or comment."
(let ((pps (parse-partial-sexp (apdl-position 'bol) (point))))
(or (nth 3 pps) (nth 4 pps))))
;; ======================================================================
;; --- interactive functions ---
(defun apdl-mode-help ()
"Browse the APDL-Mode documentation in the Info Viewer."
(interactive)
(info "(apdl-mode)Top"))
(defun apdl-mode-browse-online ()
"Browse the APDL-Mode online documentations."
(interactive)
(let ((url "https://dieter-wilhelm.github.io/apdl-mode"))
(cond
(apdl-is-unix-system-flag
;; use browse-url-default-browser!
(if (fboundp 'browse-url-xdg-open)
(browse-url-xdg-open url)
;; (browse-url-default-browser
;; (concat path file)) not working with E23.1 on RHEL
(browse-url-firefox url)))
;; windows
(t
;; wrapper of ShellExecute MS-Windows API
;; (message "file:%s path:%s" file path)
;; (w32-shell-execute "Open" (concat path file)))
(browse-url-default-windows-browser url)))))
(defun apdl-align (p-min p-max)
"Align current paragraph or selection of APDL variable definitions.
If a region is selected align it (with the region borders P-MIN
and P-MAX) otherwise align the current code paragraph."
(interactive "r")
(if mark-active
(align p-min p-max)
(align-current))) ; align-current needs a mark
(defun apdl-add-variable-hooks ()
"Add APDL-Mode variable hooks."
(add-hook 'after-change-functions
#'apdl-find-user-variables nil t)
(add-hook 'post-command-hook
#'apdl-update-parameter-help nil t))
;; the autoload cookie is copying stuff to the -autoloads.el file
;; check with (update-file-autoloads)
;;;###autoload (add-to-list 'auto-mode-alist '("\\.mac\\'" . apdl-mode))
;;;###autoload (add-to-list 'auto-mode-alist '("\\.ans\\'" . apdl-mode))
;;;###autoload (add-to-list 'auto-mode-alist '("\\.dat\\'" . apdl-mode))
;;;###autoload (add-to-list 'auto-mode-alist '("\\.inp\\'" . apdl-mode))
;;;###autoload
(defun apdl-mode ()
"Editor support for the APDL language and working with Ansys MAPDL.
APDL-Mode (formerly Ansys-Mode) - in conjunction with the
GNU-Emacs editor - is an advanced APDL environment with features
like, pin-pointing the APDL reference documentation, keyword
completion, code templates, dedicated highlighting, solver
communication (GNU-Linux only), license reporting, etc. Over the
years it has accumulated lots of features for writing WorkBench /
Discovery AIM Command (APDL) objects and debugging complete FEA
models in APDL code.
The extensive documentation can be accessed from the APDL-Mode
menu or by calling the function `apdl-mode-help' with
\\[apdl-mode-help].
\\{apdl-mode-map}"
(interactive)
(unless (string= major-mode "apdl-mode")
(set (make-local-variable 'apdl-previous-major-mode) major-mode))
(put 'apdl-previous-major-mode 'permanent-local t)
(when (and (overlayp apdl-help-overlay)
(overlay-buffer apdl-help-overlay))
(delete-overlay apdl-help-overlay))
(kill-all-local-variables) ; convention
(setq major-mode 'apdl-mode)
(setq mode-name "APDL") ; mode line string
;; only effective for window systems!
(setq indicate-empty-lines apdl-indicate-empty-lines-flag)
(setq completion-ignore-case t) ; keyword completion regardless of cases
;; --- hooks ---
(run-hooks 'apdl-mode-hook)
;; we needs this before the -mode-map, which reacts on
;; outline-minor-mode
(use-local-map apdl-mode-map)
(set-syntax-table apdl-mode-syntax-table)
(setq local-abbrev-table apdl-mode-abbrev-table)
(setq font-lock-maximum-decoration
`((apdl-mode . ,apdl-highlighting-level) (t . t)))
(setq align-mode-rules-list apdl-align-rules-list)
;; (when (> apdl-highlighting-level 1)
;; (setq font-lock-multiline t)) ; for *msg, *vwrite,.. format strings
(make-local-variable 'apdl-user-variable-regexp) ; for font-lock
(setq apdl-user-variable-regexp nil)
(make-local-variable 'parens-require-spaces)
(setq parens-require-spaces apdl-require-spaces-flag)
(make-local-variable 'indent-line-function)
(setq indent-line-function 'apdl-indent-line-function)
(make-local-variable 'comment-start)
(setq comment-start apdl-indent-comment-string)
(make-local-variable 'comment-padding)
(setq comment-padding apdl-comment-padding)
(make-local-variable 'comment-add)
(setq comment-add apdl-comment-add)
(make-local-variable 'comment-column)
(setq comment-column apdl-code-comment-column)
;; FIXME:
;; (setq comment-fill-column 50)???
;; comment-indent -> fill-column?? only when line-wrap mode t?
;; overlay for command-parameter-help
;; (make-local-variable 'apdl-timer)
;; (make-local-variable 'apdl-help-overlay)
(setq apdl-help-overlay (make-overlay 1 1))
;; look at newcomment.el
(make-local-variable 'comment-start-skip)
(setq comment-start-skip apdl-comment-start-skip)
;; (make-local-variable 'parse-sexp-ignore-comments)
;; (setq parse-sexp-ignore-comments t)
;; (make-local-variable 'font-lock-defaults) is always local
(setq font-lock-defaults `(,apdl-font-lock-keyword-list nil 'case-ignore))
;; keywords
;; keywords-only -- nil: syntactic fontification
;; case-fold -- non nil: ignore case
(make-local-variable 'outline-regexp)
(make-local-variable 'apdl-hide-region-overlays)
;; outline-minor-mode searches only at the line beginning
(setq outline-regexp (concat "![" apdl-outline-string "]+"))
;; discrepancies from Emacs defaults
(apdl-font-lock-mode) ; switch on font-lock when
; it's toggled
;; It is impolite to enforce below behaviour over possible user
;; customisation
;; ; (delete-selection-mode t)
;; ; (toggle-truncate-lines 1)
;; ; (show-paren-mode t)
;; ; (set (make-local-variable 'scroll-preserve-screen-position) nil)
(setq apdl-is-unix-system-flag (apdl-is-unix-system-p))
;; menu
(apdl-add-apdl-menu)
;; All files and all buffers use with apdl-mode
;; only when apdl-dynamic-highlighting-flag is t
;; and
;; only: .mac, .ans, .inp can have dynamic highlighting and buffer
;; *APDL code*, .dat is per default the workbench input file format
;; File > 1 MB < 30 MB y-or-n-p: dynamic
;; highlighting
;; file > 30 MB yes or no: (extended) variable highlighting with
;; apdl-highlight-variable?, never dynamic highlighting
;; -highlighting-level [2] >= 2 and apdl-dynamic-highlighting-flag [t]
;;apdl-add-variable-hooks
;; --- dealing with 1) "extended" variable highlighting and 2) dynamic
;; variable highlighting ---
;; either *APDL code* buffer (we ignore other buffers here) or files
(if (string= (buffer-name) "*APDL code*")
(when apdl-dynamic-highlighting-flag
(apdl-add-variable-hooks))
(let* ; now we deal with existing files
((File (buffer-file-name))
(Size (and File
(nth 7 (file-attributes (buffer-file-name))))))
(when File
(cond
((> Size 3000000) ; file > 3 MB, that's very likely WB generated
;; (when
;; (yes-or-no-p
;; "File larger than 3 MB, switch on extended variable highlighting? ")
;; (apdl-find-user-variables)
;; (message "Extended, non-dynamic highlighting of variables activated."))
(message "Non-dynamic highlighting of variables activated."))
((> Size 500000) ; file > 0.5 MB editing is becoming very sluggish
; with dynamic highlighting
(when (or (string= (file-name-extension (buffer-file-name) 'dot) ".ans")
(string= (file-name-extension (buffer-file-name) 'dot) ".inp")
(string= (file-name-extension (buffer-file-name) 'dot) ".mac"))
(apdl-find-user-variables)
(when
(and
apdl-dynamic-highlighting-flag
(yes-or-no-p "File larger than 0.5 MB, switch on dynamic variable highlighting? "))
(apdl-add-variable-hooks)
(message "Dynamic highlighting of user variables activated."))))
(t ; file <= 0.5 MB
(apdl-find-user-variables)
(when
(and
apdl-dynamic-highlighting-flag
(or (string= (file-name-extension (buffer-file-name) 'dot) ".ans")
(string= (file-name-extension (buffer-file-name) 'dot) ".inp")
(string= (file-name-extension (buffer-file-name) 'dot) ".mac")))
(apdl-add-variable-hooks)
(message "Dynamic highlighting of user variables activated.")))))))
;; (if (and (>= apdl-highlighting-level 2) ;
;; apdl-dynamic-highlighting-flag
;; (or
;; ;; either *APDL code* buffer
;; (string= (buffer-name) "*APDL code*")
;; ;; or .mac or .ans files and both smaller than 30 Mb
;; ;; .dat and .inp might be huge WorkBench files..
;; (and (buffer-file-name)
;; (or (string= (file-name-extension (buffer-file-name)
;; 'dot) ".ans")
;; (string= (file-name-extension (buffer-file-name)
;; 'dot) ".inp")
;; (string= (file-name-extension (buffer-file-name)
;; 'dot) ".mac"))
;; ;; 30 Mb bigger than file?
;; (when (file-attributes (buffer-file-name)) ; open an
;; ; existing
;; ; file
;; ;; Emacs-28 large-file-warning-threshold is 10mb
;; (if (> 30000000 (nth 7 (file-attributes (buffer-file-name))))
;; t
;; (y-or-n-p "File larger than 30 MB, switch on dynamic variable highlighting? "))))))
;; (progn
;; ;; (message "before apdl-update-p.")
;; (add-hook 'after-change-functions
;; #'apdl-find-user-variables nil t)
;; (add-hook 'post-command-hook
;; #'apdl-update-parameter-help nil t)
;; (message "Dynamic highlighting of user variables activated."))
;; (message "Non-dynamic highlighting of variables activated."))
;; that's the culprit for large files, not the highlighting
;; (apdl-find-user-variables)
;; (if (>= apdl-highlighting-level 2)
;; (when (or
;; (when (not buffer-file-name)
;; t) ; skip below size query (buffer without a file)
;; (> 30000000 (nth 7 (file-attributes (buffer-file-name))))
;; (y-or-n-p
;; "File is larger than 30 MB, switch on user variable highlighting? "))
;; (message "before if.")
;; (if (and apdl-dynamic-highlighting-flag
;; (or (string= (buffer-name) "*APDL code*")
;; ; (message "before ans.")
;; (string= (file-name-extension (buffer-file-name) 'dot) ".ans")
;; ; (message "before mac.")
;; (string= (file-name-extension (buffer-file-name) 'dot) ".mac")))
;; (progn (message "before addhook.")
;; (add-hook 'after-change-functions
;; 'apdl-find-user-variables nil t)
;; (message "before apdl-update-p.")
;; (add-hook 'post-command-hook
;; 'apdl-update-parameter-help nil t)
;; (message "Dynamic highlighting of user variables activated."))
;; (message "Non-dynamic highlighting of variables activated."))
;; (apdl-find-user-variables)))
;; .dat WorkBench solver input files
(when (and buffer-file-name ; a buffer with a file name
(string= (file-name-extension (buffer-file-name) t) ".dat"))
(apdl-hide-number-blocks))
;; a-align needs a mark to work for an unspecified region
;; (set-mark 0) -TODO-
;; initialise system dependent stuff
(unless apdl-initialised-flag
(apdl-initialise))
)
;; -- end of apdl-mode --
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;###autoload
(defun apdl ()
"Open a new buffer in APDL-Mode.
You must save the buffer (connect it with a file-name), otherwise
possible edits are lost."
(interactive)
(let ((b "*APDL code*"))
(get-buffer-create b)
(switch-to-buffer b)
(when (< (buffer-size) 1)
(insert "!! This is an unnamed file under APDL-Mode.\n\
!! Please save it (C-x C-s) and start your APDL hacking...\n\n"))
(apdl-mode)))
;; FIXME
;; (defun apdl-ansysli-servers-check ()
;; "Return t if Ansys interconnect server information is found.
;; Checking whether the variable `apdl-ansysli-servers' is set or
;; otherwise the environment variable AnsysLI_SERVERS. If neither
;; is set return nil"
;; (interactive)
;; (cond
;; (apdl-ansysli-servers
;; ; (setenv "AnsysLI_SERVERS" apdl-ansysli-servers)
;; ; (message "Set process environment variable AnsysLI_SERVERS
;; to apdl-ansysli-servers")
;; t)
;; ((getenv "AnsysLI_SERVERS")
;; (setq apdl-ansysli-servers (getenv "AnsysLI_SERVERS"))
;; (message "Read apdl-ansysli-servers from process environment
;; variable AnsysLI_SERVERS") t)
;; (t nil)))
;; (defun apdl-license-file-check ()
;; "Return t if Ansys license file (server) information is found.
;; Checks whether the variable `apdl-license-file' is set, if not
;; sets its value to the environment variable AnsysLMD_LICENSE_FILE
;; or LM_LICENSE_FILE, in this order of precedence. When the former
;; are not available return nil."
;; (let ((lic1 (getenv "AnsysLMD_LICENSE_FILE"))
;; (lic2 (getenv "LM_LICENSE_FILE"))
;; )
;; (cond
;; (apdl-license-file
;; ; (setenv "AnsysLMD_LICENSE_FILE" apdl-license-file)
;; ; (message "Set process environment variable AnsysLMD_LICENSE_FILE
;; to apdl-license-file")
;; t)
;; (lic1 ; need this for -license-status
;; (setq apdl-license-file lic1)
;; (message "Set apdl-license-file from AnsysLMD_LICENSE_FILE")
;; (message "apdl-license-file=%s" lic1)
;; t)
;; (lic2
;; (setq apdl-license-file lic2)
;; (message "Set apdl-license-file from MD_LICENSE_FILE")
;; (message "apdl-license-file=%s" lic2)
;; t)
;; (t
;; nil))))
(defun apdl-mark-paragraph (&optional arg allow-extend)
"Put mark at beginning of this paragraph, point at end.
The paragraph marked is the one that contains point or follows
point.
With argument ARG, puts point at end of a following paragraph, so
that the number of paragraphs marked equals ARG.
If ARG is negative, point is put at the beginning of this
paragraph, mark is put at the end of this or a previous
paragraph.
Interactively, if this command is repeated
or (in Transient Mark mode) if the mark is active,
it marks the next ARG paragraphs after the ones already marked.
Arg ALLOW-EXTEND is in interactive calls the same as ARG."
(interactive "p\np")
(unless arg (setq arg 1))
(when (zerop arg)
(error "Cannot mark zero paragraphs"))
(cond ((and allow-extend ; we already called this function
(or (and (eq last-command this-command) (mark t))
(and transient-mark-mode mark-active)))
(forward-paragraph arg))
((and (bolp) (eolp)) ; we are in an empty line
(push-mark nil t t)
(forward-paragraph arg))
(t ; we are within a paragraph
(backward-paragraph arg)
(push-mark nil t t)
(forward-paragraph arg))))
;;;###autoload
(defun apdl-mode-version ()
"Display the APDL-Mode version numbering scheme.
Together with the APDL-Mode update date and the Ansys version on
which the keyword- and completion system is based upon."
(interactive)
(message "APDL-Mode version: %s (%s) based on Ansys %s"
apdl-mode-version
apdl-mode-update
apdl-ansys-version))
;; ATTENTION: reloading seems to be critical, when there are multiple
;; entries in `load-path' for APDL-Mode!
(defun apdl-reload-apdl-mode ()
"Reload APDL-Mode for debugging or testing purposes.
Clear (unload) all mode definitions, if apdl-mode is active, load
the necessary code and call `apdl-mode'. In general, this is
only possible if apdl-mode.el is in the load-path of Emacs."
(interactive)
(progn
(when (featurep 'apdl-mode)
(unload-feature 'apdl-mode)
(unload-feature 'apdl-keyword)
(unload-feature 'apdl-process)
(unload-feature 'apdl-template)
(unload-feature 'apdl-wb-template)
;; the others rely on -initialise !!
(unload-feature 'apdl-initialise))
;; (load "apdl-config") ; don't rely on apdl-config!
(if (file-exists-p "apdl-mode.el")
(load "apdl-mode.el")
(error "There is no apdl-mode.el in load-path")) ; load apdl-mode.el
(apdl-mode)
(message "APDL-Mode %s based on Ansys %s reloaded"
apdl-mode-version apdl-ansys-version)))
(defun apdl-show-paren-mode () ; _C
"Switch on minor mode function `show-paren-mode'.
The Matching parenthesis is highlighted."
(show-paren-mode 1))
;; (defun apdl-ruler-mode () ; _C
;; "Toggle display of ruler in header line.
;; This is the minor mode `ruler-mode'."
;; (ruler-mode))
(defun apdl-font-lock-mode ()
"Switch on function `font-lock-mode'.
Font Lock is also known as \"syntax highlighting\"."
(unless font-lock-mode
(font-lock-mode 1)))
(defun apdl-outline-minor-mode ()
"Switch on mode function `outline-minor-mode'.
Editing with selective display."
(outline-minor-mode 1))
(defun apdl-auto-insert-mode ()
"Switch on mode function `auto-insert-mode'.
Automatic template insertion is enabled"
(auto-insert-mode 1))
(defun apdl-insert-pi ()
"Insert the code \"Pi = acos(-1)\" = 3.141.. at point.
Indent the current line according to the context."
(interactive)
(insert "Pi = acos(-1) ! 3.14159265359")
(indent-according-to-mode)
(newline-and-indent))
(defun apdl-column-ruler ()
"Insert a temporary column ruler above the current line.
The insertion remains until the next keystroke. The key typed is
inserted or evaluated unless it is the SPC key."
(interactive)
(save-excursion
(momentary-string-display
(if apdl-ruler-wide-flag
apdl-column-ruler-wide
apdl-column-ruler-narrow)
(line-beginning-position))))
(defun apdl-position (position) ; FIXME: with `line-beginning-position' etc.
;; redundant function
"Return the value of point at certain POSITIONs."
(save-excursion
(cond
((eq position 'bol) (beginning-of-line)) ; line-beginning-position
((eq position 'eol) (end-of-line)) ; line-end-position
((eq position 'boi) (back-to-indentation))
((eq position 'bonl) (forward-line 1))
((eq position 'bopl) (forward-line -1))
(t (error "Unknown buffer position requested: %s" position)))
(point)))
(defun apdl-close-block () ; FIXME: choices for *IF
"Complete an APDL block command with the appropriate end keyword.
Insert the end keyword on a separate line. An error is signalled
if no block to close is found. For example the *IF command
represents only a proper block command when it is followed by a
THEN action label."
(interactive "*")
(let (bb-keyword str tmp)
(condition-case nil ; more pertinent error message -TODO-
(progn
(save-excursion
(apdl-up-block)
(setq bb-keyword (buffer-substring-no-properties
(match-beginning 1) (match-end 1)))
;; for *IF we're getting more than one word (*IF,...,THEN)
(setq tmp (compare-strings bb-keyword 0 nil
"*IF" 0 nil 'ignore-case))
(when (> tmp 2)
(setq bb-keyword
(substring-no-properties
(buffer-substring-no-properties
(match-beginning 1) (match-end 1)) 0 3))))
;; prepare insertion of keyword
(setq str (car (reverse ; FIXME: incomplete, why?
;; RESTRICTED: asssoc-string Emacs 21.4
(assoc-string bb-keyword
apdl-block-match-alist 1))))
;; capitalise properly
(let ((case-fold-search nil))
(when (string-match
"\\([a-z].\\)\\|\\(\\*\\|/\\|~\\)[a-z]" bb-keyword)
(setq str (downcase str))))
(cond
((apdl-in-empty-line-p)
;; (delete-blank-lines) deletes in 23.1 an isolated empty line
(insert str)
(indent-according-to-mode))
((apdl-in-indentation-p)
(beginning-of-line)
(open-line 1)
(insert str)
(indent-according-to-mode)
(forward-line 1)
(indent-according-to-mode)
(forward-line -1)
(end-of-line))
((apdl-in-string-or-comment-p)
(end-of-line)
(newline)
(insert str)
(indent-according-to-mode))
((and (apdl-code-line-p)
(not (apdl-at-end-of-text-p)))
(indent-according-to-mode)
(newline 2)
(forward-line -1)
(insert str)
(indent-according-to-mode)
(forward-line 1)
(indent-according-to-mode)
(forward-line -1)
(end-of-line))
(t
(indent-according-to-mode)
(newline)
(insert str)
(indent-according-to-mode)))
(apdl-blink-matching-block)
t)
(error (message "Cannot find a proper block command to close")))))
;;; --- Command parameters and command completions ----
(defsubst apdl-count-commas ()
"Return the number of commas in the line before point."
(how-many "," (line-beginning-position) (point)))
(defun apdl-manage-overlay ( str)
"Display or remove the command help overlay string STR.
Applying this function in the same line erases the help overlay.
The help overlay will be automatically removed after some time
interval."
(interactive)
(let (; (ho (overlay-start apdl-help-overlay))
(lb (line-beginning-position)))
(if apdl-timer
(cancel-timer apdl-timer))
(delete-overlay apdl-help-overlay)
;; (setq apdl-help-overlay-str str)
(move-overlay apdl-help-overlay lb lb)
(overlay-put apdl-help-overlay 'before-string str)
(setq apdl-timer
(run-at-time
apdl-parameter-help-duration nil
(lambda ()
(when (overlayp apdl-help-overlay)
(delete-overlay apdl-help-overlay)))))))
(defun apdl-search-comma (str count)
"Return the index of the COUNT's occurrence of a comma in STR.
Return nil otherwise."
(let ((index 0)
(c 0))
(while (and (> count c) (not (null index)))
(setq index (string-match "," str (1+ index))
c (1+ c)))
index))
;; function is used as a post-command-hook
;; (defun apdl-update-parameter-help (&optional a b c)
(defun apdl-update-parameter-help ()
"Update parameter help counting according to the cursor position.
Check if we are in a help overlay and if the cursor position
changed. Then call `apdl-show-command-parameters'."
(let ((p (point))
(lo (overlays-in (line-beginning-position)
(1+ (line-beginning-position)))))
(when (and (not (equal p apdl-parameter-help-position))
(not (equal 1 p)) ; -TODO- not working in the first line
(memq apdl-help-overlay lo)) ;there's an overlay above line
(setq apdl-parameter-help-position (point))
(apdl-show-command-parameters -1))))
;; spec: preserve post-command-hook! => no errors
;; edit command while help overlay!
;; remove overlay and warn when too many commas!
(defun apdl-show-command-parameters (&optional ask-or-toggle)
"Display the APDL parameters help for the command near the cursor.
Show the command name and a brief description. In a second line
its parameters (if any) and in a further line the number of
parameters and highlighting the parameter position (if any) of
the cursor. The command is chosen for the current cursor line,
and for the previous APDL command in an empty line (see the
function `apdl-command-start').
In a comment line this function is also looking for an Ansys
keyword. When no word characters are in the line this function
is showing a help for the previous APDL command - which is not
commented out.
With a prefix argument ASK-OR-TOGGLE of zero switch off the
command parameters highlighting, with an prefix `C-u' or argument
`4' (four) enquire a command name from the mini buffer. Here,
the beginning command characters can be completed with <TAB>."
(interactive "p" )
(let ((case-fold-search t) ; in case customised to nil
(count 0)
substr
tmpstr
start
end
length
str)
;; enquire a command or search for a valid command name
(cond ((= ask-or-toggle 0)) ; do nothing here (but below)
;; ------------------------------
((= ask-or-toggle -1) ; apdl-update-parameter-help is calling
;; and thus there's an overlay above us, so stay put
(save-excursion
(back-to-indentation)
(skip-chars-forward "!") ;we might be in a comment line
(re-search-forward "[^[:space:]]\\w*\\>" nil t)
(setq str (match-string-no-properties 0))))
;; ------------------------------
((= ask-or-toggle 4)
(setq str (completing-read
"Type APDL keyword to get its short help: "
apdl-help-index)))
;; ------------------------------
((apdl-in-comment-line-p)
(save-excursion
(back-to-indentation)
(skip-chars-forward "!")
(re-search-forward "[^[:space:]]\\w*\\>" (line-end-position) t)
(setq str (match-string-no-properties 0))
(message "keyword1 = %s" str)
)
(when (string= str "!") ;from skip-chars-forward?
(apdl-command-start)
(re-search-forward "[^[:space:]]\\w*\\>" nil t)
(setq str (match-string-no-properties 0))))
;; ------------------------------
((apdl-in-indentation-p) ; we are possibly before a command
;; -TODO- strange bug, when cursor is in a line with only
;; -commas and no command follows in lines below, then
;; -match-string-no-properties bails out!?
(save-excursion
(re-search-forward "[^[:space:]]\\w*\\>" nil t)
(setq str (match-string-no-properties 0))))
;; ------------------------------
((apdl-in-empty-line-p)
;; we need to follow -command-start otherwise the overlay
;; is hanging in the "air"
(apdl-command-start)
(save-excursion
;; (apdl-command-start)
(re-search-forward "[^[:space:]]\\w*\\>" nil t)
(setq str (match-string-no-properties 0))))
;; ------------------------------
((unless (apdl-in-indentation-p)
(save-excursion
(apdl-command-start)
(re-search-forward "[^[:space:]]\\w*\\>" nil t)
(setq str (match-string-no-properties 0))))))
;;(message "keyword after cond: %s" str)
;; search, amend and display help string in overlay
(if (= ask-or-toggle 0)
(delete-overlay apdl-help-overlay)
(catch 'foo
(dolist (s apdl-dynamic-prompt)
;; 2 line documentation strings in -dynamic-prompt
(when (and (string-match (concat "^" str) s)
(not (string= "" s)))
(setq length (length s))
;; creating additional row with comma counts
(setq start (string-match "\n" s)) ; looking for the first
; line break
(setq substr (substring s (1+ start))) ;second line
(setq tmpstr (mapconcat ;create third line
(lambda (str)
(cond ((string-match "," (string str))
(setq count (1+ count))
(if (> count 9)
(setq count 0))
(format "%d" count))
(t "-")))
substr ""))
(when (> count 0)
(setq s (concat s "\n" tmpstr)))
(setq s (propertize (concat s "\n") 'face 'highlight))
;; show different face for current argument
(setq count (apdl-count-commas))
(setq start (apdl-search-comma s count))
;; highlight redundant argument commas
(cond ((null start)
(setq start (length s))
;; (setq s (propertize (concat s "Redundant argument") 'face 'highlight))
;; (skip-chars-backward "[^,]")
;;(delete-overlay apdl-help-overlay)
(unless (or (apdl-in-string-command-line-p)
(apdl-in-comment-line-p))
(message "Redundant comma, command has fewer arguments!")
(beep)
;;(throw 'foo nil))
))
((= 0 start)
(setq start (1+ (string-match "\n" s)))))
(setq end (apdl-search-comma s (1+ count)))
(unless end
(setq end length))
(unless (>= start end)
(add-text-properties start end '(face isearch-fail) s))
(apdl-manage-overlay s)
;; break dolist when str is found and skip over error
(throw 'foo nil)))
(delete-overlay apdl-help-overlay)
(message "\"%s\" not found in keyword list" str)))))
(defun apdl-check-capitalisation ( string)
"Check case of APDL keyword STRING.
Return symbols capitalise, upcase and downcase."
(interactive)
;; preferences: downcase, capitalize, upcase
(cond
((string= string (downcase string)) 'downcase)
((string= string (capitalize string)) 'capitalize)
((string= string (upcase string)) 'upcase)
(t 'downcase)))
(defun apdl-complete-symbol ()
"Perform a completion on APDL keywords preceding the cursor.
Complete the character(s) to APDL's reserved words, functions
and element names, otherwise throw an error. When the keyword or
the completed character(s) represent a unique APDL keyword
indicate this fact with a message. When the completion is not
unique or only partial show the other possible completions in a
temporary completion buffer, from which the completions might be
chosen with the mouse. You might remove the *APDL completion*
buffer with the SPACE key."
;; This code taken from lisp-complete-symbol
(interactive "*")
(let* ((buffer-name "*APDL-completion*")
(completion-buffer (get-buffer-create buffer-name))
(completion-window (get-buffer-window completion-buffer)))
(if (and (eq last-command this-command)
completion-window ; already window there?
;; window is visible
(window-live-p completion-window))
;; If this command was repeated, and
;; there's a fresh completion window with a live buffer,
;; and this command is repeated, scroll that window.
(with-current-buffer (window-buffer completion-window)
(if (pos-visible-in-window-p (point-max) completion-window)
(set-window-start completion-window (point-min))
(save-selected-window
(select-window completion-window)
(scroll-up)))))
;; Do completion.
(let* ((end (progn (skip-chars-backward " \t") (point)))
(beg (save-excursion
(skip-chars-backward "()")
;; we need to check if we are before * or / in
;; operator syntax
(if (looking-back "[*/]" (- (point) 1))
(skip-chars-backward "*/" (- (point) 1)))
;; are we at a code beginning?
(unless (apdl-in-indentation-p)
(backward-sexp 1))
;; we need to check if we are in a * or / command
(if (looking-back "[*/]" (- (point) 1))
(skip-chars-backward "*/" (- (point) 1)))
(point)))
(completion-string (buffer-substring-no-properties beg end))
(completion (try-completion
completion-string apdl-completions))
(completion-list (all-completions
completion-string apdl-completions))
(cc (apdl-check-capitalisation completion-string)))
(cond
;; completion not possible
((null completion)
(message "\"%s\" cannot be completed to an APDL symbol"
completion-string)
(if completion-window ; bury completion buffer
(save-selected-window
(select-window completion-window)
(bury-buffer)))
(ding))
;; unique and upcased like in the -completions variable
((equal completion t)
(message "\"%s\" is a unique APDL symbol."
completion-string)
(kill-buffer completion-buffer))
;; unique or uniquely completable, case independent
((= (length completion-list) 1) ; unique
(setq completion (funcall cc completion))
(unless (string= completion completion-string)
(setq completion (funcall cc completion))
(delete-region beg end)
(insert completion))
;; possibly move back into parens
(skip-chars-backward ")" (1- (point)))
(kill-buffer completion-buffer)
(message "\"%s\" is a unique APDL symbol." completion))
;; complete or not, but not unique anyway
(t
(setq completion (funcall cc completion))
(unless (string= completion completion-string)
(delete-region beg end)
(insert completion))
(with-output-to-temp-buffer buffer-name
(display-completion-list completion-list))
(if (= (apply #'min (mapcar #'length completion-list))
(length completion))
;; already a complete, valid symbol but fragment is further
;; completable
(message
;; (concat "Complete APDL symbol. Hit SPACE to remove the "
(concat "Complete but not unique APDL symbol. \
Hit SPACE to remove the "
buffer-name " buffer."))
;; not yet complete
(message
(concat "Incomplete APDL symbol. Hit SPACE to remove the "
buffer-name " buffer.")))
;; mouse selections in the completion buffer?
(let (key
first)
(if (progn
(set-buffer (get-buffer completion-buffer))
;; we are temporarily in the completion buffer
(setq key (read-key-sequence nil)
first (aref key 0)) ; first key of key sequence
(and (consp first) ; is cons cell
(consp (event-start first))
(eq
(window-buffer (posn-window (event-start first)))
(get-buffer completion-buffer))
;; (eq (key-binding key) 'choose-completion)))
;; (choose-completion first)
(eq (key-binding key) 'mouse-choose-completion))); <E23.2
(choose-completion first)
;; (mouse-choose-completion first) ; outdated function
(if (eq first ?\ )
(kill-buffer completion-buffer)
(setq unread-command-events
(listify-key-sequence key))))))))))
;;;; Electric characters & friends
(defun apdl-reindent-then-newline-and-indent ()
;; (&ptional non-matching) ; FIXME: docu
"Reindent current APDL line, insert newline, and indent the new line.
If function `abbrev-mode' is on, expand the abbreviations first."
(interactive "*") ; * means signal error if read-only
(expand-abbrev)
(apdl-blink-matching-block)
(save-excursion
(delete-region
(point)
(progn (skip-chars-backward " \t")
(point))) ; move trailing whitespace
(indent-according-to-mode))
(insert "\n")
(indent-according-to-mode))
(defun apdl-electric-space ()
"Insert a space in APDL-Mode.
Maybe expand abbrevs and blink matching block open keywords.
Reindent the line if `apdl-auto-indent-flag' is non-nil."
(interactive "*") ; error if read only
(setq last-command-event ? )
(cond ((and mark-active transient-mark-mode delete-selection-mode)
(kill-region (point) (mark))
(self-insert-command 1))
((and (apdl-not-in-string-or-comment-p)
(not (apdl-in-indentation-p))
(not (apdl-in-empty-line-p)))
(indent-according-to-mode)
(self-insert-command 1)
(expand-abbrev)
(apdl-blink-matching-block)
(if (and apdl-auto-indent-flag
(save-excursion
(skip-syntax-backward " ")
(not (bolp))))
(indent-according-to-mode)))
(t
(self-insert-command 1))))
(defun apdl-add-apdl-menu ()
"Add an \"APDL\" entry to the Emacs menu bar."
(require 'easymenu)
(easy-menu-define apdl-task-menu-map apdl-mode-map
"Menu keymap for APDL Tasks." apdl-task-menu)
(easy-menu-define apdl-mode-menu-map apdl-mode-map
"Menu keymap for APDL-Mode." apdl-mode-menu)
;; redundant for emacs > 28
(when (version< "28" emacs-version)
(with-no-warnings
(easy-menu-add apdl-task-menu-map apdl-mode-map)
(easy-menu-add apdl-mode-menu-map apdl-mode-map))))
(defun apdl-calculate-indent () ; FIXME: comment, fixed goal column,
"Return appropriate indentation for the current APDL code line.
Returns an integer (the column to indent to) unless the line is a
comment line with fixed goal column. In that case, returns a
list whose car is the column to indent to, and whose cdr is the
current indentation level."
(let ((column 0) ; column
(keyword_c 0) ; for specified commands
(comma_c nil) ; for default commands
lep ; line end predicate
lbp) ; line beginning predicate
;; --- first for the previous code line ---
(save-excursion
(when (zerop (apdl-previous-code-line 1)) ; there is a previous
; code line
(if (or (apdl-condensed-input-line-p)
(and (apdl-in-indentation-p)
(not (apdl-default-command-p))))
(back-to-indentation)
(apdl-command-start)) ; skip to the beginning of a *msg and
; default command
(setq keyword_c (current-column))
(cond
((looking-at apdl-block-begin-regexp)
;; checking for then keywords in if
; (when (looking-at "\\*if.*,\\s-*then") ; *if base1 or base2
;; must be THEN for being a block keyword
(setq keyword_c (+ keyword_c apdl-block-offset)));)
((looking-at apdl-block-else-regexp)
(setq keyword_c (+ keyword_c apdl-block-offset)))
((looking-at "[^\n,]") ; */ are also valid default commands 12.1
(setq lep (line-end-position))
(setq comma_c (re-search-forward "\\w+\\s-*" lep 'noerror))
(when comma_c
(setq lbp (line-beginning-position))
(setq comma_c (- comma_c lbp))))
((looking-at ",") ; -TODO-: shouldn't be possible
(setq lep (line-end-position))
(setq comma_c (1- (re-search-forward
"," lep 'noerror))) ; excluding the comma
(when comma_c
(setq lbp (line-beginning-position))
(setq comma_c (- comma_c lbp)))))))
;; --- now for the current code line ---
(save-excursion
(back-to-indentation)
(if (apdl-first-line-p) ; we are at the first code line
(setq column (current-column))
(cond
((and (looking-at apdl-block-else-regexp)
(apdl-not-in-string-or-comment-p))
(setq column (- keyword_c apdl-block-offset)))
((and (looking-at apdl-block-end-regexp)
(apdl-not-in-string-or-comment-p))
(setq column (- keyword_c apdl-block-offset)))
((and (looking-at ",") ; APDL default command substitution
(apdl-not-in-string-or-comment-p)) ; FIXME:for *msg lines etc.?
(if comma_c
(setq column comma_c)
(setq column keyword_c)))
((and (looking-at "\\s<\\w") ; FIXME:? this is for "code
; comments"
(not (looking-at
( concat
"\\(\\s<\\s<\\s-\\S<\\)\\|\\(\\^\\s<"
apdl-outline-string "+\\)")))
(setq column comment-column)))
(t
(setq column keyword_c)))))
(when (< column 0)
(error "%s" "Can't deduce sensible column offset"))
column))
(defun apdl-indent-line-function (&optional arg)
"Indent current line in APDL coding style.
With optional ARG, use this as offset unless this line is a
comment with fixed goal column. This function is saved in
`indent-line-function'."
(interactive "*p")
(unless arg (setq arg 1))
(let ((icol (apdl-calculate-indent))
(relpos (- (current-column) (current-indentation))))
(if (listp icol) ; FIXME: -calculate-indent returns no list
(setq icol (car icol))
(setq icol (+ icol (1- arg))))
(if (< icol 0)
(error "Unmatched end keyword") ; FIXME: this is probably wrong
(indent-line-to icol)
(if (> relpos 0)
(move-to-column (truncate (+ icol relpos)))))))
;;;; Electric characters & friends
(defun apdl-abbrev-start ()
"Start entering an APDL abbreviation.
If Abbrev mode is turned on, typing ` (grave accent) followed by ? or
\\[help-command] lists all APDL abbrevs. Any other key combination is
executed normally.
Note that all APDL-Mode abbrevs start with a grave accent."
(interactive)
;; (if (not abbrev-mode) ; FIXME: redundant with E22.?
;; (self-insert-command 1)
(let (c)
(insert last-command-event)
(if (or (eq (setq c (read-event)) ??)
(eq c help-char))
(list-abbrevs t)
(setq unread-command-events (list c))))) ; )
;; ;; redefine function because of bug in Emacs 23.2 squashed in 23.3
;; (defun prepare-abbrev-list-buffer (&optional local)
;; "Temporary redefinition of internal Emacs function with the argument LOCAL."
;; (let ((l-a-t-n (abbrev-table-name local-abbrev-table)))
;; (with-current-buffer (get-buffer-create "*Abbrevs*")
;; (erase-buffer)
;; (if local
;; (insert-abbrev-table-description l-a-t-n t)
;; (dolist (table abbrev-table-name-list)
;; (insert-abbrev-table-description table t)))
;; (goto-char (point-min))
;; (set-buffer-modified-p nil)
;; (edit-abbrevs-mode)
;; (current-buffer))))
(defun apdl-indent-format-line ()
"Break APDL line at point, continuing comment if within one.
If within code, insert the APDL continuation character `&'
before breaking the line. If within a string, signal an error.
The new line is properly indented."
(interactive "*")
(delete-horizontal-space)
(cond
((apdl-in-comment-p)
(indent-new-comment-line))
((apdl-in-string-p) ; FIXME: there are no strings defined yet
(error "Cannot split a code line inside a string"))
((apdl-in-format-construct-p)
(insert " &")
(apdl-reindent-then-newline-and-indent))
(t
(apdl-reindent-then-newline-and-indent))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; --- Cursor movement ---
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun apdl-default-command-end ()
"Move cursor to the end of an APDL default command construct."
(unless (apdl-default-command-p)
(re-search-forward "^\\s-*,"))
(while (apdl-default-command-p)
(forward-line))
(forward-line -1)
(end-of-line))
(defun apdl-search-number-line (&optional dir)
"Search forward for a line existing purely of numbers.
If not If direction DIR is negative search backwards. The default
for DIR is 1. When already in a number line just go to the line
beginning when DIR is < 1 and when DIR is > to the end. When no
further number line is in the file signal an error."
(interactive "p")
(unless dir (setq dir 1))
(let ((re apdl-number-line-regexp))
(unless (apdl-at-end-of-text-p)
(beginning-of-line))
(cond
((< dir 1)
(while (progn
(unless (re-search-backward re nil t)
(error "Can't find preceding number line"))
(apdl-in-format-construct-p))))
(t
(while (progn
(unless (re-search-forward re nil t)
(error "Can't find subsequent number line"))
(apdl-in-format-construct-p)))))))
(defun apdl-number-block-start ()
"Move to the line beginning before a pure number block.
For example an APDL NBLOCK or EBLOCK typically found in
WorkBench APDL files. If there is no code before a number block,
signal an error."
(interactive)
(when (or (apdl-in-indentation-p)
(not (apdl-number-line-p)))
(apdl-search-number-line -1))
(while (apdl-number-line-p)
(forward-line -1))
(forward-line))
(defun apdl-number-block-end ()
"Move to the end of a pure number block.
For example an APDL NBLOCK or EBLOCK typically found in
WorkBench APDL files."
(interactive)
(when (or (apdl-at-end-of-text-p)
(not (apdl-number-line-p)))
(apdl-search-number-line))
(while (apdl-number-line-p)
(forward-line))
(forward-line -1)
(end-of-line))
(defun apdl-next-code-line (&optional num)
"Move NUM lines of APDL code forward, default for NUM is 1.
Skip past intermediate comment and empty lines."
(interactive "p")
(unless num (setq num 1))
(unless (memq last-command '(next-line
previous-line
apdl-next-code-line
apdl-previous-code-line))
(setq temporary-goal-column (current-column)))
(cond ((eobp)
(message "End of buffer"))
(t
(forward-line 1)
(while (and (apdl-not-in-code-line-p)
(not (apdl-last-line-p)))
(forward-line 1))
;; (forward-comment (buffer-size))
;; temporary-goal-column might be a cons cell since E23.2
(move-to-column (if (integerp temporary-goal-column)
(truncate temporary-goal-column)
(truncate (car temporary-goal-column))))
(setq num (1- num))
(when (and (not (apdl-last-line-p))
(/= num 0))
(apdl-next-code-line num)))))
(defun apdl-previous-code-line (&optional num)
"Move NUM lines of APDL code backward, default for NUM is 1.
Skip all empty - and comment lines and return the difference
between NUM and actually moved code lines. Check if there is
previous a code line before the cursor."
(interactive "p")
(unless num (setq num 1))
(unless (memq last-command '(next-line
previous-line
apdl-next-code-line
apdl-previous-code-line))
(setq temporary-goal-column (current-column)))
(let ((Diff num)
(Goal num))
(cond
((= num 0)
(message "%s" "do nothing and return 0")
num)
((apdl-first-line-p)
(message "Already at first line.")
num)
((save-excursion ; here we are not at bob
(while (progn
(forward-line -1)
(and (apdl-not-in-code-line-p)
(not (apdl-first-line-p)))))
;; we are either at the first line or in a code line or both
(if (apdl-not-in-code-line-p)
nil ; first line without code
t)) ; we found a previous code line
(while (progn
(forward-line -1)
(apdl-not-in-code-line-p)))
(setq Goal (1- Goal) ; moved to first previous code line
Diff Goal)
;; move to goal column
(move-to-column (if (integerp temporary-goal-column)
(truncate temporary-goal-column)
(truncate (car temporary-goal-column))))
;; recursion for possibly further code
(unless (= Goal 0) ; = : numerically equal
(setq Diff (apdl-previous-code-line Goal)))
;; (if (= 1 (- num Diff))
;; (message "Moved %d code line" (- num Diff))
;; (message "Moved %d code lines" (- num Diff)))
Diff)
(t ; found no code line
;; (message "No previous code line found.") ; in all templates
num))))
(defun apdl-back-to-format-command ()
"Move cursor back to the beginning of a previous format command.
Signal an error when there is no format command."
(interactive)
(when (re-search-backward apdl-format-commands-regexp) ; signals error
(back-to-indentation)))
(defun apdl-move-to-end-of-format-string ()
"Move cursor to the end of an format command's format string."
(when (apdl-in-format-command-line-p)
(forward-line))
(while (and (apdl-continuation-line-p)
(= (forward-line 1) 0))) ; in case of wrong format at eof
(move-end-of-line 1))
(defun apdl-move-before-comment()
"Move cursor to the line's end of text (which is not commented out)."
(beginning-of-line)
(search-forward "!" (apdl-position 'eol) 1)
(skip-chars-backward " \t!"))
(defun apdl-command-start (&optional num)
"Move cursor to the beginning of the NUMth previous command or assignment.
Default for NUM is 1. If in a comment or empty line, go to the
previous command or to the first line if no previous command is
there. When on a condensed input line, go to previous `$'
statement or to the line's first command. When in a format
command string move backward to the beginning of the respective
command. When no APDL command is to be found signal an error.
When NUM is 0 move to the current code line indentation."
(interactive "p")
(unless num (setq num 1))
(while (> num 0)
(cond
((apdl-in-format-construct-p)
(apdl-back-to-format-command)
(setq num (1- num)))
((apdl-number-line-p)
(while (apdl-number-line-p)
(forward-line -1))
(end-of-line))
((apdl-default-command-p)
(while (apdl-default-command-p)
(forward-line -1))
(end-of-line))
((and (not (apdl-code-line-p)) ; in empty line or comment
(not (= num 0))
(not (apdl-first-line-p)))
(beginning-of-line)
(forward-comment (-(buffer-size))))
((apdl-in-indentation-p)
(if (apdl-first-line-p)
(setq num -1)
(forward-comment (-(buffer-size))))) ; skips also \n!
((apdl-condensed-input-line-p)
(when (looking-back "\\$\\s-*" nil) ; we are already before a $ sign
;; -TODO- speed things with LIMIT?
(skip-chars-backward " \t$")) ; skip at or before the $ char
(if (re-search-backward "\\$\\s-*" (apdl-position 'bol) t)
(skip-chars-forward "$ \t")
(back-to-indentation))
(setq num (1- num)))
(t
(back-to-indentation)
(setq num (1- num))))))
(defun apdl-command-end (&optional num)
"Move to the end of the NUMth next APDL command or assignment statement.
Default for NUM is 1. If in a comment or empty line, go to the
next command or to the last line if no following command is
there. When on a condensed input line, go to the end of the next
`$' statement or to the line's end. Otherwise, when in a format
command string move forward to the end of the (possibly)
multi-line format string. In a code comment skip back to the end
of uncommenteded code, except when at the end of the code text,
then skip to the next code line's end."
(interactive "p")
(unless num (setq num 1))
(while (> num 0)
(cond
((apdl-at-end-of-code-p)
(if (apdl-last-line-p)
(setq num -1)
(forward-comment (buffer-size))))
((or (apdl-in-format-command-line-p)
(apdl-in-format-construct-p)) ; not the format command line
(apdl-move-to-end-of-format-string)
(setq num (1- num)))
((apdl-number-line-p)
(apdl-number-block-end)
(setq num (1- num)))
((apdl-default-command-p)
(apdl-default-command-end)
(setq num (1- num)))
((and (not (apdl-code-line-p)) ; in empty line or comment
(not (= num 0))
(not (apdl-last-line-p)))
(end-of-line)
(forward-comment (-(buffer-size))))
((apdl-condensed-input-line-p)
(when (looking-at "\\s-*\\$") ; we are already before a $ sign
(skip-chars-forward " \t$")) ; skip at or before the $ char
(if (re-search-forward "\\s-*\\$" (apdl-position 'eol) t)
(skip-chars-backward " \t$")
(end-of-line))
(setq num (1- num)))
(t
(back-to-indentation)
(while (not (apdl-at-end-of-code-p))
(forward-char))
(setq num (1- num))))))
(defun apdl-scan-blocks (count level-offset)
"Scan from (point) COUNT balanced APDL begin-end blocks.
Return the position thus found. COUNT may be negative.
If LEVEL-OFFSET is nonzero, the block level gets an offset of
LEVEL-OFFSET."
(let ((min-level-offset (if (> level-offset 0) 0 level-offset)) ; level-offset
;; can become large (we are going deeper down block levels)
;; but never smaller than min-level-offset
(inc (if (> count 0) 1 -1))
(pt (point)))
(save-excursion
(while (/= count 0)
(catch 'foo ; end the inner while loop
(while (or (re-search-forward apdl-block-begin-or-end-regexp
nil t inc) ; FIXME:it's not
; working when
;; in a block regexp
(when (/= level-offset 0)
(error "Can't reach specified block level")))
(unless (apdl-in-string-or-comment-p)
(cond
((match-end 1) (setq level-offset
(+ level-offset inc))) ; begin-block-keywords
((match-end 2) (setq level-offset
(- level-offset inc)))) ; end-block-keywords
(when (< level-offset min-level-offset)
(if (< min-level-offset 0)
(error "Reached minimum block level: Can't go deeper")
(error "Reached maximum block level: Can't go further up")))
(when (= level-offset 0) (throw 'foo nil)))))
(setq count (- count inc)))
(if (= pt (point))
(error "No block keyword found")
(point)))))
(defun apdl-mark-block () ; FIXME: this is not consistent with
;; mark-paragraph, cursor below construct
"Mark current block level.
Either inside of block structure or in the line of a block beginning
keyword."
(interactive)
;; when we are in a line before a block beginning keyword
(if (save-excursion
(back-to-indentation)
(looking-at apdl-block-begin-regexp))
(progn
(move-beginning-of-line nil)
(set-mark-command nil))
(progn
(apdl-up-block)
(move-beginning-of-line nil)
(set-mark-command nil)))
(apdl-skip-block-forward)
(forward-line))
(defun apdl-skip-block-forward (&optional arg)
;; &optional: default arg always
;; nil when non interactively
;; called
"Move forward across one balanced begin- and end-block keyword pair.
With argument, do it that many times. Negative ARG means move
backward across |ARG| blocks."
(interactive "p") ; "p" defaults to 1 only when interactive
(unless arg (setq arg 1))
(goto-char (or (apdl-scan-blocks arg 0)
(if (> arg 0)
(message "No %d block end(s) after cursor position" arg)
(message "No %d block start(s) before cursor position"
arg)))))
(defun apdl-skip-block-backwards (&optional arg)
"Move backward across one balanced APDL begin-end block.
With argument, do it that many times.
Negative ARG means move forward across |ARG| blocks."
(interactive "p")
(unless arg (setq arg 1))
(apdl-skip-block-forward (- arg)))
(defun apdl-next-block-end (&optional count)
"Move forwards behind the next block end.
With argument COUNT do that COUNT times. With negative argument
move backwards to the beginning of the |COUNT| previous block
end."
(interactive "p")
(unless count (setq count 1))
(let ((c)
(dir (if (< count 0 ) -1 1))
(n (abs count)))
(save-excursion
(dotimes (i n)
(while (progn
(setq c (re-search-forward apdl-block-end-regexp nil t dir))
(unless c
(if (< dir 0)
(error "No previous block end(s), %d is(are) missing"
(- n i))
(error "No further block end(s), %d is(are) missing"
(- n i))))
(apdl-in-string-or-comment-p)))))
(goto-char c)))
(defun apdl-previous-block-start-and-conditional (&optional count)
"Move backwards to the beginning the previous block start and conditionals.
This includes the conditional command *IF with bases other then
the keyword THEN; furthermore the looping controls *CYCLE and
*EXIT. With argument COUNT do that COUNT times. With negative
argument move forward to the end of the |COUNT| next block start
or conditional or looping construct."
(interactive "p")
(unless count (setq count 1))
(let ((c)
(dir (if (< count 0 ) -1 1))
(n (abs count))
(b-regexp
(concat
apdl-block-begin-regexp
"\\|\\*[iI][fF]\\>\\|\\*[cC][yY][cC]\\|\\*[eE][xX][iI]")))
(save-excursion
(dotimes (i n)
(while (progn
(setq c (re-search-backward b-regexp nil t dir))
(unless c
(if (< dir 0)
(error "No further block start(s), %d is(are) missing"
(- n i))
(error "No previous block start(s), %d is(are) missing"
(- n i))))
(apdl-in-string-or-comment-p)))))
(goto-char c)))
(defun apdl-down-block (&optional down-level)
"Move forward down one begin-end block level of APDL code.
Position cursor behind the beginning keyword of the respective
block. With argument DOWN-LEVEL, do this for that many levels.
A negative argument means move backwards up DOWN-LEVEL
levels (see `apdl-up-block')."
(interactive "p")
(unless down-level (setq down-level 1))
(let ((inc (if (> down-level 0) 1 -1)))
;; we have to take care whether cursor sits on a beginning keyword
(while (/= down-level 0)
(goto-char (apdl-scan-blocks inc (- inc)))
(setq down-level (- down-level inc)))))
(defun apdl-up-block (&optional depth)
"Move backwards up one begin-end block level of APDL code.
Position cursor before the beginning keyword of the respective
block. With argument DEPTH, do this for that many levels. A
negative argument DEPTH means move forward down DEPTH levels (see
`apdl-down-block')."
(interactive "p")
(unless depth (setq depth 1))
(apdl-down-block (- depth)))
(defun apdl-blink-matching-block ()
"Blink the matching APDL begin block keyword.
If point is right after an APDL else or end type block keyword,
move cursor momentarily to the corresponding begin keyword.
Signal an error if the keywords are incompatible."
(interactive)
(when apdl-blink-matching-block-flag
(let (bb-keyword bb-arg eb-keyword pos eol)
(when
(and
(apdl-not-in-string-or-comment-p)
(looking-at "\\>")
(save-excursion
(skip-syntax-backward "w") ; FIXME: is * in word syntax?
(looking-at apdl-block-else-or-end-regexp))) ; FIXME: and
; otherwise?
(save-excursion
(cond
((match-end 1) ; else keyword
(setq eb-keyword
(buffer-substring-no-properties
(match-beginning 1) (match-end 1)))
(apdl-up-block))
((match-end 2) ; end keyword
(setq eb-keyword
(buffer-substring-no-properties
(match-beginning 2) (match-end 2)))
(apdl-skip-block-backwards)))
(forward-word)
(setq pos (point)
bb-keyword (buffer-substring-no-properties
(match-beginning 0) pos)
;; pos (1+ pos); FIXME: bb-arg is eating commas
eol (apdl-position 'eol)
bb-arg (save-excursion
(save-restriction
(goto-char pos)
(while (and (skip-syntax-forward "^<" eol)
(apdl-in-string-p)
(not (forward-char 1))))
(skip-syntax-backward " ")
(buffer-substring-no-properties pos (point)))))
(if (member-ignore-case
eb-keyword (cdr (assoc-string
bb-keyword apdl-block-match-alist 1)))
(progn
(message "`%s' matches `%s%s'" eb-keyword bb-keyword bb-arg)
(when (pos-visible-in-window-p)
(sit-for apdl-blink-matching-delay)))
(error "Block keywords `%s' and `%s' do not match"
bb-keyword eb-keyword)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; hiding regions heavily borrowed from M. Dahls hide-region.el
(defun apdl-hide-region ()
"Hide a region by making an invisible overlay over it.
Put some markers (`apdl-hide-region-before-string',
`apdl-hide-region-after-string') around and save the overlay in
the `apdl-hide-region-overlays' \"overlay ring\"."
(interactive)
(let ((new-overlay (make-overlay (mark) (point))))
(push new-overlay apdl-hide-region-overlays)
(overlay-put new-overlay 'invisible t)
(overlay-put new-overlay 'intangible t)
(overlay-put new-overlay 'before-string
(if apdl-hide-region-propertize-markers
(propertize apdl-hide-region-before-string
'font-lock-face 'region)
apdl-hide-region-before-string))
(overlay-put new-overlay 'after-string
(if apdl-hide-region-propertize-markers
(propertize apdl-hide-region-after-string
'font-lock-face 'region)
apdl-hide-region-after-string))))
(defun apdl-hide-number-blocks ()
"Hide all number blocks (nblock, eblocks, cmblocks) in file.
These constructs appear in WorkBench created solver input files."
(interactive)
(let ((p-orig (point))
p1
p2
lines)
(message "Hiding number blocks ...")
(goto-char (point-min))
(while (re-search-forward "nblock\\|eblock\\|cmblock" nil t)
(setq p1 (point))
(re-search-forward "^-1\\|^cmsel\\|^d" nil nil)
(setq p2 (point)
lines (count-lines p1 p2))
(when (> lines 5) ; only hide blocks if larger then 5 lines
(goto-char p1)
(forward-line 3) ; show one line of numbers before markers
;;(set-mark (point))
(push-mark (point) t nil) ; no message, no activated mark
(goto-char p2)
(forward-line -2) ; show one line of numbers after markers
(end-of-line)
(apdl-hide-region)))
(goto-char p-orig)))
(defun apdl-unhide-number-blocks ()
"Unhide all hidden regions in the current buffer."
(interactive)
(while apdl-hide-region-overlays
(if (car apdl-hide-region-overlays)
(progn
(delete-overlay (car apdl-hide-region-overlays))
(setq apdl-hide-region-overlays (cdr apdl-hide-region-overlays))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; --- Abbreviations ---
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(unless apdl-mode-abbrev-table
(let ((ac abbrevs-changed)) ; inhibit offer to save .abbrev_defs
(define-abbrev-table 'apdl-mode-abbrev-table ())
(define-abbrev apdl-mode-abbrev-table
"`1" "finish\n/clear\n!y\n" ) ; the first 1 one
(define-abbrev apdl-mode-abbrev-table
"`2" "*afun,deg\n" ) ; the 2nd one ;-)
(define-abbrev apdl-mode-abbrev-table
"`3" "sqrt(3)/2" ) ; the 3rd
(define-abbrev apdl-mode-abbrev-table "`s" "" 'apdl-skeleton-separator-line)
(define-abbrev apdl-mode-abbrev-table "`ss" "" 'apdl-skeleton-section-separator)
(define-abbrev apdl-mode-abbrev-table "`i" "" 'apdl_if)
(define-abbrev apdl-mode-abbrev-table "`d" "" 'apdl_do)
(define-abbrev apdl-mode-abbrev-table
"`p" "*dim,Dir,string,248 ! maximum of 248 characters!\nDir(1) = \
'/HOME/uidg1626/development/report/ej/95ks91leg0/'\n\
/syp,ls,Dir(1)\n") ; for path
(define-abbrev apdl-mode-abbrev-table "`p" "" 'apdl-insert-pi)
(define-abbrev apdl-mode-abbrev-table "`if" "" 'apdl-if)
(define-abbrev apdl-mode-abbrev-table "`ie" "" 'apdl-if-then)
(define-abbrev apdl-mode-abbrev-table "`do" "" 'apdl-do)
(define-abbrev apdl-mode-abbrev-table "`e"
"/eof ----------------------------------------\n"
(lambda () (indent-according-to-mode)))
(define-abbrev apdl-mode-abbrev-table
"`c" "!! ========================================\n"
(lambda () (indent-according-to-mode)))
(define-abbrev apdl-mode-abbrev-table "`t" "/title,"
(lambda () (indent-according-to-mode)))
(setq abbrevs-changed ac))) ; reset `abbrevs-changed' to previous
; state
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; --- Bug reporting ---
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun apdl-submit-bug-report () ; from Octave
"Open an Emacs mail buffer with an APDL-Mode bug report."
(interactive)
(require 'reporter)
(let ((salutation))
(when (y-or-n-p "Do you want to write a bug report? ")
(setq salutation
"Please describe briefly what your problem is and
which actions triggered the bug. A self contained,
reproducible test case would be advantageous.")
(reporter-submit-bug-report
apdl-maintainer-address
"APDL-Mode" ; becomes prefix for the subject line
(list
;; constants
'apdl-mode-version
'apdl-mode-update
'apdl-mode-install-directory
;; 'apdl-ansys-version ; is in -ansys-install-directory included
;; variables
'apdl-initialised-flag
'apdl-current-ansys-version
'apdl-is-unix-system-flag
;; defcustoms
'apdl-parameter-help-duration
'apdl-hide-region-before-string
'apdl-hide-region-after-string
'apdl-hide-region-propertize-markers
'apdl-highlighting-level
'apdl-dynamic-highlighting-flag
'apdl-indicate-empty-lines-flag
'apdl-comment-padding
'apdl-comment-add
'apdl-code-comment-column
'apdl-auto-indent-flag
'apdl-indent-comment-suffix
'apdl-ruler-wide-flag
'apdl-require-spaces-flag
'apdl-blink-matching-block-flag
'apdl-blink-matching-delay
'apdl-block-offset
'apdl-outline-string
'apdl-mode-hook
'apdl-align-rules-list
'apdl-license-occur-regexp
'apdl-job
'apdl-license-categories
'apdl-license
'apdl-no-of-processors
'apdl-blink-delay
'apdl-blink-region-flag
'apdl-username ; 20.4.0
'apdl-ansys-install-directory
'apdl-ansys-program
'apdl-ansys-launcher
'apdl-ansys-wb
'apdl-ansys-help-program
'apdl-ansys-help-path
'apdl-lmutil-program
'apdl-license-file
'apdl-ansysli-servers
'apdl-wb-custom-template-directory ; 20.4.0
)
nil
nil
salutation))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; --- dynamic highlighting ---
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ---- Restrictions ----
;; Variables or 'parameters' in APDL parlance:
;; 1.) Begin with a letter
;; 2.) Contain only letters, numbers and the underscore '_'
;; 3.) Have no more than 32 characters
;; 4.) Any variable ending with an underscore are *not* shown
;; with the *STATUS command
;; 5.) The maximum number of parameter (< 5000) is retrieved by
;; *GET,par,PARM,,MAX
;; 6.) (A<B) returns the value of A when A is less than B, B otherwise!
(defun apdl-asterisk-regexp(string)
"Regexp STRING representing an asterisk."
(when (= (elt string 0) ?*)
(setq string (concat "\\" string)))
string)
(defun apdl-string-length-predicate (s1 s2)
"Return t when string S1 is larger then S2."
(< (length s1) (length s2)))
(defun apdl-find-duplicate-p (entry list)
"Return t when ENTRY is already a member of LIST."
(let ((l list) p)
(while (and (not p) l)
(setq p (assoc-string entry (car l) 'ignore-case))
(pop l))
p))
;; with pseudo arguments _a _b _c in case of usage as
;; after-change-function. Underscore before variable removes compiler
;; warning about unused lexical variables.
(defun apdl-find-user-variables (&optional _a _b _c)
;; (defun apdl-find-user-variables ()
;; fontification is not working!? -TODO-
"Find all user variables in the current buffer.
Pre-process the findings into the variables `apdl-user -variables'
and `apdl-user-variable-regexp' for subsequent fontification.
Added pseudo arguments _A _B _C."
;; RESTRICTED: line-number-at-pos was introduced after Emacs 21.4
(interactive)
(save-excursion
(save-match-data
(let (res var com) ; Start with APDL *USE vars
(setq apdl-user-variables ())
(dolist (command apdl-variable-defining-commands)
(setq com (car command))
(goto-char (point-min))
(while (re-search-forward
;; take care of variables clashing with command names
(concat "\\(?:^\\|$\\)\\s-*" com
"\\s-*,\\s-*\\([[:alpha:]][[:alnum:]_]\\{0,31\\}\\)")
nil t)
(setq var (match-string-no-properties 1))
;; format line, comment, message, C***
(unless (or (apdl-in-string-or-comment-p)
(apdl-in-string-command-line-p)
(apdl-in-format-construct-p)
(apdl-find-duplicate-p var apdl-user-variables))
(add-to-list 'apdl-user-variables
;; (match-beginning 1)
(list var (line-number-at-pos))))))
;; APDL = assignment
(goto-char (point-min))
(while (re-search-forward
;; search for reserved variables as well
"\\_<\\([[:alpha:]_][[:alnum:]_]\\{0,31\\}\\)\\s-*="
nil t)
(setq var (match-string-no-properties 1))
(unless
(or (apdl-in-string-or-comment-p)
(apdl-in-string-command-line-p)
(apdl-in-format-construct-p)
(apdl-find-duplicate-p var apdl-user-variables))
(add-to-list 'apdl-user-variables
(list var (line-number-at-pos)))))
;; we must sort the variables according to their occurrence
;; for the display
(setq apdl-user-variables
(sort apdl-user-variables
(if (version< "24" emacs-version)
(lambda (arg1 arg2)
(< (cadr arg1) (cadr arg2)))
(lambda (arg1 arg2)
(< (cadr arg1) (cadr arg2))))))
;; make the regexp for fontification
(setq res (mapcar #'car apdl-user-variables)
res (regexp-opt res 'symbols) ; words inhibits variables
; ending in _!
apdl-user-variable-regexp res)))))
;; in comments: OK
;; in * comments: apdl-in-asterisk-comment-p
;; clashes with command names
;; in format strings without % chars
(defun apdl-search-variable (variable limit)
"Search for the variable VARIABLE up to limit LIMIT.
This function is used as a highlighting function."
(save-excursion
(while (progn
(re-search-forward variable limit t)
(or (apdl-in-asterisk-comment-p)
(and (or (apdl-in-format-construct-p)
(apdl-in-string-command-line-p)
(not (looking-at "%")))))))))
(defun apdl-highlight-variable (limit)
"Find user variables from (point) to position LIMIT for highlighting.
Use variable `apdl-user-variable-regexp'."
(let ((r apdl-user-variable-regexp))
(re-search-forward r limit t)))
(defun apdl-higlight-percent-and-ampersand (limit)
"Find percent and ampersand up to position LIMIT for highlighting."
(let (res )
(while
(progn
(setq res (re-search-forward "%\\|&\\s-*$" limit t))
;; don't highlight in comments
(and res (apdl-in-comment-p))))
res))
(defun apdl-copy-buffer-line (buffer line-no)
"Return from buffer BUFFER the line with LINE-NO as a string."
(let (bol eol)
;; (set-buffer buffer)
(with-current-buffer buffer
(save-excursion
(goto-char (point-min))
(forward-line (- line-no 1))
(back-to-indentation)
(setq bol (point))
(end-of-line)
(setq eol (point))
(buffer-substring bol eol)))))
(defun apdl-buffer-line-marker (buffer line-no)
"Return from buffer BUFFER a marker at the beginning of the
LINE-NO line."
(with-current-buffer buffer
(save-excursion
(goto-char (point-min))
(forward-line (1- line-no))
(point-marker))))
(require 'button)
(define-button-type 'apdl-marker
'help-echo (purecopy "mouse-2 or <RET>: Skip to variable definition."))
(defun apdl-display-variables (arg)
"Displays APDL variable assignments in the current buffer.
Together with the corresponding line number. These numbers are
links to the respective APDL buffer. Clicking with the middle
mouse button (button-2) on these numbers is skipping the cursor
to the corresponding line number. You can also use the <TAB> key
and Shift <TAB> to skip between the links and type <RET> to
activate the links.
With a prefix argument ARG, the function evaluates the variable
at point. The result is shown in the command process buffer, if
an MAPDL process is running under Emacs (GNU-Linux only)."
(interactive "P")
(cond
(arg ; --- enquire value of variable
(unless (or (apdl-process-running-p) apdl-classics-flag)
(error "No MAPDL process running"))
(let* (
(pt (point))
(re "\s_[[:word:]]*")
(lbp (line-beginning-position))
(str (buffer-substring-no-properties
(save-excursion (+ pt (skip-chars-backward re lbp)))
(save-excursion (+ pt (skip-chars-forward re))))))
(if apdl-classics-flag
(progn
(kill-new (concat "*status," str "\n"))
(apdl-send-to-classics))
(comint-send-string (get-process apdl-process-name)
(concat "*status," str "\n"))
(display-buffer (concat "*" apdl-process-name "*")
'other-window))
(message (concat "Enquiring status for variable: " str))))
(t ; ---- display variable definitions
(apdl-find-user-variables) ; set apdl-user-variables
(let* ((current-buffer (buffer-name))
(buffer-name "*APDL-variables*")
(variable-buffer (get-buffer-create buffer-name))
str old-num com p1 p2
(markr (make-marker))
(num 0))
;;(set-buffer variable-buffer)
(with-current-buffer variable-buffer
(use-local-map button-buffer-map)
;; make buffer writable
(read-only-mode -1)
(kill-region (point-min) (point-max))
;; insert header
(insert
(propertize
(concat "-*- APDL variables of " current-buffer
" click with mouse-2 -*-\n")
'face 'match))
(insert (propertize " Line | Definition\n"
;; 'mouse-face 'highlight
'face 'bold))
;; insert variable lines
(dolist (command apdl-user-variables)
(setq old-num num
num (cadr command) ; cadr same as nth 1
com (apdl-copy-buffer-line current-buffer num)
markr (apdl-buffer-line-marker current-buffer num)
str (concat
(format "%5d " num)
(propertize "| "
;;'mouse-face 'highlight
'face 'bold)
com "\n"))
(unless (= num old-num)
(insert str)
(save-excursion
(forward-line -1)
(skip-chars-forward " ")
(setq p1 (point))
(skip-chars-forward "[:digit:]")
(setq p2 (point)))
(make-text-button p1 p2
'type 'apdl-marker
'action markr)))
(goto-char (point-min))
;; make buffer read-only
(read-only-mode 1))
(set-buffer current-buffer)
(display-buffer buffer-name 'other-window)))))
(defun apdl-customise-apdl ()
"Call the GNU-Emacs customisation facility for APDL-Mode."
(interactive)
(customize-group "APDL"))
(defun apdl-delete-other-window (&optional win)
"Delete the other, not selected Emacs window.
A window is in Emacs parlance a \"field\" where data is displayed
and possibly others in a window manager frame. The command
deletes only the window and not the buffer, i. e. not the data
itself. A frame can have many windows (and Emacs can also
control multiple frames, by the way), often the Emacs beginners
confuse the term window with an Emacs frame. Optional prefix
argument WIN is the WIN'th different window in the current frame.
The default argument is 1."
(interactive "p")
(unless win (setq win 1))
(let ((swin (selected-window)))
(other-window win)
(delete-window)
(select-window swin)))
(provide 'apdl-mode)
;;; apdl-mode.el ends here
;; Local Variables:
;; minor-mode: flycheck
;; indicate-empty-lines: t
;; show-trailing-whitespace: t
;; End: