* bug#20896: 25.0.50; [js-mode][FR] support chain syntax indentation
@ 2015-06-25 15:37 Rasmus
2015-06-26 0:14 ` Rasmus
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Rasmus @ 2015-06-25 15:37 UTC (permalink / raw)
To: 20896
Hi,
I would be lovely if js-mode would support the chain-syntax used by the
d3.js library. d3.js is used to making svg graphics. The syntax is very
readable if indentation is right:
var points = svg.selectAll(".scatter-dots")
.data(data)
.enter().append("path")
.more_funs();
var an_axis = axes.append("g")
.call(d3.svg.axis()
.scale(Scale)
.orient("bottom"));
Usually calls are factored out so the latter example is not so important
to be able to match. Just aligning on the first dot on the previous line
would be a big step forward.
I don't know if this is useful for other JS libraries than d3. Some d3
documentation mentioned this selector-mechanism was inspired by jQuery,
but I don't know this library well enough to say whether it would be
useful with that.
Thanks,
Rasmus
--
Not everything that goes around comes back around, you know
^ permalink raw reply [flat|nested] 7+ messages in thread
* bug#20896: 25.0.50; [js-mode][FR] support chain syntax indentation
2015-06-25 15:37 bug#20896: 25.0.50; [js-mode][FR] support chain syntax indentation Rasmus
@ 2015-06-26 0:14 ` Rasmus
2017-01-10 6:29 ` bug#20896: patch to add chained indentation Tom Tromey
2017-01-14 17:45 ` bug#20896: done Tom Tromey
2 siblings, 0 replies; 7+ messages in thread
From: Rasmus @ 2015-06-26 0:14 UTC (permalink / raw)
To: 20896
Hi,
Rasmus <rasmus@gmx.us> writes:
> var an_axis = axes.append("g")
> .call(d3.svg.axis()
> .scale(Scale)
> .orient("bottom"));
Actually, this case is not as crazy as first assumed and should ideally be
supported. Here's a pretty reasonable example (except for names being too
long):
plot.axes.yScale = d3.scale.ordinal()
.domain(d3.range(bar.ybins).map(function(d){return d*10;}))
.range(d3.range(bar.ybins)
.map(function(d,i) {
return plot.height-plot.height/bar.ybins * i;}));
Also, notice there's another, potential, indentation typo in this code.
The last "return" should be one character to the right IMO, i.e.
.map(function(d,i) {
return plot.height-plot.height/bar.ybins * i;}));
Thanks,
Rasmus
--
Dung makes an excellent fertilizer
^ permalink raw reply [flat|nested] 7+ messages in thread
* bug#20896: patch to add chained indentation
2015-06-25 15:37 bug#20896: 25.0.50; [js-mode][FR] support chain syntax indentation Rasmus
2015-06-26 0:14 ` Rasmus
@ 2017-01-10 6:29 ` Tom Tromey
2017-01-12 1:57 ` Dmitry Gutov
2017-01-14 17:45 ` bug#20896: done Tom Tromey
2 siblings, 1 reply; 7+ messages in thread
From: Tom Tromey @ 2017-01-10 6:29 UTC (permalink / raw)
To: 20896; +Cc: Daniel Colascione
This patch adds chained indentation, as requested in the bug. It comes
with some tests (added to a file that first appears in patch in another
bug -- I can commit these when the time comes, mostly I'm interested in
review).
Tom
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 0551f2a..1211631 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -552,6 +552,20 @@ js-indent-first-init
:safe 'symbolp
:group 'js)
+(defcustom js-chain-indent nil
+ "Use \"chained\" indentation.
+Chained indentation applies when the current line starts with \".\".
+If the previous expression also contains a \".\" at the same level,
+then the \".\"s will be lined up:
+
+ let x = svg.mumble()
+ .chained;
+"
+ :version "26.1"
+ :type 'boolean
+ :safe 'booleanp
+ :group 'js)
+
;;; KeyMap
(defvar js-mode-map
@@ -1808,6 +1822,62 @@ js--continued-expression-p
(and (progn (backward-char)
(not (looking-at "+\\+\\|--\\|/[/*]"))))))))))
+(defun js--skip-term-backward ()
+ "Skip a term before point; return t if a term was skipped."
+ (let ((term-skipped nil))
+ ;; Skip backward over balanced parens.
+ (let ((progress t))
+ (while progress
+ (setq progress nil)
+ ;; First skip whitespace.
+ (skip-syntax-backward " ")
+ ;; Now if we're looking at closing paren, skip to the opener.
+ ;; This doesn't strictly follow JS syntax, in that we might
+ ;; skip something nonsensical like "()[]{}", but it is enough
+ ;; if it works ok for valid input.
+ (when (memq (char-before) '(?\] ?\) ?\}))
+ (setq progress t term-skipped t)
+ (backward-list))))
+ ;; Maybe skip over a symbol.
+ (let ((save-point (point)))
+ (if (and (< (skip-syntax-backward "w_") 0)
+ (looking-at js--name-re))
+ ;; Skipped.
+ (progn
+ (setq term-skipped t)
+ (skip-syntax-backward " "))
+ ;; Did not skip, so restore point.
+ (goto-char save-point)))
+ (when (and term-skipped (> (point) (point-min)))
+ (backward-char)
+ (eq (char-after) ?.))))
+
+(defun js--skip-terms-backward ()
+ "Skip any number of terms backward.
+Move point to the earliest \".\" without changing paren levels.
+Returns t if successful, nil if no term was found."
+ (when (js--skip-term-backward)
+ ;; Found at least one.
+ (let ((last-point (point)))
+ (while (js--skip-term-backward)
+ (setq last-point (point)))
+ (goto-char last-point)
+ t)))
+
+(defun js--chained-expression-p ()
+ "A helper for js--proper-indentation that handles chained expressions.
+A chained expression is when the current line starts with '.' and the
+previous line also has a '.' expression.
+This function returns the indentation for the current line if it is
+a chained expression line; otherwise nil.
+This should only be called while point is at the start of the line."
+ (when js-chain-indent
+ (save-excursion
+ (when (and (eq (char-after) ?.)
+ (js--continued-expression-p)
+ (js--find-newline-backward)
+ (js--skip-terms-backward))
+ (current-column)))))
(defun js--end-of-do-while-loop-p ()
"Return non-nil if point is on the \"while\" of a do-while statement.
@@ -1984,6 +2054,7 @@ js--proper-indentation
;; At or after the first loop?
(>= (point) beg)
(js--array-comp-indentation bracket beg))))
+ ((js--chained-expression-p))
((js--ctrl-statement-indentation))
((js--multi-line-declaration-indentation))
((nth 1 parse-status)
diff --git a/test/lisp/progmodes/js-tests.el b/test/lisp/progmodes/js-tests.el
index de322f2..effd58c 100644
--- a/test/lisp/progmodes/js-tests.el
+++ b/test/lisp/progmodes/js-tests.el
@@ -69,6 +69,77 @@
(should (equal (buffer-substring (point-at-bol) (point-at-eol))
"\tdo_something();"))))
+(ert-deftest js-mode-indent-bug-20896-chain ()
+ (with-temp-buffer
+ (js-mode)
+ (setq-local js-chain-indent t)
+ (setq-local indent-tabs-mode nil)
+ (insert "let x = svg.mumble()\n.zzz")
+ (js-indent-line)
+ (should (equal (buffer-substring (point-at-bol) (point-at-eol))
+ " .zzz"))))
+
+(ert-deftest js-mode-indent-bug-20896-chain-comment ()
+ (with-temp-buffer
+ (js-mode)
+ (setq-local js-chain-indent t)
+ (setq-local indent-tabs-mode nil)
+ (insert "let x = svg.mumble() // line comment\n.zzz")
+ (js-indent-line)
+ (should (equal (buffer-substring (point-at-bol) (point-at-eol))
+ " .zzz"))))
+
+(ert-deftest js-mode-indent-bug-20896-chain-multi ()
+ (with-temp-buffer
+ (js-mode)
+ (setq-local js-chain-indent t)
+ (setq-local indent-tabs-mode nil)
+ ;; Must line up to the first "." at the same level.
+ (insert "let x = svg.selectAll().something()\n.zzz")
+ (js-indent-line)
+ (should (equal (buffer-substring (point-at-bol) (point-at-eol))
+ " .zzz"))))
+
+(ert-deftest js-mode-indent-bug-20896-chain-nested ()
+ (with-temp-buffer
+ (js-mode)
+ (setq-local js-chain-indent t)
+ (setq-local indent-tabs-mode nil)
+ ;; Must line up to the first "." at the same level.
+ (insert "let x = svg.selectAll(d3.svg.something()\n.zzz")
+ (js-indent-line)
+ (should (equal (buffer-substring (point-at-bol) (point-at-eol))
+ " .zzz"))))
+
+(ert-deftest js-mode-indent-bug-20896-no-chain-1 ()
+ (with-temp-buffer
+ (js-mode)
+ ;; Don't set js-chain-indent.
+ (insert "let x = svg.mumble()\n.zzz")
+ (js-indent-line)
+ (should (equal (buffer-substring (point-at-bol) (point-at-eol))
+ " .zzz"))))
+
+(ert-deftest js-mode-indent-bug-20896-no-chain-2 ()
+ (with-temp-buffer
+ (js-mode)
+ (setq-local js-chain-indent t)
+ ;; Nothing to chain to.
+ (insert "let x = svg()\n.zzz")
+ (js-indent-line)
+ (should (equal (buffer-substring (point-at-bol) (point-at-eol))
+ " .zzz"))))
+
+(ert-deftest js-mode-indent-bug-20896-no-chain-2 ()
+ (with-temp-buffer
+ (js-mode)
+ (setq-local js-chain-indent t)
+ ;; Nothing to chain to.
+ (insert "let x = svg().mumble.x() + 73\n.zzz")
+ (js-indent-line)
+ (should (equal (buffer-substring (point-at-bol) (point-at-eol))
+ " .zzz"))))
+
(provide 'js-tests)
;;; js-tests.el ends here
^ permalink raw reply related [flat|nested] 7+ messages in thread
* bug#20896: patch to add chained indentation
2017-01-10 6:29 ` bug#20896: patch to add chained indentation Tom Tromey
@ 2017-01-12 1:57 ` Dmitry Gutov
2017-01-12 4:01 ` Tom Tromey
0 siblings, 1 reply; 7+ messages in thread
From: Dmitry Gutov @ 2017-01-12 1:57 UTC (permalink / raw)
To: Tom Tromey, 20896; +Cc: Daniel Colascione
On 10.01.2017 09:29, Tom Tromey wrote:
> This patch adds chained indentation, as requested in the bug.
Thanks.
> It comes
> with some tests
I'd just like to point out that it's much better to write indentation
tests in the format used by test/manual/indent/js*.
> (added to a file that first appears in patch in another
> bug
Not sure which patch you mean. This file seems new.
As for review: js--skip-term-backward seems to be doing something
similar to the loop in js--multi-line-declaration-indentation.
Maybe a extraction and unification is in order.
^ permalink raw reply [flat|nested] 7+ messages in thread
* bug#20896: patch to add chained indentation
2017-01-12 1:57 ` Dmitry Gutov
@ 2017-01-12 4:01 ` Tom Tromey
2017-01-13 1:09 ` Dmitry Gutov
0 siblings, 1 reply; 7+ messages in thread
From: Tom Tromey @ 2017-01-12 4:01 UTC (permalink / raw)
To: Dmitry Gutov; +Cc: 20896, Tom Tromey, Daniel Colascione
>> It comes with some tests
Dmitry> I'd just like to point out that it's much better to write indentation
Dmitry> tests in the format used by test/manual/indent/js*.
Thanks, I wasn't aware of this. I'll redo the test this way.
>> (added to a file that first appears in patch in another
>> bug
Dmitry> Not sure which patch you mean. This file seems new.
I added js-tests.el in the bug#19399/bug#22431 patch, then further
amended it in bug#15582. None of these have landed yet. (There's also
bug#25389, which is related, but doesn't touch the test file.)
Dmitry> As for review: js--skip-term-backward seems to be doing something
Dmitry> similar to the loop in js--multi-line-declaration-indentation.
Dmitry> Maybe a extraction and unification is in order.
I don't really see it. Could you explain more?
Tom
^ permalink raw reply [flat|nested] 7+ messages in thread
* bug#20896: patch to add chained indentation
2017-01-12 4:01 ` Tom Tromey
@ 2017-01-13 1:09 ` Dmitry Gutov
0 siblings, 0 replies; 7+ messages in thread
From: Dmitry Gutov @ 2017-01-13 1:09 UTC (permalink / raw)
To: Tom Tromey; +Cc: 20896, Daniel Colascione
On 12.01.2017 07:01, Tom Tromey wrote:
> I'll redo the test this way.
Thanks.
> Dmitry> As for review: js--skip-term-backward seems to be doing something
> Dmitry> similar to the loop in js--multi-line-declaration-indentation.
> Dmitry> Maybe a extraction and unification is in order.
>
> I don't really see it. Could you explain more?
The `while' loop jumps to the beginning of the current "assignment
expression".
`js--skip-terms-backward' is similar because it skips to the beginning
of the call chain. It's more narrow, though (the other function also
jumps over binary operators).
Anyway, I'm not so sure there's much value in unifying the
implementations anymore.
^ permalink raw reply [flat|nested] 7+ messages in thread
* bug#20896: done
2015-06-25 15:37 bug#20896: 25.0.50; [js-mode][FR] support chain syntax indentation Rasmus
2015-06-26 0:14 ` Rasmus
2017-01-10 6:29 ` bug#20896: patch to add chained indentation Tom Tromey
@ 2017-01-14 17:45 ` Tom Tromey
2 siblings, 0 replies; 7+ messages in thread
From: Tom Tromey @ 2017-01-14 17:45 UTC (permalink / raw)
To: 20896-done
This was fixed by 502390822f9c0068898ae41285b37568bf0e4d1c.
Tom
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2017-01-14 17:45 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-06-25 15:37 bug#20896: 25.0.50; [js-mode][FR] support chain syntax indentation Rasmus
2015-06-26 0:14 ` Rasmus
2017-01-10 6:29 ` bug#20896: patch to add chained indentation Tom Tromey
2017-01-12 1:57 ` Dmitry Gutov
2017-01-12 4:01 ` Tom Tromey
2017-01-13 1:09 ` Dmitry Gutov
2017-01-14 17:45 ` bug#20896: done Tom Tromey
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.