You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently properties are always inserted after the last property (or after the header, if no properties are present).
I'm using this library to migrate configuration files that are primarily human-edited.
It makes sense to group related properties nearby each other, so I arrived at this abstraction:
There is an interface whose implementations control where a property is inserted.
It'd be possible to add an overload to Properties#put and Properties#putCommented which accept an instance of InsertWhere.
This way users could optionally control where properties are inserted.
Discussion
Do you think this feature is suitable for this library?
Or is the Cursor API simple enough that end-users are expected to write these for themselves as needed?
changed the title [-][Feature Discussion] Presets for controlling where properties are inserted[/-][+]Control where properties are inserted[/+]on Sep 23, 2026
The idea is definitely interesting, I have to think a bit about the suggested API. At first glance it doesn't really seem to "fit" with the rest of the API. But the idea of creating several ways to put the cursor where you want it to then use that to insert your new property seems a good one.
I think that instead of creating a new interface and an entirely new API for this I'd rather go with some helper functions using the Cursor mechanism. For example:
Cursor Properties.first() - already exists
Cursor Properties.last() - also already exists
Cursor Properties.before(String key)
Cursor Properties.after(String key)
Having two extra insertion points where you'd normally insert the first property (after any header comments) or right after the last property are also interesting, just not sure about the names, something like this I guess:
Cursor Properties.beforeFirstProperty() - should handle when no properties exist yet
Cursor Properties.afterLastProperty() - should call beforeFirstProperty() when no properties exist yet
Once you get the cursor it's easy enough to insert something at that point using Cursor.add().
Btw, the code to implement beforeFirstProperty() and afterLastProperty() really already exist, because it's what the internal method Properties.addNewKeyValue() uses to determine where to insert new properties. Its code could be refactored to create both beforeFirstProperty() and afterLastProperty() instead. And then it simply calls afterLastProperty() and things should be good.
Just realized we probably need something else as well, because finding the right spot to insert a new property is the first step. But step 2 is making sure we can actually insert something there (imagine that after("foo") leaves us at the end, then we have to insert an EOL token before we can insert anything else.), perhaps something like:
prepareAdd(Cursor c) - prepares the Properties object to accept a new item being added to the current location
I think it would make sense to create Properties#addProperty(Cursor cursor, String key, String value).
This method would be responsible for creating tokens in the correct order, converting to raw strings, and adding EOLs as needed.
That would also lighten the cognitive load for end-users.
(edit: this method should also navigate / throw an exception if the cursor points at a separator or value token, as an insertion here would be destructive)
As a short explanation, you just use one of the methods for getting positions (first(), last(), beforeProperty(), afterProperty(), beforeFirstProperty(), afterLastProperty(), home()) together with put(pos, key, value) and things should just work. (Eg. put(afterProperty("foo"), "bar", "baz");)
last().next() is a bit clunky for inserting a new last line
indeed, I did actually think of adding things like start() (ie first().prev()) and end() (ie last().next()) but I felt that would actually be more confusing.
Activity
[-][Feature Discussion] Presets for controlling where properties are inserted[/-][+]Control where properties are inserted[/+]quintesse commentedon Sep 23, 2026
The idea is definitely interesting, I have to think a bit about the suggested API. At first glance it doesn't really seem to "fit" with the rest of the API. But the idea of creating several ways to put the cursor where you want it to then use that to insert your new property seems a good one.
quintesse commentedon Sep 24, 2026
I think that instead of creating a new interface and an entirely new API for this I'd rather go with some helper functions using the
Cursormechanism. For example:Cursor Properties.first()- already existsCursor Properties.last()- also already existsCursor Properties.before(String key)Cursor Properties.after(String key)Having two extra insertion points where you'd normally insert the first property (after any header comments) or right after the last property are also interesting, just not sure about the names, something like this I guess:
Cursor Properties.beforeFirstProperty()- should handle when no properties exist yetCursor Properties.afterLastProperty()- should callbeforeFirstProperty()when no properties exist yetOnce you get the cursor it's easy enough to insert something at that point using
Cursor.add().quintesse commentedon Sep 24, 2026
Btw, the code to implement
beforeFirstProperty()andafterLastProperty()really already exist, because it's what the internal methodProperties.addNewKeyValue()uses to determine where to insert new properties. Its code could be refactored to create bothbeforeFirstProperty()andafterLastProperty()instead. And then it simply callsafterLastProperty()and things should be good.quintesse commentedon Sep 24, 2026
Just realized we probably need something else as well, because finding the right spot to insert a new property is the first step. But step 2 is making sure we can actually insert something there (imagine that
after("foo")leaves us at the end, then we have to insert an EOL token before we can insert anything else.), perhaps something like:prepareAdd(Cursor c)- prepares thePropertiesobject to accept a new item being added to the current locationnx-eric-jarosch commentedon Sep 24, 2026
I think it would make sense to create
Properties#addProperty(Cursor cursor, String key, String value).This method would be responsible for creating tokens in the correct order, converting to raw strings, and adding EOLs as needed.
That would also lighten the cognitive load for end-users.
(edit: this method should also navigate / throw an exception if the cursor points at a separator or value token, as an insertion here would be destructive)
quintesse commentedon Sep 24, 2026
Yes, I was trying out this idea of
prepareAdd()and I didn't like it very much. So I agree, I think asetProperty()is probably the best idea.feat: added new methods for inserting properties at specific positions
feat: added new methods for inserting properties at specific positions
quintesse commentedon Sep 30, 2026
@nx-eric-jarosch I just merged an implementation for this and I wanted to know if this works for your use-case before creating a new release.
Again thanks for all your help and suggestions!
Let me know what you think.
quintesse commentedon Sep 30, 2026
As a short explanation, you just use one of the methods for getting positions (
first(),last(),beforeProperty(),afterProperty(),beforeFirstProperty(),afterLastProperty(),home()) together withput(pos, key, value)and things should just work. (Eg.put(afterProperty("foo"), "bar", "baz");)nx-eric-jarosch commentedon Oct 1, 2026
@quintesse I've had a look and found these 4 issues. (linked above)
last().next()is a bit clunky for inserting a new last line, but it does make sense based on how inserting works.. so shrug.Other than that, your change does suit my use-case. Thanks!
Note that my test-cases assume this convenience method.
quintesse commentedon Oct 1, 2026
indeed, I did actually think of adding things like
start()(iefirst().prev()) andend()(ielast().next()) but I felt that would actually be more confusing.quintesse commentedon Oct 1, 2026
@nx-eric-jarosch all your issues have been fixed, could you perhaps find some more? I mean, could you check if everything works now? 🙂
nx-eric-jarosch commentedon Oct 2, 2026
@quintesse I've had a look, but found no bugs :)
I did find some "technically correct" behaviour:
this behaviour matches the documentation:
But it's not what I'd intuitively expect:
# header\n\nput=val\nEither way, I'm approaching nitpicking territory.
I'm ready to call this solved.
quintesse commentedon Oct 2, 2026
You're right! I think the second part of this sentence was never actually implemented:
So, I'm still going to fix that before releasing. Thanks @nx-eric-jarosch !