update plantuml-mode

As plantuml.jar has added a new option “-language” which shows the keywords/builtins used in plantuml, the new plantuml-mode tries to take advantage of this feature. Here it is

;; plantuml-mode.el -- Major mode for plantuml

;; Author: Zhang Weize (zwz)
;; Keywords: uml ascii

;; You can redistribute this program and/or modify it under the terms
;; of the GNU General Public License as published by the Free Software
;; Foundation; either version 2, or (at your option) any later
;; version.


;; A major mode for plantuml, see: http://plantuml.sourceforge.net/
;; Plantuml is an open-source tool in java that allows to quickly write :
;;     - sequence diagram,
;;     - use case diagram,
;;     - class diagram,
;;     - activity diagram,
;;     - component diagram,
;;     - state diagram
;;     - object diagram
;; using a simple and intuitive language.

;; version 0.2, 2010-09-20 Initialize the keywords from the -language output of plantuml.jar instead of the hard-coded way.
;; version 0.1, 2010-08-25 First version

(require 'thingatpt)

(defgroup plantuml-mode nil
  "Major mode for editing plantuml file."
  :group 'languages)

(defvar plantuml-jar-path (expand-file-name "~/plantuml.jar"))

(defvar plantuml-mode-hook nil "Standard hook for plantuml-mode.")

(defvar plantuml-mode-version nil "plantuml-mode version string.")

(defvar plantuml-mode-map nil "Keymap for plantuml-mode")

;;; syntax table
(defvar plantuml-mode-syntax-table
  (let ((synTable (make-syntax-table)))
    (modify-syntax-entry ?' "< b" synTable)
    (modify-syntax-entry ?\n "> b" synTable)
    (modify-syntax-entry ?! "w" synTable)
    (modify-syntax-entry ?@ "w" synTable)
    (modify-syntax-entry ?# "'" synTable)
  "Syntax table for `plantuml-mode'.")

(defvar plantuml-types nil)
(defvar plantuml-keywords nil)
(defvar plantuml-preprocessors nil)
(defvar plantuml-builtins nil)

;; keyword completion
(defvar plantuml-kwdList nil "plantuml keywords.")

;;; font-lock

(defun plantuml-init ()
  "Initialize the keywords or builtins from the cmdline language output"
  (unless (file-exists-p plantuml-jar-path)
    (error "Could not find plantuml.jar at %s" plantuml-jar-path))
    (shell-command (concat "java -jar "
                           (shell-quote-argument plantuml-jar-path)
                           " -language") (current-buffer))
    (goto-char (point-min))
    (let ((found (search-forward ";" nil nil))
          (word "")
          (count 0)
          (pos 0))
      (while found
        (setq word (current-word))
        (if (string= word "EOF") (setq found nil)
            ;; else
            (setq count (string-to-number (current-word)))
            (beginning-of-line 2)
            (setq pos (point))
            (forward-line count)
            (cond ((string= word "type")
                   (setq plantuml-types
                      (buffer-substring-no-properties pos (point)))))
                  ((string= word "keyword")
                   (setq plantuml-keywords
                      (buffer-substring-no-properties pos (point)))))
                  ((string= word "preprocessor")
                   (setq plantuml-preprocessors
                      (buffer-substring-no-properties pos (point)))))
                  (t (setq plantuml-builtins
                             (buffer-substring-no-properties pos (point)))))))
;;                  ((string= word "skinparameter")
;;                  ((string= word "color")))
            (setq found (search-forward ";" nil nil)))))))

(unless plantuml-kwdList
  (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))
  (defvar plantuml-preprocessors-regexp (concat "^\\s *" (regexp-opt plantuml-preprocessors 'words)))

  (setq plantuml-font-lock-keywords
          (,plantuml-types-regexp . font-lock-type-face)
          (,plantuml-keywords-regexp . font-lock-keyword-face)
          (,plantuml-builtins-regexp . font-lock-builtin-face)
          (,plantuml-preprocessors-regexp . font-lock-preprocessor-face)
          ;; note: order matters

  (setq plantuml-kwdList (make-hash-table :test 'equal))
  (mapc (lambda (x) (puthash x t plantuml-kwdList)) plantuml-types)
  (mapc (lambda (x) (puthash x t plantuml-kwdList)) plantuml-keywords)
  (mapc (lambda (x) (puthash x t plantuml-kwdList)) plantuml-builtins)
  (mapc (lambda (x) (puthash x t plantuml-kwdList)) plantuml-preprocessors)
  (put 'plantuml-kwdList 'risky-local-variable t)

  ;; clear memory
  (setq plantuml-types nil)
  (setq plantuml-keywords nil)
  (setq plantuml-builtins nil)
  (setq plantuml-preprocessors nil)
  (setq plantuml-types-regexp nil)
  (setq plantuml-keywords-regexp nil)
  (setq plantuml-builtins-regexp nil)
  (setq plantuml-preprocessors-regexp nil))

(defun plantuml-complete-symbol ()
  "Perform keyword completion on word before cursor."
  (let ((posEnd (point))
        (meat (thing-at-point 'symbol))

    (when (not meat) (setq meat ""))

    (setq maxMatchResult (try-completion meat plantuml-kwdList))
    (cond ((eq maxMatchResult t))
          ((null maxMatchResult)
           (message "Can't find completion for \"%s\"" meat)
          ((not (string= meat maxMatchResult))
           (delete-region (- posEnd (length meat)) posEnd)
           (insert maxMatchResult))
          (t (message "Making completion list...")
             (with-output-to-temp-buffer "*Completions*"
                (all-completions meat plantuml-kwdList)
             (message "Making completion list...%s" "done")))))

(add-to-list 'auto-mode-alist '("\\.plu$" . plantuml-mode))

(defun plantuml-mode ()
  "Major mode for plantuml.

Shortcuts             Command Name
\\[plantuml-complete-symbol]      `plantuml-complete-symbol'"


;;  (python-mode) ; for indentation
  (setq major-mode 'plantuml-mode
        mode-name "plantuml")
  (set-syntax-table plantuml-mode-syntax-table)
  (use-local-map plantuml-mode-map)

  (make-local-variable 'font-lock-defaults)
  (setq font-lock-defaults '((plantuml-font-lock-keywords) nil t))

  (run-mode-hooks 'plantuml-mode-hook))

(provide 'plantuml-mode)

This entry was posted in Uncategorized and tagged , , , , , , , , , , , . Bookmark the permalink.

4 Responses to update plantuml-mode

  1. Joonhwan Lee says:

    Would it be possible for you to share this in github or something? It’d be great if you do!

  2. I just created a GitHub repo to store it, I did my best to not claim ownership of the code. Feel free to ask me to remove it if you don’t fancy it to be there.


  3. Reblogged this on Duong Bao Duy and commented:
    awesome about UML with org-mode on emacs.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s