From da2c301c1a3391bfeb55024a871153d552976619 Mon Sep 17 00:00:00 2001 From: Raymond Huang Date: Tue, 14 Aug 2018 14:08:29 -0700 Subject: [PATCH] Add autoindent support (#75) Add indent-line implementation --- plantuml-mode.el | 35 ++++++ test/plantuml-indentation-test.el | 166 +++++++++++++++++++++++++++++ test/resources/unindented.plantuml | 70 ++++++++++++ 3 files changed, 271 insertions(+) create mode 100644 test/plantuml-indentation-test.el create mode 100644 test/resources/unindented.plantuml diff --git a/plantuml-mode.el b/plantuml-mode.el index bf11586..a1c5cf8 100644 --- a/plantuml-mode.el +++ b/plantuml-mode.el @@ -340,6 +340,8 @@ Uses prefix (as PREFIX) to choose where to display it: (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))) + (defvar plantuml-indent-regexp-start "^[ \t]*\\(\\(?:.*\\)?\s*\\(?:[<>.*a-z-|]+\\)?\s*\\(?:\\[[a-zA-Z]+\\]\\)?\s+if\\|alt\\|else\\|note\s+over\\|note\sas\s.*\\|note\s+\\(\\(?:\\(?:buttom\\|left\\|right\\|top\\)\\)\\)\\(?:\s+of\\)?\\|\\(?:class\\|enum\\|package\\)\s+.*{\\)") + (defvar plantuml-indent-regexp-end "^[ \t]*\\(endif\\|else\\|end\\|end\s+note\\|.*}\\)") (setq plantuml-font-lock-keywords `( @@ -390,6 +392,38 @@ Uses prefix (as PREFIX) to choose where to display it: (all-completions meat plantuml-kwdList))) (message "Making completion list...%s" "done"))))) + +;; indentation + + +(defun plantuml-current-block-indentation () + (save-excursion + (let ((relative-depth 0)) + (while (>= relative-depth 0) + (forward-line -1) + (if (bobp) + (setq relative-depth -2)) ;end fast + (if (looking-at plantuml-indent-regexp-end) + (setq relative-depth (1+ relative-depth))) + (if (looking-at plantuml-indent-regexp-start) + (setq relative-depth (1- relative-depth)))) + + (if (= -2 relative-depth) + 0 + (+ tab-width (current-indentation)))))) + +(defun plantuml-indent-line () + (interactive) + (save-excursion + (beginning-of-line) + (if (bobp) + (indent-line-to 0) + (let ((offset (plantuml-current-block-indentation))) + (when (looking-at plantuml-indent-regexp-end) + (setq offset (max (- offset tab-width) 0))) + (indent-line-to offset))))) + + ;;;###autoload (add-to-list 'auto-mode-alist '("\\.\\(plantuml\\|pum\\|plu\\)\\'" . plantuml-mode)) @@ -406,6 +440,7 @@ Shortcuts Command Name (set (make-local-variable 'comment-end) "'/") (set (make-local-variable 'comment-multi-line) t) (set (make-local-variable 'comment-style) 'extra-line) + (set (make-local-variable 'indent-line-function) 'plantuml-indent-line) (setq font-lock-defaults '((plantuml-font-lock-keywords) nil t))) (defun plantuml-deprecation-warning () diff --git a/test/plantuml-indentation-test.el b/test/plantuml-indentation-test.el new file mode 100644 index 0000000..a0a59e6 --- /dev/null +++ b/test/plantuml-indentation-test.el @@ -0,0 +1,166 @@ +;;; plantuml-mode-indentation-test.el --- PlantUML Mode indentation tests -*- lexical-binding: t; -*- + +;; Author: Raymond Huang (rymndhng) +;; Maintainer: Carlo Sciolla (skuro) +;; URL: https://github.com/skuro/plantuml-mode + +;;; Commentary: + +;; Test setup is inspired/taken from clojure-mode-indentation-tests + +;;; Code: + +;; This is taken from https://github.com/clojure-emacs/clojure-mode/blob/master/test/clojure-mode-indentation-test.el +(defmacro check-indentation (description before after &optional var-bindings) + "Declare an ert test for indentation behaviour. +The test will check that the swift indentation command changes the buffer +from one state to another. It will also test that point is moved to an +expected position. +DESCRIPTION is a symbol describing the test. +BEFORE is the buffer string before indenting, where a pipe (|) represents +point. +AFTER is the expected buffer string after indenting, where a pipe (|) +represents the expected position of point. +VAR-BINDINGS is an optional let-bindings list. It can be used to set the +values of customisable variables." + (declare (indent 1)) + (let ((fname (intern (format "indentation/%s" description)))) + `(ert-deftest ,fname () + (let* ((after ,after) + (expected-cursor-pos (1+ (s-index-of "|" after))) + (expected-state (delete ?| after)) + ,@var-bindings) + (with-temp-buffer + (insert ,before) + (goto-char (point-min)) + (search-forward "|") + (delete-char -1) + (plantuml-mode) + (indent-according-to-mode) + + (should (equal expected-state (buffer-string))) + (should (equal expected-cursor-pos (point)))))))) + +(check-indentation toplevel-relationship + "|Nobody -> [APIGateway]" + "|Nobody -> [APIGateway]") + +(check-indentation package-block + "package APackage { +|A -> B +}" "package APackage { + |A -> B +}") + +(check-indentation nested-package + "package APackage { +|package AnotherPackage { +} +}" + "package APackage { + |package AnotherPackage { +} +}") + +(check-indentation empty-package + "|package Foo {}" + "|package Foo {}") + +(check-indentation relative-indent + "package APackage { +database Foo +|A --> B +} +}" + "package APackage { +database Foo + |A --> B +} +}" + ) + +(check-indentation note-as + "note as N1 +|This is a note +end note" + "note as N1 + |This is a note +end note" + ) + +(check-indentation note-of + "note right of Foo +|This is a note +end note" + "note right of Foo + |This is a note +end note" + ) + +(check-indentation alt + "alt choice 1 +|A -> B +end +" + "alt choice 1 + |A -> B +end +") + +(check-indentation alt-end + "alt choice 1 + A -> B +|end +" + "alt choice 1 + A -> B +|end +") + +(check-indentation alt-else + "alt choice 1 +|else +end +" + "alt choice 1 +|else +end +") + +(check-indentation alt-else-body + "alt choice 1 +else +|A -> B +end +" + "alt choice 1 +else + |A -> B +end +") + +(check-indentation alt-else-end + "alt choice 1 +else +|end +" + "alt choice 1 +else +|end +") + +(check-indentation alt-else-body + "alt choice 1 +else +|A -> B +end +" + "alt choice 1 +else + |A -> B +end +") + +(provide 'plantuml-indentation-test) + +;;; plantuml-mode-preview-test.el ends here diff --git a/test/resources/unindented.plantuml b/test/resources/unindented.plantuml new file mode 100644 index 0000000..2d1a94d --- /dev/null +++ b/test/resources/unindented.plantuml @@ -0,0 +1,70 @@ +/' This is a manual test for you to test different use-cases '/ +Nobody -> [APIGateway] + +package APackage { +A -> B +B -> A +} + +package "APP Stack" { +[APIGateway] --> [Lambda] +} + +package haha {} + +package "Streams Stack" { +database Kinesis +[Lambda] --> Kinesis +} + +package foo { +package bar { +foo --> bar +} + +package bar { +foo --> bar +} + +} + + +package "Roles And Policies" { +[Lambda] --> [IAM Roles] +[APIGateway] --> [IAM Roles] +} + +package "SharedResources" { +[Lambda] ----> [LambdaCodeBucket] + +note as N1 +This belongs to a separate set +of resources we should clean up +separately. +end note +} + +note right of Lambda +This thing is end of life +end note + +note left of Nobody +There is no traffic coming +into the service. +end note + + +@startuml + +participant API +participant Instance + +alt deploy success +Instance -> API: Deploy successful +else deploy failure +Instance -> API: Deploy failed +else deploy timeout +Instance -> API: Deploy failed +end + +@enduml