oakmac / sublime-text-parinfer

Parinfer plugin for Sublime Text
ISC License
57 stars 8 forks source link

"Parent expression" hack #23

Open oakmac opened 8 years ago

oakmac commented 8 years ago

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.

shaunlebron commented 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.

oakmac commented 8 years ago

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.

shaunlebron commented 8 years ago

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

kyleerhabor commented 2 years ago

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)
oakmac commented 2 years ago

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.