Closed ALSchwalm closed 4 years ago
You could implement something like following:
user:cd-pre-dir = ~
fn cd {
a = $args
if (and (eq (count $args) 1) (eq $0 -)) {
a = [$user:cd-pre-dir]
}
user:cd-pre-dir = $pwd
builtin:cd $@a
}
That's pretty much my current approach. I'm not aware of a way to hook in to the storage and make things persistent and cross session though, but that's probably an uncommon use-case.
Would be nice to also have a directory stack, with pushd
/popd
. (I'm very surprised there are zero mentions of pushd
in this repo, including issues.)
The directory stack should not be cross session or persistent!! Just like OLDPWD
.
However it should work with implicit cd ("invoking a directory"). And that always invokes the built-in cd
, not a custom fn cd
…
It seems that cd -
is useful in scripts. I would prefer this to be built as an editor feature instead of a feature of cd
.
Oops, typo: s/is useful/is rarely useful/
It would be really weird if cd -
worked in interactive mode but not in scripts… I expect all built-in commands to work exactly the same in both
As anecdotal evience, I've used cd -
in the past in (fish) scripts in this manner:
for i in (find . -type d)
cd $i
# do something
cd -
end
@xofyarg Thanks for the example, but it doesn't track directory changes done via the location mode, or direct assignment to $pwd
. See below for my idea of introducing APIs for this.
@myfreeweb sorry for not being clear. My current stance is to not support cd -
at all, whether in interactive mode or in scripts. But rather, build an interactive feature and an underlying API. I am generally against the use of magical values that are only recognized by a certain command, but this only applies to the Elvish core; you are always welcome to build customizations however you like.
Fish has a per-session directory history that you can navigation using Alt-Left, Alt-Right, that is something I think we can copy. It is comparable to pushd
/popd
, but doesn't require manual pushing/popping. We should also add a low-level API for more flexibility (which, among other things, should enable you to implement cd -
if you like), and we have several choices here. We can implement the per-session directory history as a builtin functionality, and expose this as a variable, say $edit:dir-history
(how to choose a name that disambiguates itself from the global directory history would be an interesting question). Then cd -
can be implemented as easily as
fn cd- { cd $edit:dir-history[-1] }
We can also add a hook for directory change (see https://elvish.io/ref/edit.html#hooks for how the current hooks work), say $after-cd
. Then we can implement the per-session directory history in elv script, rather as a builtin functionality.
@occivink You use case is better covered by:
pwd=$i {
# do something
}
Using cd -
can do the same thing in simpler case, but has two drawbacks: you need to remember to put cd -
in the correct place (which might not be trivial if your script grows), and it cannot be nested -- what if you need to change directory in that # do something
? This doesn't work:
cd $i
# ...
cd $j
# ...
cd - # undoes cd $j
cd - # doesn't undo cd $i!
But temporary assignment to pwd
can be nested:
pwd=$i {
# ...
pwd=$j {
# ...
}
}
In general, this pattern of do-something-and-undo-later is almost always better implemented with some kind of scoping construct; compare RAII in C++, and with
in Python.
it doesn't track directory changes done via the location mode
My bad, I actually use narrow mode, which calls a closure that does the magic.
... or direct assignment to $pwd
I was surprised to know $pwd
is not readonly.
The hooks based implementation sounds like a more general solution to me. It could be leveraged to build session based dir-history.
Fish has a per-session directory history that you can navigation using Alt-Left, Alt-Right, that is something I think we can copy.
ooh not bad
It is comparable to pushd/popd, but doesn't require manual pushing/popping.
zsh has automatic pushd!
We can also add a hook for directory change
That would allow auto pushd to be implemented, yes :)
Hi all,
@xiaq Let's say cd -
isn't implemented as a core function as you say but rather left to the user to implement fn cd- { cd $edit:dir-history[-1] }
; my question is: what would be the similar way to quickly access the previous working directory in elvish?
When you're rushing throwing commands into a terminal cd -
makes a whole lot of a difference.
I agree, cd -
is the one thing I'm missing the most from my pre-elvish time.
In case anyone is interested, I've implemented a directory stack using prompt hooks. It's not perfect but it works reasonably well: https://github.com/zzamboni/elvish-modules/blob/master/dir.org
And how I use it: https://github.com/zzamboni/dot_elvish/blob/master/rc.org#directory-and-command-navigation-and-history
In addition to the directory history, its dir:cd
function (which I alias to cd
) also supports -
as an argument to change to the previous directory.
@xiaq
We can also add a hook for directory change (see https://elvish.io/ref/edit.html#hooks for how the current hooks work), say $after-cd. Then we can implement the per-session directory history in elv script, rather as a builtin functionality.
Autojump implements its functionality in fish via hooks, specifically by hooking into $PWD
changes. Perhaps variable hooks is a more flexible/generic solution.
I suggest using a separate command instead of an argument of the builtin: cd-
instead of cd -
. It requires less typing, and don't cause a trouble if the directory is named -
.
I suggest using a separate command instead of an argument of the builtin: cd- instead of cd -. It requires less typing, and don't cause a trouble if the directory is named -.
That is true for any of the other magical path expansion chars such as ~
, *
, etc. In my four decades of using UNIX operating systems I have never seen a directory named -
outside of deliberate attempts to create a security hole. If someone really does need to be able to chdir to such a directory name they can do cd ./-
.
I agree with @xiaq that having the builtin cd
support cd -
is a bad idea. Notwithstanding my previous comment. This is a good example of a POSIX 1003.2 shell feature that should not be adopted by Elvish. And the zsh cd -$n
form is especially bad. Whether cd -
should be supported interactively as a convenience is a slightly different question. I've used cd -
interactively for several decades. Nonetheless, I now think that other solutions are preferable and it definitely should not be supported by the builtin cd
command.
My current preference is:
fn cd [d]{
if (eq $d -) {
builtin:cd $edit:session-dir-history[-1]
} else {
builtin:cd $d
}
}
Per-session directory history is now tracked in #1043, closing this.
Sorry to write to a closed issue, but can we have an up-to-date snippet?
Absolute beginner here, heard of elvish 30min ago, got it on my nix shell and am trying to do something quick with it. Was hit with this error in @xiaq's script:
compilation error: variable $edit:session-dir-history not found
Elvish 0.15
I also tried the first snippet in the thread and it also failed.
(I could have commented on the other issue but it seemed more general than "how can I cd -
in elvish?")
EDIT: Oops, realized xiaq's script was meant as future syntax.
Here's the error on the first script in thread:
compilation error: cannot create variable $user:cd-pre-dir; new variables can only be created in the local scope
I'm guessing that snippet is outdated?
EDIT2: I also tried https://github.com/zzamboni/elvish-modules/blob/master/dir.org
Used it like:
#! /usr/bin/env nix-shell
#! nix-shell -i elvish -p elvish
use epm
epm:install github.com/zzamboni/elvish-modules
use github.com/zzamboni/elvish-modules/dir
use github.com/zzamboni/elvish-modules/alias
alias:new cd "use github.com/zzamboni/elvish-modules/dir; dir:cd"
cd bastion
cd -
Got this error:
Exception: compilation error: variable $edit:current-command not found
/Users/juliano/.elvish/lib/github.com/zzamboni/elvish-modules/dir.elv, line 89: if (> (count $edit:current-command) 0) {
/Users/juliano/git/NoRedInk/tf-all.elv, line 7: use github.com/zzamboni/elvish-modules/dir
@omnibs, Elvish has been evolving rapidly over the past two years. The 0.15.0 release is considered old. In general @zzamboni's modules are only guaranteed to work with Elvish built from a recent commit. Try one of the "HEAD" binaries at https://elv.sh/get/.
P.S., There isn't much need for the alias module anymore since the introduction of the edit:add-var
command. What I do is put the following (along with a bunch of other things) in ~/.elvish/lib/interactive.elv:
fn cd [@_args]{
use github.com/zzamboni/elvish-modules/dir
dir:cd $@_args
}
Then in ~/.elvish/rc.elv I do this:
use interactive
edit:add-var cd~ $interactive:cd~
Oh, I see. I got it from nixpkgs where even in unstable
we have 0.15.0.
Thanks for clarifying!
In bash,
cd -
expands tocd $OLDPWD
, where$OLDPWD
holds the previous working directory. It would be nice to have this in elvish.zsh
extends on this by providingcd -N
(whereN
is in integer) to access arbitrary 'directory history' items, which may also be worth adding.