-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Indentation Fixes #75
Conversation
Just wanted to say that this PR works wonderful 👍 |
This beast ready to be merged now that #72 is? |
Yup -- was planning to rebase later today to give it a final look and merge |
There's some problems with this, will deal with it later tonight |
Ok, thanks! Let me know when it's ready. I have a bit more time now for open source :) |
@felipeochoa I've backed out the docs you've put in this branch, they still exist on your fork in a branch, you can reapply them after this PR is merged. This PR should be good to go. |
Ok, I think I understand how this is working, and I like it! I have a couple of nits, and a couple of substantive questions. Happy to handle the nits myself if you're busy, and also happy to leave the substantive Qs as bugs/todo, but want to understand nonetheless |
One other high-level question: does this code handle the case of a top-level tag with its Thanks again for pulling this together!! |
Sounds good, but have you reviewed the PR but forgot to submit the review again?
No. Top-level JSX is a noop, there's no point dealing with this edge case. The same approach is used for commenting as well. |
|
||
(defvar-local rjsx--indent-line-columns nil | ||
"A list of indent columns on a per-line basis. The car is the | ||
indent column of the last line, cadr the indent column of the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] Docstring spacing is off here and a couple of other places
limitation of `sgml-indent-line' not being able to indent with | ||
tabs. | ||
|
||
Fixes: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hopefully these will be fixed upstream at some point (!). Maybe better to leave this as a comment than in the docstring?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nah. The only way to fix this upstream satisfactorily is to merge js2-mode and rjsx-mode. Text-based heuristics is a thin PVC pipe under 10 tons of pressure, it doesn't matter how to you plug it, it'll leak.
(let* ((sgml-basic-offset js-indent-level) ;; `sgml-indent-line' can only indent by spaces | ||
(cur-pos (save-excursion (back-to-indentation) (point))) | ||
(cur-char (char-after cur-pos)) | ||
(node (js2-node-at-point (- cur-pos rjsx--indent-running-offset)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to understand this rjsx--indent-running-offset
bit. Is the idea to simply convert between "current" buffer coordinates and "as of last parse" buffer coordinate? If so, a defsubst
for this would be great. There's a comment further down where I think we need this but don't have it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's an optimization to prevent having to reparse to get the node of the beginning of the line after indenting a line.
After indenting a line, the "offset" is the difference of the position of the beginning of the line between "before" and "after" indentation. If you are indenting a region, the offsets accumulate in a list of +4 -5 +2..... etc on a line by line basis. Adding them all together and subtracting the current position will get you back the position of the node you need to process, without reparsing the whole file.
rjsx-mode.el
Outdated
(cond | ||
;; Top-level tag | ||
((not (rjsx-node-p (js2-node-parent node))) | ||
(cl-letf (((symbol-function #'js--continued-expression-p) 'ignore)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] I get why you're doing this, but cl-letf
ing a private function is usually worth a quick explanatory comment. E.g.,
;; Prevent `js-indent-line' from treating the leading `<' as a continued expression
rjsx-mode.el
Outdated
(rjsx-indent-with-spaces cur-pos (js-indent-line)))) | ||
;; Align the /> of a multi-line self-closing tag | ||
((and (not (rjsx-node-closing-tag node)) | ||
(save-excursion (goto-char cur-pos) (looking-at "/[[:space:]]*>"))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] Use `looking-at-p' here.
((and (rjsx-node-p (js2-node-parent node)) | ||
(char-equal ?> cur-char)) | ||
(rjsx-indent-with-spaces cur-pos (js-indent-line))) | ||
;; Get around `js-indent-line' bug with not aligning JSXElement sibling |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] Is there a bug number to go with this workaround? One of the ones above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This just explains the root cause for one of those in the docstring, I don't remember which one tho.
;; Get around `js-indent-line' bug with not aligning JSXElement sibling | ||
;; after a JSX expression. | ||
((rjsx-wrapped-expr-p | ||
(let* ((parent (js2-node-parent node)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] I suspect this could be simplified to avoid looping twice, but for now can you just factor it out into a helper function? It's a bit dense, and I think putting a name + docstring would make it much easier to understand what's going on. (I think it's just looking for the preceding non-blank child?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect this could be simplified to avoid looping twice
O(2 * 1) = O(1 * 2), meh
I think it's just looking for the preceding non-blank child?
That's right. I'd prefer not to make a function that's just used once. I'll put a comment here.
rjsx-mode.el
Outdated
;; after a JSX expression. | ||
((rjsx-wrapped-expr-p | ||
(let* ((parent (js2-node-parent node)) | ||
(children (cl-loop for kid in (cl-struct-slot-value 'rjsx-node 'kids parent) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] isn't there an accessor we could use here?
rjsx-mode.el
Outdated
(rjsx-indent-with-spaces cur-pos (js--as-sgml (sgml-indent-line)))) | ||
;; Inside JSX expression or looking at the end of it | ||
((rjsx-ancestor node #'rjsx-wrapped-expr-p) | ||
(if (cl-loop for c being the elements of "[])},;" thereis (char-equal c cur-char)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] (memq cur-char '(?\[ ?\] ?\) ?\} ?, ?\;))
is easier to read (for me) and much faster
rjsx-mode.el
Outdated
(progn | ||
(setq rjsx--indent-region-p t) | ||
(js2-indent-region start end)) | ||
(setq rjsx--indent-running-offset 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] Are these used anywhere else? If not, why not just let-bind them around the js2-indent-region' call and get rid of the
unwind-protect' form?
Oops. Submitted now. Makes sense re: top-level. I think I actually understand this one 😄 |
I've left the docstring alone but cleaned up the rest. Thanks for reviewing! |
@wyuenho Thanks again for all your work on |
# Merge after #72## DiffFixes:
Similar to
js-jsx-indent-line
, but fixes indentation bug with JSXElement after a JSX expression and arrow function. In addition, the > of a multi-line open tag and the /> of a multi-line self-closing tag are aligned to the beginning <. This function also ensures everything inside a JSX context is indented according tojs-indent-level
using spaces, this is due to the limitation ofsgml-indent-line
not being able to indent with tabs.As an added bonus, this also fixes the
rjsx-indentation-1
test for Emacs < 26.