File 0440-Improve-strings-with-indent-region.patch of Package erlang
From aca91020b143c0ac96d775135cdae5f1f5852858 Mon Sep 17 00:00:00 2001
From: Dan Gudmundsson <dgud@erlang.org>
Date: Fri, 13 Dec 2024 12:47:12 +0100
Subject: [PATCH] Improve strings with indent-region
Indent region could indent multiline strings.
Improve that by trying move outside of the string before parsing the
function.
This aint perfect since we use emacs builtin knowledge if we are in a
string or not, and that might falter with triple-qouted strings.
---
lib/tools/emacs/erlang.el | 68 +++++++++++++------
.../test/emacs_SUITE_data/comprehensions | 5 +-
lib/tools/test/emacs_SUITE_data/type_specs | 34 ++++++++++
3 files changed, 85 insertions(+), 22 deletions(-)
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index f582c198ad..bf36f05189 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -2715,6 +2715,7 @@ This is automagically called by the user level function `indent-region'."
(goto-char beg)
(beginning-of-line)
(setq indent-point (point))
+ (erlang-string-start)
(erlang-beginning-of-clause)
;; Parse the Erlang code from the beginning of the clause to
;; the beginning of the region.
@@ -2795,7 +2796,6 @@ This is automagically called by the user level function `indent-region'."
(defmacro erlang-push (x stack) (list 'setq stack (list 'cons x stack)))
(defmacro erlang-pop (stack) (list 'setq stack (list 'cdr stack)))
-
(defun erlang-calculate-indent (&optional parse-start)
"Compute appropriate indentation for current line as Erlang code.
Return nil if line starts inside string, t if in a comment."
@@ -2804,7 +2804,8 @@ Return nil if line starts inside string, t if in a comment."
(case-fold-search nil)
(state nil))
(if parse-start
- (goto-char parse-start)
+ (goto-char parse-start)
+ (erlang-string-start)
(erlang-beginning-of-clause))
(while (< (point) indent-point)
(let ((pt (point)))
@@ -2821,7 +2822,8 @@ Return nil if line starts inside string, t if in a comment."
(save-excursion
(let ((starting-point (point))
(case-fold-search nil)
- (state nil))
+ (state nil))
+ (erlang-string-start)
(erlang-beginning-of-clause)
(while (< (point) starting-point)
(setq state (erlang-partial-parse (point) starting-point state)))
@@ -2834,12 +2836,24 @@ Value is list (stack token-start token-type in-what)."
(goto-char from) ; Start at the beginning
(erlang-skip-blank to)
(let ((cs (char-syntax (following-char)))
- (stack (car state))
- (token (point))
- in-what)
+ (stack (car state))
+ (token (point))
+ in-what)
(cond
-
- ;; Done: Return previous state.
+ ((and stack (eq (car (car stack)) 'string))
+ (goto-char (car (cdr (car stack)))) ;; String start
+ (condition-case nil
+ (progn
+ (forward-sexp 1)
+ (if (<= (point) to)
+ (erlang-pop stack)
+ (setq in-what 'string)
+ ))
+ (error
+ (setq in-what 'string)
+ (goto-char to))))
+
+ ;; Done: Return previous state.
((>= token to)
(setq token (nth 1 state))
(setq cs (nth 2 state))
@@ -2922,16 +2936,18 @@ Value is list (stack token-start token-type in-what)."
(forward-sexp 1))
;; String: Try to skip over it. (Catch error if not complete.)
((= cs ?\")
- (condition-case nil
- (progn
- (forward-sexp 1)
- (if (> (point) to)
- (progn
- (setq in-what 'string)
- (goto-char to))))
- (error
- (setq in-what 'string)
- (goto-char to))))
+ (condition-case nil
+ (progn
+ (forward-sexp 1)
+ (if (> (point) to)
+ (progn
+ (erlang-push (list 'string token (current-column)) stack)
+ (setq in-what 'string)
+ (goto-char to))
+ ))
+ (error
+ (setq in-what 'string)
+ (goto-char to))))
;; Expression prefix e.i. $ or ^ (Note ^ can be in the character
;; literal $^ or part of string and $ outside of a string denotes
@@ -3492,6 +3508,18 @@ commands."
;; The current implementation makes it hopeless to use the functions as
;; subroutines in more complex commands. /andersl
+(defun erlang-string-start ()
+ "If inside a string (or comment), move to the beginning of the string"
+
+ ;; This is not perfect because of erlang.el handling of multiline strings but better than before
+ (beginning-of-line)
+ (let ((string-start-pos (nth 8 (syntax-ppss))))
+ (while string-start-pos
+ (goto-char string-start-pos)
+ (beginning-of-line) ;; Hack to handle "" inside """ """
+ (setq string-start-pos (nth 8 (syntax-ppss)))
+ )))
+
(defun erlang-beginning-of-clause (&optional arg)
"Move backward to previous start of clause.
With argument, do this that many times.
@@ -3508,11 +3536,11 @@ Return t unless search stops due to end of buffer."
(forward-char 1))
(forward-char -1)
(if (looking-at "\\`\n")
- (forward-char 1))))
+ (forward-char 1))))
;; The regexp matches a function header that isn't
;; included in a string.
(and (re-search-forward "\\(\\`\\|\\`\n\\|[^\\]\n\\)\\(-?[a-z]\\|'\\|-\\)"
- nil 'move (- arg))
+ nil 'move (- arg))
(let ((beg (match-beginning 2)))
(and beg (goto-char beg))
t)))
diff --git a/lib/tools/test/emacs_SUITE_data/comprehensions b/lib/tools/test/emacs_SUITE_data/comprehensions
index 002c9140ad..f818db3872 100644
--- a/lib/tools/test/emacs_SUITE_data/comprehensions
+++ b/lib/tools/test/emacs_SUITE_data/comprehensions
@@ -15,13 +15,14 @@ list() ->
#record{a=X} <- lists:seq(1, 10),
true = (X rem 2)
],
- Result2 = [X || <<X:32,_:32>> <= <<0:512>>,
+ Result2 = [X || <<X:32,_:32>> <:= <<0:512>>,
true = (X rem 2)
],
Res = [ func(X,
arg2)
||
- #record{a=X} <- lists:seq(1, 10),
+ #record{a=X} <:- lists:seq(1, 10) &&
+ {B,X} <:- lists:zip("asdas", "bewre"),
true = (X rem 2)
],
Result1.
diff --git a/lib/tools/test/emacs_SUITE_data/type_specs b/lib/tools/test/emacs_SUITE_data/type_specs
index a72e90cf57..ccb5176e64 100644
--- a/lib/tools/test/emacs_SUITE_data/type_specs
+++ b/lib/tools/test/emacs_SUITE_data/type_specs
@@ -2,6 +2,7 @@
%% Copyright Ericsson AB 2017. All Rights Reserved.
%% Tests how types and specs are indented (also that the editor can parse them)
+%% Verifies -doc attributes and basic testing of strings as well
%% May need improvements
@@ -136,3 +137,36 @@
-opaque attributes_data() ::
[{'column', column()} | {'line', info_line()} |
{'text', string()}] | {line(),column()}.
+
+
+%% Test multiline strings as well
+%% since the tests works by removing indentation and then
+%% adding them again strings can only be tested without leading spaces
+
+-doc """
+startline
+second line zero indentation
+" String indented to steps"
+last not indented
+""".
+
+%% Uncommment and test manually
+%% more_strings() ->
+%% """
+%% ok, This string
+%% should not be changed
+%% column 0
+%% """,
+%% foo.
+
+func2() ->
+ "
+asd
+asd
+asd
+",
+ foo.
+
+func3() ->
+ "",
+ asd.
--
2.43.0