Skip to content
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

Add support for @upper_case @lower_case captures #838

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

ctdunc
Copy link

@ctdunc ctdunc commented Jan 17, 2025

Add support for @upper_case @lower_case captures.

Issue: #836

Description

This adds really basic support for the feature discussed in the linked issue.
I tested it with my SQL capture, and it works, but I don't know if adding SQL as a language is in scope for this PR and there are a lot of other issues with my query (it's still kinda ugly).

Checklist

Checklist before merging:

  • CHANGELOG.md updated
  • README.md up-to-date

@ctdunc ctdunc force-pushed the feature/capitalization branch from bbbf44b to 5da7294 Compare January 17, 2025 21:15
topiary-core/src/atom_collection.rs Outdated Show resolved Hide resolved
topiary-core/src/atom_collection.rs Outdated Show resolved Hide resolved
Copy link
Member

@Xophmeister Xophmeister left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution 🙏

My immediate concern with this is that it does not respect leaf nodes (i.e., those annotated with @leaf, which are meant to remain unchanged by formatting). For example:

; test.scm
(string) @leaf

(command
  argument: (_) @prepend_space
)

(command) @upper_case
$ topiary format -lbash -qtest.scm <<'SH'
> echo "hello"
> SH
ECHO "HELLO"

Topiary is meant to be general: adding @{upper,lower}_case already feels a bit overly specific,1 but regardless, they should follow the other assumptions. As such, if you could modify your code to respect @leaf nodes, then I think it would meet that bar.

Footnotes

  1. It occurs to me that one could implement case changes with a mixture of @delete and @append_delimiter. Granted, it's not as clean as your solution, but it's doable. Something like this might work:

    (select_keyword
      _ @delete @append_delimiter
    
      (#not-eq? @delete "SELECT")
      (#delimiter! "SELECT")
    )
    

    Untested, but we use similar tricks in queries for other languages.

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
topiary-config/Cargo.toml Outdated Show resolved Hide resolved
topiary-core/src/atom_collection.rs Outdated Show resolved Hide resolved
topiary-core/src/atom_collection.rs Outdated Show resolved Hide resolved
topiary-core/src/lib.rs Outdated Show resolved Hide resolved
topiary-core/src/atom_collection.rs Show resolved Hide resolved
topiary-core/src/atom_collection.rs Outdated Show resolved Hide resolved
@ctdunc
Copy link
Author

ctdunc commented Jan 20, 2025

Thanks for your contribution 🙏

My immediate concern with this is that it does not respect leaf nodes (i.e., those annotated with @leaf, which are meant to remain unchanged by formatting). For example:

; test.scm
(string) @leaf

(command
  argument: (_) @prepend_space
)

(command) @upper_case
$ topiary format -lbash -qtest.scm <<'SH'
> echo "hello"
> SH
ECHO "HELLO"

Topiary is meant to be general: adding @{upper,lower}_case already feels a bit overly specific,1 but regardless, they should follow the other assumptions. As such, if you could modify your code to respect @leaf nodes, then I think it would meet that bar.

Footnotes

1. It occurs to me that one could implement case changes with a mixture of `@delete` and `@append_delimiter`. Granted, it's not as clean as your solution, but it's doable. Something like this _might_ work:
   ```
   (select_keyword
     _ @delete @append_delimiter
   
     (#not-eq? @delete "SELECT")
     (#delimiter! "SELECT")
   )
   ```
   
   
   Untested, but we use similar tricks in queries for other languages. [↩](#user-content-fnref-rewrite-5338fc0ec3c8f848b186ccebc7cb7573)

Will add respect for leaf nodes. I based my implementation off of @delete, which also does not respect @leaf. If there were one capture I'd expect to have higher precedence than @leaf, @delete would probably be it, but wanted to confirm that this is intended behavior.

; test.scm
(string) @leaf

(command
  argument: (_) @prepend_space
)

(command) @delete

Also, cannot find docs for @leaf in the README, which may be worth adding.

As for using delete and delimiter, I thought about this, but (A) there are over 300 keywords in the SQL grammar I am using, and (B) I would like to be able to apply this to column aliases/identifiers as well, for which the node content is not necessarily known.

@Xophmeister
Copy link
Member

Will add respect for leaf nodes. I based my implementation off of @delete, which also does not respect @leaf. If there were one capture I'd expect to have higher precedence than @leaf, @delete would probably be it, but wanted to confirm that this is intended behavior.

; test.scm
(string) @leaf

(command
  argument: (_) @prepend_space
)

(command) @delete

Touché 😉 Yes, @delete will delete nodes that are marked as leaves, so it does indeed have higher precedence than @leaf. It wouldn't make much sense to delete nodes and somehow leave any leaf-children in the source. I suppose what I was getting at is that @{upper,lower}_case affecting the contents of a string is rather surprising behaviour, which @leaf is designed to address.

Also, cannot find docs for @leaf in the README, which may be worth adding.

Excellent point 👍 I'll add an issue.

As for using delete and delimiter, I thought about this, but (A) there are over 300 keywords in the SQL grammar I am using, and (B) I would like to be able to apply this to column aliases/identifiers as well, for which the node content is not necessarily known.

That's fair; this method is a bit unwieldy. There was talk of a more generic rewriting capture some time ago, but even that wouldn't solve your problem as effectively as your @{upper,lower}_case solution.

@Xophmeister Xophmeister mentioned this pull request Jan 20, 2025
@ctdunc
Copy link
Author

ctdunc commented Jan 21, 2025

I think this is ready for review again. Given the previous query you gave, the output is now:

ECHO "hello"

@ctdunc ctdunc requested a review from Xophmeister January 21, 2025 13:26
Copy link
Member

@Xophmeister Xophmeister left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great 🙏 Thanks, @ctdunc

I've approved this, but it's not ready to merge just yet. Nearly, but I have a few small requests!

  1. There is a TODO floating around in atom_collection.rs that either needs to be resolved or removed. (Either way 👌)
  2. A simple test for @{upper,lower}_case would be helpful, although I'm not sure where you'd put it (there aren't explicit tests for other capture names). As such, don't sweat on this if it doesn't make sense.
  3. Please update the CHANGELOG and credit yourself 💯

Not for this PR, but per this discussion, I think your idea of adding other case modifiers (kebab, snake, etc.) is interesting and, with this contribution, will make it easy to pursue in the future. So, thank you 🙇

Edit: I'll run the CI as well, just to check everything passes...

topiary-core/src/atom_collection.rs Outdated Show resolved Hide resolved
@ctdunc
Copy link
Author

ctdunc commented Jan 21, 2025

This is great 🙏 Thanks, @ctdunc

I've approved this, but it's not ready to merge just yet. Nearly, but I have a few small requests!

1. There is a `TODO` floating around in `atom_collection.rs` that either needs to be resolved or removed. (Either way 👌)

2. A simple test for `@{upper,lower}_case` would be helpful, although I'm not sure where you'd put it (there aren't explicit tests for other capture names). As such, don't sweat on this if it doesn't make sense.

3. Please update the `CHANGELOG` and credit yourself 💯

Not for this PR, but per this discussion, I think your idea of adding other case modifiers (kebab, snake, etc.) is interesting and, with this contribution, will make it easy to pursue in the future. So, thank you 🙇

Edit: I'll run the CI as well, just to check everything passes...

I have tests for @{upper,lower}_case on my feature/sql branch, where this test will actually make sense. Not sure what other language I'd want to put it in, but I can cook one up for sure.

Copy link
Member

@Xophmeister Xophmeister left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made a few more suggestions to simplify the code 👍

I have tests for @{upper,lower}_case on my feature/sql branch, where this test will actually make sense. Not sure what other language I'd want to put it in, but I can cook one up for sure.

That's fine then; no need to bother in this PR. I was thinking about having explicit tests in the code, rather than using the IO tester. Best to hold your IO tester tests back until they make sense, rather than trying to shoehorn them into an unexpecting language!

topiary-core/src/atom_collection.rs Outdated Show resolved Hide resolved
topiary-core/src/atom_collection.rs Outdated Show resolved Hide resolved
CHANGELOG.md Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants