-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Add support for 'cd +' #7206
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 'cd +' #7206
Conversation
… the stack as well for more intuitive ways of going back
| } | ||
|
|
||
| // Replace path with last working directory from redo stack and push to the undo stack when '+' was passed. | ||
| if (originalPath.Equals("+", StringComparison.OrdinalIgnoreCase)) |
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.
We could use switch with C# 7.0 syntax and exclude pushNextLocation:
switch (originalPath)
{
case var path when path.Equals("-", StringComparison.OrdinalIgnoreCase):
if (_SetLocationHistory.UndoCount <= 0)
{
throw new InvalidOperationException(SessionStateStrings.SetContentToLastLocationWhenHistoryUndoStackIsEmpty);
}
var previousLocation = _SetLocationHistory.Undo(this.CurrentLocation);
path = previousLocation.Path;
break;
case var path when path.Equals("+", StringComparison.OrdinalIgnoreCase);
if (_SetLocationHistory.RedoCount <= 0)
{
throw new InvalidOperationException(SessionStateStrings.SetContentToLastLocationWhenHistoryRedoStackIsEmpty);
}
var previousLocation = _SetLocationHistory.Redo();
_SetLocationHistory.Push(this.CurrentLocation);
path = previousLocation.Path;
break;
default:
var newPushPathInfo = GetNewPushPathInfo();
_SetLocationHistory.Push(newPushPathInfo);
if (_SetLocationHistory.RedoCount >= 0)
{
_SetLocationHistory.InvalidateRedoStack();
}
break;
}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.
Yes, we could. I will take a note of this but would prefer to address style issues like this only at the end once the design/behaviour has been reviewed/approved.
| { | ||
| throw new InvalidOperationException(SessionStateStrings.BoundedStackIsEmpty); | ||
| } | ||
| var item = this.First.Value; |
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.
Please add new line after } (CodeFactor issue).
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 disagree, in order to improve readability I have put the code for cd - and cd +` into 2 blocks that are separated by a newline. This would make it worse, we should not be a slave of all rules, I question the usefulness of this rule. I agree that it can be useful to have a newline after a big block but not after a one-liner and not having braces can be dangerous as well.
I suggest that I could refactor the 2 blocks into a private method of their own instead, what do you think?
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.
@bergmeister I don't understand why you ask about private method. CodeFactor issue is to add new line after 1552 and before 1553.
There are not many such issues in our code reported by CodeFactor. In other words, it is a style that we always follow.
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.
Sorry, I thought your comment was on the other place in the SessionStateLocationAPIs class, my bad.
The idea for the SessionStateLocationAPIs class was to put the 2 code blocks into a private method to avoid making the main method even longer.
Nevertheless, I still find the rule odd for a brace that has only one line in it but I will have to comply with whatever is preferred at the end anyway.
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.
No one happy in this situation (style issues) but at least this tool always gives the same result as opposed to human work.
Now the CodeFactor settings are such that we get a minimum of requests for each PR. I hope in a few months we will be able to escape most annoying style issues.
…not allow negative values
…ogic to the HistoryStack class.
iSazonov
left a comment
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.
Leave a comment
| internal class BoundedStack<T> : LinkedList<T> | ||
| { | ||
| private readonly int _capacity; | ||
| private readonly uint _capacity; |
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 wonder - how do this related to the PR?
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.
As I was writing the XUnit unit tests for the 2 classes, I was thinking about the case of someone passing in a negative number, hence why I made it unsigned to get that for free. We could even make it an ushort but with modern processor architecture and runtimes, there is usually no speed advantage any more.
| } | ||
| } | ||
|
|
||
| internal class HistoryStack<T> |
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.
BoundedStack<T> below has a public doc comment. I expect we add a public comment here too with an explanation why we use it and what is the difference from BoundedStack<T>.
| <value>The dynamic parameters for the GetContentWriter operation cannot be retrieved for the '{0}' provider for path '{1}'. {2}</value> | ||
| </data> | ||
| <data name="SetContentToLastLocationWhenHistoryIsEmpty" xml:space="preserve"> | ||
| <data name="SetContentToLastLocationWhenHistoryUndoStackIsEmpty" xml:space="preserve"> |
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.
Could we use more short name? UndoStackIsEmpty? SetContentUndoStackIsEmpty?
| <data name="SetContentToLastLocationWhenHistoryUndoStackIsEmpty" xml:space="preserve"> | ||
| <value>There is no location history left to navigate backwards.</value> | ||
| </data> | ||
| <data name="SetContentToLastLocationWhenHistoryRedoStackIsEmpty" xml:space="preserve"> |
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.
The same - very long name.
|
This PR has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed if no further activity occurs within 10 days. |
|
Feedback was addressed and the PR got stale again similar to its previous |
|
@bergmeister Sorry, MSFT team is hard working on porting Windows modules. I suppose that most of the open PRs will be reviewed only after 6.1 release (~2-3 weeks). |
|
@bergmeister Please add a commit with |
|
@anmenaga Done and it is still green. |
|
@bergmeister Ran into a need for |
| { | ||
| var newPushPathInfo = GetNewPushPathInfo(); | ||
| _SetLocationHistory.Push(newPushPathInfo); | ||
| case var originalPathSwitch when originalPathSwitch.Equals("-", StringComparison.OrdinalIgnoreCase): |
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 would use the type of originalPathSwitch here instead of var, just so it's clear. Same below.
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.
Ok, addressed (type is string)
| path = _SetLocationHistory.Redo(this.CurrentLocation).Path; | ||
| break; | ||
| default: | ||
| var newPushPathInfo = GetNewPushPathInfo(); |
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.
Since it's not clear on this line what type the method returns, I would prefer not to use var here.
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.
Ok, I renamed it to pushPathInfo instead, which is the name of the type here. which seemed to be the better compromise after looking at it again (otherwise the word pushpathInfo would've been repeated 3 times in one line)
| /// </summary> | ||
| internal class HistoryStack<T> | ||
| { | ||
| private BoundedStack<T> _boundedUndoStack; |
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.
If this are never reassigned they could be made readonly.
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.
Ok, addressed.
|
|
||
| internal T Undo(T currentItem) | ||
| { | ||
| var previousItem = _boundedUndoStack.Pop(); |
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.
T is shorter and more explicit than var here
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.
Ok, addressed.
| } | ||
| } | ||
|
|
||
| internal T Undo(T currentItem) |
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.
Worth documenting the methods here, mainly since Undo and Redo are not entirely self-explanatory
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.
Added comment explaining the level stashing and popping.
rjmholt
left a comment
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.
LGTM!
| var newPushPathInfo = GetNewPushPathInfo(); | ||
| _SetLocationHistory.Push(newPushPathInfo); | ||
| case string originalPathSwitch when originalPathSwitch.Equals("-", StringComparison.OrdinalIgnoreCase): | ||
| if (_SetLocationHistory.UndoCount <= 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.
I wonder that it is nit _setLocationHistory.
| /// Location history for Set-Location that supports Undo/Redo using bounded stacks. | ||
| /// </summary> | ||
| private BoundedStack<PathInfo> _SetLocationHistory; | ||
| private HistoryStack<PathInfo> _SetLocationHistory; |
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.
Please use _setLocationHistory for private.
And seems it is private readonly.
| /// Handles bounded history stacks by pushing the current item to the redoStack and returning the item from the popped undoStack. | ||
| /// </summary> | ||
| /// <param name="currentItem"></param> | ||
| /// <returns></returns> |
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.
Please add a value comment or remove the empty tag.
| /// Handles bounded history stacks by pushing the current item to the undoStack and returning the item from the popped redoStack. | ||
| /// </summary> | ||
| /// <param name="currentItem"></param> | ||
| /// <returns></returns> |
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.
The same.
| } | ||
|
|
||
| It 'Should go to last location back, forth and back again when specifying minus, plus and minus as a path' { | ||
| $initialLocation = Get-Location |
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.
What about $initialPath = (Get-Location).Path ? (See next test.)
… consistency, make member variable readonly, removing redundant comic and minor test syntax improvement
|
@iSazonov @adityapatwardhan please merge this when you get a chance. |
|
@bergmeister Thanks for your contribution! Sorry for delay - I did wait 6.1 GA when MSFT team get a time to review. |
|
@kvprasoon This is a common situation. You should resolve the merge conflict in #7797. |
PR Summary
Closes #7189
cd +adds the ability to revertcd -by having another bounded stack with the same limit for 'redo' actions.Behaviour is similar to back/forward navigation in explorer.exe
When the location is set to a path and the redo stack is non-empty then the redo stack gets flushed.
When
cd +happens, then the redo stack is pushed to as well for a more intuitive way of navigating backwards and forwards.All the work is done of course on the Set-location cmdlet, which is aliased to cd on all platforms.
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:to the beginning of the title and remove the prefix when the PR is ready.cd -here: 'cd -' capability added in PowerShell 6.1 MicrosoftDocs/PowerShell-Docs#2476[feature]if the change is significant or affects feature tests