Open oakmac opened 8 years ago
If the cursor is at line n
, we cannot reliably identify the starting line of its highest-level parent expression without parsing all lines 0
to n
. proof is straightforward. Furthermore, a line starting with a (
is neither necessary nor sufficient for determining the start of a list expression because:
only thing I can think of at the moment is to isolate and apply parinfer's lisp reader in a minimal way just for finding this line number. regardless of how the API exposes this, I think this is the only way to reliably get this data.
For clarity:
The purpose of the "parent expression" hack is not to detect the start of top-level expressions with perfect accuracy. As you noted, that would obviously require parsing the file - which is exactly the expensive computational cost we are trying to avoid for performance reasons while editing.
The purpose is to quickly detect something that looks like a parent expression. Without fully parsing, this will always be a guess and always have edge cases that are not covered (like the two cases you mention above).
The purpose of this issue is to track cases where this breaks under normal development circumstances. Presumably, users of Parinfer buy into the idea that there is a relationship between Lisp code structure and indentation. In Lisp dialects that adhere to this idea, I am not aware of one that doesn't start parent expressions at the beginning of a line as a strong convention. I suspect someone who didn't want to follow that convention in their code would likely not choose Parinfer as an editing mode in the first place.
a surprising result, but the reader can now identify all top-level open-parens of a 2800 line file in ~7ms. So I plan to offload the responsibility of fast change processing to a new pure change function, tracked here: https://github.com/shaunlebron/parinfer/issues/75
Although this is an old issue, is this why expressions like this have weird behavior?
;; Take this code.
(ds.cdn/resize (ds.cdn/effective-user-avatar user) size)
;; If you delete the opening `(` at `ds.cdn/effective-user-avatar`, you're left with:
(ds.cdn/resize ds.cdn/effective-user-avatar user) size
;; But if you had the code separated line-for-line like this:
(ds.cdn/resize
(ds.cdn/effective-user-avatar user)
size)
;; And tried deleting again, you'd be left with this
;; (which is correct, according to http://shaunlebron.github.io/parinfer/#paredit-emerges).
(ds.cdn/resize
ds.cdn/effective-user-avatar user
size)
is this why expressions like this have weird behavior?
No; this behavior is unrelated to the parent expression hack.
In the case you have described, Parinfer does not have enough information to decide whether to close the paren after user
or size
. The decision to close either way comes with trade-offs explored in this issue and these test cases.
This issue is to track the "parent expression" hack that is described in the README.
Please add to it if you experience a significant problem or have ideas for a better approach.