🆕Multiple run modes, now including JAR and SERVER (#96)
It is now possible to support many execution modes, currently available are: - `jar`: the traditional way of running PlantUML from `plantuml-mode` - `server`: ask a [`plantuml-server`](https://github.com/plantuml/plantuml-server) instance to run the preview (defaults to https://www.plantuml.com/plantuml)
This commit is contained in:
parent
698a248549
commit
27d48942a6
22
README.md
22
README.md
|
@ -35,6 +35,7 @@ You can also download the latest version of PlantUML straight into `plantuml-jar
|
|||
- Syntax highlight
|
||||
- Autocompletion
|
||||
- Preview of buffer or region
|
||||
- [EXPERIMENTAL] Use either local JAR or remote server for preview
|
||||
|
||||
# Enable the major mode
|
||||
|
||||
|
@ -88,6 +89,27 @@ Then you can edit a `plantuml` code block with `plantuml-mode` by hitting `C-'`
|
|||
|
||||
When in the `plantuml-mode` buffer you can then hit again `C-'` to return to the original `org-mode` document.
|
||||
|
||||
# Execution modes
|
||||
|
||||
**EXPERIMENTAL**
|
||||
|
||||
As of `v1.3.0` support is added for switching execution mode. The following two modes are available:
|
||||
|
||||
- `jar` (default) to run PlantUML as a local JAR file. This is the traditional system used by `plantuml-mode`
|
||||
- `server` (experimental) to let an instance of [`plantuml-server`](https://github.com/plantuml/plantuml-server) render the preview
|
||||
|
||||
You can customize `plantuml-default-exec-mode` or run `plantuml-set-exec-mode` from a `plantuml-mode` buffer to switch modes.
|
||||
|
||||
## Configure server rendering
|
||||
|
||||
When selecting `server` execution modes, you can customize the following variable to set the server to use for rendering:
|
||||
|
||||
```
|
||||
plantuml-server-url
|
||||
```
|
||||
|
||||
It defaults to `"https://www.plantuml.com/plantuml"`.
|
||||
|
||||
# Migration from `puml-mode`
|
||||
|
||||
If you were previously using `puml-mode`, you should change any reference to a `puml-..` variable or function to its `plantuml-..` counterpart. Most notably, `puml-plantuml-jar-path` is now just `plantuml-jar-path`.
|
||||
|
|
195
plantuml-mode.el
195
plantuml-mode.el
|
@ -37,6 +37,7 @@
|
|||
|
||||
;;; Change log:
|
||||
;;
|
||||
;; version 1.3.0, 2019-05-31 Added experimental support for multiple rendering modes and, specifically, preview using a PlantUML server
|
||||
;; version 1.2.11, 2019-04-09 Added `plantuml-download-jar'
|
||||
;; version 1.2.10, 2019-04-03 Avoid messing with window layouts and buffers -- courtesy of https://github.com/wailo
|
||||
;; version 1.2.9, Revamped indentation support, now working with a greater number of keywords
|
||||
|
@ -111,12 +112,24 @@
|
|||
:type '(repeat string)
|
||||
:group 'plantuml)
|
||||
|
||||
(defcustom plantuml-server-url "https://www.plantuml.com/plantuml"
|
||||
"The base URL of the PlantUML server."
|
||||
:type 'string
|
||||
:group 'plantuml)
|
||||
|
||||
(defcustom plantuml-default-exec-mode 'server
|
||||
"Default execution mode for PlantUML. Valid values are:
|
||||
- `jar': run PlantUML as a JAR file (requires a local install of the PlantUML JAR file, see `plantuml-jar-path'"
|
||||
:type 'symbol
|
||||
:group 'plantuml
|
||||
:options '(jar server))
|
||||
|
||||
(defcustom plantuml-suppress-deprecation-warning t
|
||||
"To silence the deprecation warning when `puml-mode' is found upon loading."
|
||||
:type 'boolean
|
||||
:group 'plantuml)
|
||||
|
||||
(defun plantuml-render-command (&rest arguments)
|
||||
(defun plantuml-jar-render-command (&rest arguments)
|
||||
"Create a command line to execute PlantUML with arguments (as ARGUMENTS)."
|
||||
(let* ((cmd-list (append plantuml-java-args (list (expand-file-name plantuml-jar-path)) plantuml-jar-args arguments))
|
||||
(cmd (mapconcat 'identity cmd-list "|")))
|
||||
|
@ -144,6 +157,25 @@
|
|||
;; keyword completion
|
||||
(defvar plantuml-kwdList nil "The plantuml keywords.")
|
||||
|
||||
;; PlantUML execution mode
|
||||
(defvar-local plantuml-exec-mode plantuml-default-exec-mode
|
||||
"The Plantuml execution mode. See `plantuml-default-exec-mode' for acceptable values.")
|
||||
|
||||
(defun plantuml-set-exec-mode (mode)
|
||||
"Set the execution mode MODE for PlantUML."
|
||||
(interactive (let* ((completion-ignore-case t)
|
||||
(supported-modes '("jar" "server")))
|
||||
(completing-read (format "Exec mode [%s]: " plantuml-exec-mode)
|
||||
supported-modes
|
||||
nil
|
||||
t
|
||||
nil
|
||||
nil
|
||||
plantuml-exec-mode)))
|
||||
(if (member mode '("jar" "server"))
|
||||
(setq plantuml-exec-mode (intern mode))
|
||||
(error (concat "Unsupported mode:" mode))))
|
||||
|
||||
(defun plantuml-enable-debug ()
|
||||
"Enables debug messages into the *PLANTUML Messages* buffer."
|
||||
(interactive)
|
||||
|
@ -185,20 +217,40 @@
|
|||
(xml-node-children)
|
||||
(first))))
|
||||
(message (concat "Downloading PlantUML v" version " into " plantuml-jar-path))
|
||||
(url-copy-file (format "https://search.maven.org/remotecontent?filepath=net/sourceforge/plantuml/plantuml/%s/plantuml-%s.jar" version version) plantuml-jar-path)
|
||||
(kill-buffer))
|
||||
(message "Aborted.")))
|
||||
(url-copy-file (format "https://search.maven.org/remotecontent?filepath=net/sourceforge/plantuml/plantuml/%s/plantuml-%s.jar" version version) plantuml-jar-path t)
|
||||
(kill-buffer)))
|
||||
(message "Aborted."))
|
||||
(message "Aborted.")))
|
||||
|
||||
(defun plantuml-init ()
|
||||
"Initialize the keywords or builtins from the cmdline language output."
|
||||
(defun plantuml-jar-get-language (buf)
|
||||
"Retrieve the language specification from the PlantUML JAR file and paste it into BUF."
|
||||
(unless (or (eq system-type 'cygwin) (file-exists-p plantuml-jar-path))
|
||||
(error "Could not find plantuml.jar at %s" plantuml-jar-path))
|
||||
(with-temp-buffer
|
||||
(with-current-buffer buf
|
||||
(let ((cmd-args (append (list plantuml-java-command nil t nil)
|
||||
(plantuml-render-command "-language"))))
|
||||
(plantuml-jar-render-command "-language"))))
|
||||
(apply 'call-process cmd-args)
|
||||
(goto-char (point-min)))
|
||||
(goto-char (point-min)))))
|
||||
|
||||
(defun plantuml-server-get-language (buf)
|
||||
"Retrieve the language specification from the PlantUML server and paste it into BUF."
|
||||
(let ((lang-url (concat plantuml-server-url "/language")))
|
||||
(with-current-buffer buf
|
||||
(url-insert-file-contents lang-url))))
|
||||
|
||||
(defun plantuml-get-language (mode buf)
|
||||
"Retrieve the language spec using the preferred PlantUML execution mode MODE. Paste the result into BUF."
|
||||
(let ((get-fn (pcase mode
|
||||
('jar #'plantuml-jar-get-language)
|
||||
('server #'plantuml-server-get-language))))
|
||||
(if get-fn
|
||||
(funcall get-fn buf)
|
||||
(error "Unsupported execution mode %s" mode))))
|
||||
|
||||
(defun plantuml-init (mode)
|
||||
"Initialize the keywords or builtins from the cmdline language output. Use exec mode MODE to load the language details."
|
||||
(with-temp-buffer
|
||||
(plantuml-get-language mode (current-buffer))
|
||||
(let ((found (search-forward ";" nil t))
|
||||
(word "")
|
||||
(count 0)
|
||||
|
@ -236,10 +288,10 @@
|
|||
|
||||
(defvar plantuml-output-type
|
||||
(if (not (display-images-p))
|
||||
"utxt"
|
||||
"txt"
|
||||
(cond ((image-type-available-p 'svg) "svg")
|
||||
((image-type-available-p 'png) "png")
|
||||
(t "utxt")))
|
||||
(t "txt")))
|
||||
"Specify the desired output type to use for generated diagrams.")
|
||||
|
||||
(defun plantuml-read-output-type ()
|
||||
|
@ -249,7 +301,7 @@
|
|||
(append
|
||||
(and (image-type-available-p 'svg) '("svg"))
|
||||
(and (image-type-available-p 'png) '("png"))
|
||||
'("utxt"))))
|
||||
'("txt"))))
|
||||
(completing-read (format "Output type [%s]: " plantuml-output-type)
|
||||
available-types
|
||||
nil
|
||||
|
@ -267,57 +319,105 @@ default output type for new buffers."
|
|||
(setq plantuml-output-type type))
|
||||
|
||||
(defun plantuml-is-image-output-p ()
|
||||
"Return true if the diagram output format is an image, false if it's text based."
|
||||
(not (equal "utxt" plantuml-output-type)))
|
||||
"Return non-nil if the diagram output format is an image, false if it's text based."
|
||||
(not (equal "txt" plantuml-output-type)))
|
||||
|
||||
(defun plantuml-output-type-opt ()
|
||||
"Create the flag to pass to PlantUML to produce the selected output format."
|
||||
(concat "-t" plantuml-output-type))
|
||||
(defun plantuml-jar-output-type-opt (output-type)
|
||||
"Create the flag to pass to PlantUML according to OUTPUT-TYPE.
|
||||
Note that output type `txt' is promoted to `utxt' for better rendering."
|
||||
(concat "-t" (pcase output-type
|
||||
("txt" "utxt")
|
||||
(_ output-type))))
|
||||
|
||||
(defun plantuml-start-process (buf)
|
||||
(defun plantuml-jar-start-process (buf)
|
||||
"Run PlantUML as an Emacs process and puts the output into the given buffer (as BUF)."
|
||||
(apply #'start-process
|
||||
"PLANTUML" buf plantuml-java-command
|
||||
`(,@plantuml-java-args
|
||||
,(expand-file-name plantuml-jar-path)
|
||||
,(plantuml-output-type-opt)
|
||||
,(plantuml-jar-output-type-opt plantuml-output-type)
|
||||
,@plantuml-jar-args
|
||||
"-p")))
|
||||
|
||||
(defun plantuml-preview-string (prefix string)
|
||||
"Preview diagram from PlantUML sources (as STRING), using prefix (as PREFIX)
|
||||
to choose where to display it:
|
||||
(defun plantuml-update-preview-buffer (prefix buf)
|
||||
"Show the preview in the preview buffer BUF.
|
||||
Window is selected according to PREFIX:
|
||||
- 4 (when prefixing the command with C-u) -> new window
|
||||
- 16 (when prefixing the command with C-u C-u) -> new frame.
|
||||
- else -> new buffer"
|
||||
(let ((b (get-buffer plantuml-preview-buffer)))
|
||||
(when b
|
||||
(kill-buffer b)))
|
||||
(let ((imagep (and (display-images-p)
|
||||
(plantuml-is-image-output-p))))
|
||||
(cond
|
||||
((= prefix 16) (switch-to-buffer-other-frame buf))
|
||||
((= prefix 4) (switch-to-buffer-other-window buf))
|
||||
(t (display-buffer buf)))
|
||||
(when imagep
|
||||
(with-current-buffer buf
|
||||
(image-mode)
|
||||
(set-buffer-multibyte t)))))
|
||||
|
||||
(let* ((imagep (and (display-images-p)
|
||||
(plantuml-is-image-output-p)))
|
||||
(process-connection-type nil)
|
||||
(buf (get-buffer-create plantuml-preview-buffer))
|
||||
(coding-system-for-read (and imagep 'binary))
|
||||
(coding-system-for-write (and imagep 'binary)))
|
||||
|
||||
(let ((ps (plantuml-start-process buf)))
|
||||
(defun plantuml-jar-preview-string (prefix string buf)
|
||||
"Preview the diagram from STRING by running the PlantUML JAR.
|
||||
Put the result into buffer BUF. Window is selected according to PREFIX:
|
||||
- 4 (when prefixing the command with C-u) -> new window
|
||||
- 16 (when prefixing the command with C-u C-u) -> new frame.
|
||||
- else -> new buffer"
|
||||
(let* ((process-connection-type nil)
|
||||
(ps (plantuml-jar-start-process buf)))
|
||||
(process-send-string ps string)
|
||||
(process-send-eof ps)
|
||||
(set-process-sentinel ps
|
||||
(lambda (_ps event)
|
||||
(unless (equal event "finished\n")
|
||||
(error "PLANTUML Preview failed: %s" event))
|
||||
(cond
|
||||
((= prefix 16)
|
||||
(switch-to-buffer-other-frame plantuml-preview-buffer))
|
||||
((= prefix 4)
|
||||
(switch-to-buffer-other-window plantuml-preview-buffer))
|
||||
(t (display-buffer plantuml-preview-buffer)))
|
||||
(when imagep
|
||||
(with-current-buffer plantuml-preview-buffer
|
||||
(image-mode)
|
||||
(set-buffer-multibyte t))))))))
|
||||
(plantuml-update-preview-buffer prefix buf)))))
|
||||
|
||||
(defun plantuml-server-preview-string (prefix string buf)
|
||||
"Preview the diagram from STRING as rendered by the PlantUML server.
|
||||
Put the result into buffer BUF and place it according to PREFIX:
|
||||
- 4 (when prefixing the command with C-u) -> new window
|
||||
- 16 (when prefixing the command with C-u C-u) -> new frame.
|
||||
- else -> new buffer"
|
||||
(let* ((url-request-location (concat plantuml-server-url "/" plantuml-output-type "/-base64-" (base64-encode-string string))))
|
||||
(save-current-buffer
|
||||
(save-match-data
|
||||
(url-retrieve url-request-location
|
||||
(lambda (status)
|
||||
;; TODO: error check
|
||||
(goto-char (point-min))
|
||||
;; skip the HTTP headers
|
||||
(while (not (looking-at "\n"))
|
||||
(forward-line))
|
||||
(kill-region (point-min) (+ 1 (point)))
|
||||
(copy-to-buffer buf (point-min) (point-max))
|
||||
(plantuml-update-preview-buffer prefix buf)))))))
|
||||
|
||||
(defun plantuml-exec-mode-preview-string (prefix mode string buf)
|
||||
"Preview the diagram from STRING using the execution mode MODE.
|
||||
Put the result into buffer BUF, selecting the window according to PREFIX:
|
||||
- 4 (when prefixing the command with C-u) -> new window
|
||||
- 16 (when prefixing the command with C-u C-u) -> new frame.
|
||||
- else -> new buffer"
|
||||
(let ((preview-fn (pcase mode
|
||||
('jar #'plantuml-jar-preview-string)
|
||||
('server #'plantuml-server-preview-string))))
|
||||
(if preview-fn
|
||||
(funcall preview-fn prefix string buf)
|
||||
(error "Unsupported execution mode %s" mode))))
|
||||
|
||||
(defun plantuml-preview-string (prefix string)
|
||||
"Preview diagram from PlantUML sources (as STRING), using prefix (as PREFIX)
|
||||
to choose where to display it."
|
||||
(let ((b (get-buffer plantuml-preview-buffer)))
|
||||
(when b
|
||||
(kill-buffer b)))
|
||||
|
||||
(let* ((imagep (and (display-images-p)
|
||||
(plantuml-is-image-output-p)))
|
||||
(buf (get-buffer-create plantuml-preview-buffer))
|
||||
(coding-system-for-read (and imagep 'binary))
|
||||
(coding-system-for-write (and imagep 'binary)))
|
||||
(plantuml-exec-mode-preview-string prefix plantuml-exec-mode string buf)))
|
||||
|
||||
(defun plantuml-preview-buffer (prefix)
|
||||
"Preview diagram from the PlantUML sources in the current buffer.
|
||||
|
@ -365,10 +465,11 @@ Uses prefix (as PREFIX) to choose where to display it:
|
|||
(plantuml-preview-region prefix (region-beginning) (region-end))
|
||||
(plantuml-preview-buffer prefix)))
|
||||
|
||||
(defun plantuml-init-once ()
|
||||
"Ensure initialization only happens once."
|
||||
(defun plantuml-init-once (&optional mode)
|
||||
"Ensure initialization only happens once. Use exec mode MODE to load the language details, which defaults to `plantuml-exec-mode'."
|
||||
(let ((mode (or mode plantuml-exec-mode)))
|
||||
(unless plantuml-kwdList
|
||||
(plantuml-init)
|
||||
(plantuml-init mode)
|
||||
(defvar plantuml-types-regexp (concat "^\\s *\\(" (regexp-opt plantuml-types 'words) "\\|\\<\\(note\\s +over\\|note\\s +\\(left\\|right\\|bottom\\|top\\)\\s +\\(of\\)?\\)\\>\\|\\<\\(\\(left\\|center\\|right\\)\\s +\\(header\\|footer\\)\\)\\>\\)"))
|
||||
(defvar plantuml-keywords-regexp (concat "^\\s *" (regexp-opt plantuml-keywords 'words) "\\|\\(<\\|<|\\|\\*\\|o\\)\\(\\.+\\|-+\\)\\|\\(\\.+\\|-+\\)\\(>\\||>\\|\\*\\|o\\)\\|\\.\\{2,\\}\\|-\\{2,\\}"))
|
||||
(defvar plantuml-builtins-regexp (regexp-opt plantuml-builtins 'words))
|
||||
|
@ -431,7 +532,7 @@ or it is followed by line end.")
|
|||
(setq plantuml-types-regexp nil)
|
||||
(setq plantuml-keywords-regexp nil)
|
||||
(setq plantuml-builtins-regexp nil)
|
||||
(setq plantuml-preprocessors-regexp nil)))
|
||||
(setq plantuml-preprocessors-regexp nil))))
|
||||
|
||||
(defun plantuml-complete-symbol ()
|
||||
"Perform keyword completion on word before cursor."
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
;;; plantuml-config-test.el --- tests for plantuml-mode configuration knobs -*- lexical-binding: t; -*-
|
||||
|
||||
;; Author: Carlo Sciolla
|
||||
;; Maintainer: Carlo Sciolla
|
||||
;; URL: https://github.com/skuro/plantuml-mode
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Test user-accessible configuration knobs
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'plantuml-mode)
|
||||
|
||||
(ert-deftest plantuml-config-test/set-exec-mode-happy-path ()
|
||||
"Test switching execution modes"
|
||||
(let ((orig-mode plantuml-exec-mode))
|
||||
;; happy flows:
|
||||
(plantuml-set-exec-mode "server")
|
||||
(should (equal 'server plantuml-exec-mode))
|
||||
(plantuml-set-exec-mode "jar")
|
||||
(should (equal 'jar plantuml-exec-mode))
|
||||
|
||||
(setq plantuml-exec-mode orig-mode)))
|
||||
|
||||
(ert-deftest plantuml-config-test/set-exec-mode-wrong-mode ()
|
||||
"Test setting the exec mode with the wrong text"
|
||||
(should-error (plantuml-set-exec-mode "turing-machine")))
|
||||
|
||||
(provide 'plantuml-mode-config-test)
|
||||
|
||||
;;; plantuml-config-test.el ends here
|
|
@ -13,11 +13,11 @@
|
|||
(should (equal `("-Djava.awt.headless=true" "-jar"
|
||||
,(expand-file-name "~/.plantuml/plantuml.jar")
|
||||
"-charset" "UTF-8")
|
||||
(plantuml-render-command)))
|
||||
(plantuml-jar-render-command)))
|
||||
|
||||
(setq-local plantuml-jar-path "/path/with spaces/plantuml.jar")
|
||||
(should (equal `("-Djava.awt.headless=true" "-jar" "/path/with spaces/plantuml.jar" "-charset" "UTF-8")
|
||||
(plantuml-render-command))))
|
||||
(plantuml-jar-render-command))))
|
||||
|
||||
(provide 'plantuml-mode-custom-jar-location-test)
|
||||
|
||||
|
|
|
@ -8,16 +8,19 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(defun assert-preview (puml output &optional format)
|
||||
(defun assert-preview (puml output &optional format mode)
|
||||
(if format
|
||||
(setq plantuml-output-type format)
|
||||
(setq plantuml-output-type "utxt"))
|
||||
(setq plantuml-output-type "txt"))
|
||||
(if mode
|
||||
(setq plantuml-exec-mode mode)
|
||||
(setq plantuml-exec-mode 'jar))
|
||||
(plantuml-preview-string 42 (read-test-file puml))
|
||||
(sleep-for 3)
|
||||
(should (equal (format-preview-output (replace-regexp-in-string " " "~" (read-test-file output)))
|
||||
(format-preview-output (replace-regexp-in-string " " "~" (read-preview-buffer))))))
|
||||
|
||||
(ert-deftest preview-utxt-test ()
|
||||
(ert-deftest preview-txt-test ()
|
||||
(setq-local plantuml-jar-path plantuml-test-jar-path)
|
||||
(assert-preview "a-b.puml" "a-b.txt"))
|
||||
|
||||
|
|
|
@ -53,15 +53,15 @@ Finally, the indented text in the buffer will be compared with AFTER."
|
|||
(with-temp-buffer
|
||||
;; fix the JAR location prior to mode initialization
|
||||
;; for some reason, plantuml-mode disregards the setq-local
|
||||
(setq-local plantuml-jar-path plantuml-test-jar-path)
|
||||
(plantuml-init-once)
|
||||
(setq plantuml-jar-path plantuml-test-jar-path)
|
||||
(plantuml-init-once 'jar)
|
||||
|
||||
(insert before)
|
||||
(goto-char (point-min))
|
||||
(plantuml-mode)
|
||||
;; use 2 spaces instead of one tab for indentation
|
||||
(setq-local indent-tabs-mode nil)
|
||||
(setq-local tab-width 2)
|
||||
(setq indent-tabs-mode nil)
|
||||
(setq tab-width 2)
|
||||
|
||||
(indent-region (point-min) (point-max))
|
||||
(should (equal (buffer-string) after))))
|
||||
|
|
Loading…
Reference in New Issue