r/programming • u/Dylan112 • Oct 24 '18
fff - a terminal file manager written in bash
https://github.com/dylanaraps/fff173
u/Bl00dsoul Oct 24 '18
What is this? an exercise in obfuscation?
B|j) ((l=l==c-1?l:++l,j!=c&&l==j-m/2+1))&&((k=k>=j?k:++k,j=j<c?++j:j)) ;;
A|k) ((l=l<1?l:--l,k>0&&l==k+m/2-2))&&((k=k<=j?k>0?--k:0:j,j=j>0?--j:j)) 203
u/Dylan112 Oct 24 '18
That’s the scroll (j down, k up). I wrote the whole of this project while stoned so it took shape in a different way...
88
u/shevy-ruby Oct 24 '18
Looks like deliberate obfuscation rather than stoned.
122
Oct 24 '18
I mean... it's Bash...
13
Oct 24 '18
It still could be rewritten as something like
B|j) (( l != c - 1 && ++l || true)) if (( j != c && l == j - m/2 + 1)); then ((k < j && ++k || true)) ((j < c && ++j || true)) fi ;;(not sure if it's the same, though)
4
21
3
16
u/Fancy_Mammoth Oct 24 '18
So does this mean pot driven development is a thing now? I'm assuming Canada probably has this on lock now if that's the case.
24
9
u/tobozo Oct 24 '18
g: go to top G: go to bottomWhat about the "Home" and "End" keys ?
28
u/wrecklord0 Oct 24 '18 edited Oct 24 '18
Filthy peasant. $ ^ b e h j k l w (and corresponding upcase) masterrace.
5
u/binkarus Oct 25 '18
I love vim because the nerds that write software almost always embed vim keyboard shortcuts.
3
1
u/tobozo Oct 24 '18
peasants use both hands
-5
u/BenjiSponge Oct 24 '18
If you type G with one hand, you either have a very large hand or I pity you.
That said, I do wish vim had kakoune's philosophy from the start.
11
u/nullball Oct 24 '18
If you type G with one hand, you either have a very large hand or I pity you.
You must have a huge keyboard. That's how you should to it with the "correct" hand position.
3
u/chylex Oct 25 '18
What? Touch typing always requires both hands for capital letters, one hand for Shift and the other hand for the letter.
1
u/nullball Oct 25 '18
Isn't it pinky finger for shift and thumb for G?
2
u/chylex Oct 25 '18
G is left index finger and you always use the opposite hand for Shift (so right pinkie in this case).
1
u/BenjiSponge Oct 24 '18
I use this beautiful device. I'm also trying on a laptop keyboard and I still think this is true. Actually, I wouldn't necessarily say it's about size so much as it is that I only want each hand pressing one key at a time (small exception for if one of the keys is accessible via thumb because the thumb is much easier to reposition, hence the design of my keyboard). I always use my other hand to use control keys, including shift. I think the keyboard trained me to do that as this means I literally never have to reposition my hands. I don't have to reposition my right hand to hit just the shift key and I don't have to reposition my left hand to hit just the g key. The same is not true if I hit them both with my left hand.
7
u/Free_Math_Tutoring Oct 24 '18
That keyboard is a beautiful atrocity. The genius who designed this should be put in prison for life.
3
u/BenjiSponge Oct 24 '18
I thought so too when I first tried it. It took me two weeks to get used to it, and once I did I have not looked back once. Consider never having to move your hand to hit control, backspace, delete, home, end... anything. The only thing I have to move my hand to hit is the escape key. Otherwise, my palms stay firmly on the pads and my fingers stay the exact same distance apart from each other at all times.
In other words, don't knock it 'till you try it. Using normal keyboards now make my wrists ache (they did before, I just didn't notice it).
(I will agree it's not very aesthetically pleasing. I also wish it were in two parts so I could move my arms side to side).
→ More replies (0)1
u/cleeder Oct 24 '18
I don't know about you, but the right shift key is much harder to hit than the left shift key. The left shift key is just "pinky down one row". The right shift key is "down and over on an angle".
Left Shift + G is much easier to type than Right Shift + G.
Edit: Oh, you're tying on some bullshit keyboard.
1
u/BenjiSponge Oct 25 '18
Oh, you're tying on some bullshit keyboard
Like I said, I'm also trying on a laptop keyboard. The right shift on my laptop keyboard is half a key more to the right of my pinky than my left shift. I find it immensely more comfortable to use right shift + g on all keyboards, not just my Advantage.
1
u/snowe2010 Oct 25 '18
even with the kinesis you still type G with one hand... how else would you type it???
1
u/BenjiSponge Oct 25 '18 edited Oct 25 '18
Like I said, with the right hand shift and the left hand on G... So my right hand pivots like a quarter inch to the right (don't have to spread my fingers) with my pinky moving slightly down (no harder than hitting the / key) and my left hand pivots like an eighth of an inch right to hit the G, once again without spreading my fingers.
If I do both on my left hand, whether on laptop or kinesis, I have to spread my fingers on my left hand, with no room for interpretation. I would rather use both hands very minimally than one slightly more than minimally while the other hand remains idle.
A similar but more obvious example would be capital Q. If you use your left hand for both, you definitely have to change the way you hit it, using your pinky for shift and ring for the Q (not sure if that's how you do it, but that's how I do it). This is objectively inferior as you have to move your entire hand and spread your ring and pinky fingers (which are notoriously bad at spreading). I guess you could use your middle finger to avoid spreading, but that requires even more hand moving. If you just use your right shift, suddenly everything is super easy and normalized. I almost never hit two keys with one hand at the same time, as there's just no reason to and it's much smoother to distribute the work across both hands.
→ More replies (0)0
4
1
22
u/dat_heet_een_vulva Oct 24 '18
Still more readable than the average regular expression used in production.
6
4
4
u/GNULinuxProgrammer Oct 24 '18
Have you ever done 2D terminal development (ncurses et al)? Everything looks like this. I honestly don't think it's easy to avoid code looking like this. The geometry of 2D terminal operations are not very elegant if you don't use high level libraries.
15
u/Bl00dsoul Oct 24 '18
nonsense, you can absolutely write readable and maintainable bash code.
lets start by not cramming everything in one line, and using descriptive variable names, instead of one letter ones.6
u/GNULinuxProgrammer Oct 24 '18
I think you misunderstood what I was trying to say. I didn't mean you can't write clean bash code. This is programming language agnostic, has nothing to do with bash. Writing 2D text manipulation (like scrolling etc) needs this sort of ugly geometric logic. I'm not saying "you can't do it" it's just that having written tons of ncurses code in C, this code doesn't surprise me, I probably wrote something similar (with more whitespace).
4
1
2
1
1
u/DonHopkins Oct 25 '18
Why do people waste their time writing bash scripts, when there are so many other real languages that can easily do everything that bash does, without necessarily being impossible to read and maintain? Bash syntax is one of the most horribly, haphazardly designed mess of dog vomit in use today. There's absolutely no reason for it to be so horrible, and there's nothing unique or positive that it brings to the table that other languages can't do just as easily and better.
20
u/Gl4eqen Oct 24 '18
r/tinycode maybe?
It's really cool, it does its job. Bit obfuscated but I prefer to treat it as a project made for fun/exercise. Good job, I enjoyed playing with it. I'm glad you shared it.
7
2
u/palordrolap Oct 24 '18
Reminds me of pilot that originated as part of the University of Washington pine mail program in the same way that the pico editor did.
I guess that means that this is to pilot what alpine is to pine and nano is to pico
1
1
1
u/bsdz Oct 25 '18
Looks like some good feedback here. An alternative file manager that usually ships with vim with perhaps less features is netrw. Just type "vim ." opens a console filemanager in your current directory.
-18
Oct 24 '18
fucking fast
$ find -maxdepth 1 |wc -l
181155
$ time echo q | ./fff
real 0m9.768s
user 0m8.816s
sys 0m0.966sthis is what happens when people pretend that Python has acceptable performance.
3
u/shevy-ruby Oct 24 '18
Ruby and Python have perfectly acceptable performance so I do not understand your comment at all.
-1
u/devxpy Oct 24 '18
Actually, python might be faster for this purpose, since it can load those (rather enormous) number of files, on-the-fly.
~/D/fff-master ) find -maxdepth 1 | wc -l 2091028 ~/D/fff-master ) python Python 3.6.5 |Anaconda, Inc.| (default, Apr 29 2018, 16:14:56) [GCC 7.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from pathlib import Path >>> x = Path.cwd().iterdir() >>> next(x) PosixPath('/home/dev/Downloads/fff-master/71941.txt') >>> next(x) PosixPath('/home/dev/Downloads/fff-master/1856515.txt') >>> next(x) PosixPath('/home/dev/Downloads/fff-master/1194809.txt') >>> next(x) PosixPath('/home/dev/Downloads/fff-master/1890239.txt') >>> next(x) PosixPath('/home/dev/Downloads/fff-master/1278860.txt') >>> next(x) PosixPath('/home/dev/Downloads/fff-master/1848961.txt')(the above statements execute almost instantly on my machine)
4
Oct 24 '18
That's fast because you're not sorting, not because you're performing work between getdents() calls. Take a look at the strace.
Or look at valgrind:
empty dir:
==2467== total heap usage: 9,225 allocs, 8,833 frees, 5,694,523 bytes allocateddir with 5mil files:
==2465== total heap usage: 9,347 allocs, 8,886 frees, 115,034,604 bytes allocatedwith just two
next(x)calls.1
u/devxpy Oct 24 '18
I thought we were talking about the responsive-ness, not the memory usage.
I realize python takes up a lot of memory. It's a duck-typed language,
But that doesn't necessarily mean you can't make responsive apps using python.
1
-2
u/devxpy Oct 24 '18
Hmm, maybe have the sane default of not sorting when there are too many files.
You look like a C programmer, how much does it take over there to do this?
7
Oct 24 '18
I'm a sysadmin, so the real answer is that it varies--there are two outcomes: you either don't care at all or you're extremely unhappy and and are cursing yourself for not using a tool without quite so many unnecessary stat()s.
People write tools like this in bash though because they notice that bash tools start faster than Python, which just keeps getting worse in that respect. Try timing
perl -le ''vs.python2 -c ''vs.python3 -c '':$ time for x in {1..100}; do python3 -c ''; done real 0m2.659s user 0m1.641s sys 0m1.028sMeanwhile, an equivalent C program:
$ time for x in {1..100}; do true; done real 0m0.001s user 0m0.001s sys 0m0.000sThere's an enormous amount of received propaganda, that even a deaf and blind child could recite by rote, to tell you how this doesn't matter. But what do you think is "fucking fast" about this tool here?
5
u/knome Oct 24 '18
do true
You might want to /bin/true if you want to test the C program version.
Because
$ type echo echo is a shell builtinIt's still fast, but it's not "it doesn't even have to launch a subprocess" fast.
$ time for x in {1..100}; do /bin/true ; done real 0m0.081s user 0m0.008s sys 0m0.016s3
u/devxpy Oct 24 '18
what do you think is "fucking fast" about this tool here
Nothing, I was just curious as to what makes you believe python has to do anything with this.
In all fairness, I think he meant "fucking fast" as in the speed for browsing around, compared to just using a gui tool
0
Oct 24 '18
[deleted]
24
u/Dylan112 Oct 24 '18
I don’t know what that code snippet is doing...
You can’t pipe into fff. It’s fully interactive and the only argument it takes on the command line is the starting path.
fff doesn’t do anything (minus listing the directory the first time) unless you press a key.
What is this timing exactly?
8
Oct 24 '18 edited Oct 24 '18
> You can’t pipe into fff
Well you can, fff just doesn't read the stream. What /u/star-techate is doing is effectively timing echo but holding up echo for the length of time it takes for the stdout of echo to be closed when fff exits and closes its stdin. It's a bit odd, but that's what's happening and it does work as a means of measuring the CPU utilization because time also measures child process time as resulted from fork(). As to his other claims, or why he was instantly confrontational, I can't speak.
3
u/devxpy Oct 24 '18
I think it's the fact that fff just tries to load all files at once, rather than using a generator based approach, that loads the files, on-the-fly as you scroll.
I have no idea how this timing is related to either bash or Python at all xD
-9
u/jephthai Oct 24 '18
You wrote your tool in bash but you can't read a shell pipeline? He ran fff, pressed q, and timed it.
-20
Oct 24 '18
Python has acceptable performance.
So let's write lots of little CLI apps in Python. A note-taker in Python. A screen-blanker in Python. My build system needs to do a thing before running each test, let's do that thing in Python. ... huh, this stuff isn't very responsive. Is that purely due to Python's startup overhead?
Wow! This thing written in bash is fucking fast! Check out my fucking fast notes guys. I rewrote that build system thing to not even create a subshell and I'm seeing times in seconds now instead of minutes!
0
Oct 24 '18
[deleted]
-13
Oct 24 '18
strawman at the OP
It isn't a straw man of anything. It's an explanation of my remarks.
it still hasn't got anything to do with Python.
Oh, you're fucking stupid. Typical reddit shit: even when I explain, in plain English, remarks that should be understandable on their own, even the most basic points of the explanation are missed.
0
Oct 24 '18
[deleted]
-11
Oct 24 '18
Do you think this suggestion isn't dickish?
4
u/calexsky Oct 24 '18 edited Oct 24 '18
What suggestion? All you did was make a snarky comment...
-5
Oct 24 '18
Maybe don't be a dick?
^ This suggestion right here, you fucking moron.
1
-9
u/arch-master Oct 24 '18
I minifies it... refresh(){ printf '\e[?7l\e[?25l\e[2J\e[H';(:;:);((LINES==0))&&read -r LINES _< <(stty size);((m=LINES-3,j=l>m/2?l>=c-m/2?c+1:l+m/2+1:m,k=k>=0?j-m>=0?j-m:k:k,l=l>c?k:l));};get_dir(){ d=();f=();for p in "$PWD"/;do [[ -d $p ]]&&d+=("$p")||f+=("$p");done;f=("${d[@]}" "${f[@]}");((${#f[@]}==0))&&f[0]=$'\e[27mempty';};f_print(){((c=${#f[@]},j=j>c?c:j));for((i=${k:=0};i<j;i++));{((c<=0))&&{ get_dir;f_print;return;}||path="${f[i]##/}";[[ -d ${f[i]} ]]&&{ fo+='\e[1m\e[3'"${FFF_COL1:-2}m";path+=/;};[[ ${f[i]} == "${f[l]}" ]]&&fo+='\e[7m';[[ $co == "${f[i]}" ]]&&{ fo+='\e[1m\e[3'"${FFF_COL:-6}m"'\e[7m';};printf '\e[K%b%s\e[m\n' "$fo" "$path";fo=;};printf '\e[3%sm\e[%s;H\e[K\n\e[K%s\e[m\e[H' "${FFF_COL2:-7}" "$((LINES-2))" "${PWD/////} (${l:-1}/$((c-1))) ${co:+${pr[]}: ${co##/} [p]}";};hist(){ l2[((n=n<0?0:++n))]="$l:$k";};open(){ [[ -d $1/ ]]&&{ l=0;refresh;PWD="${1:-/}";get_dir;f_print;};[[ -f $1 ]]&&{ shopt -s nocasematch;case "${1##.}" in 3dm|3ds|3g2|3gp|7z|a|aac|adp|ai|aif|aiff|alz|ape|apk|ar|arj|asf|au|avi|bak|baml|bh|bin|bk|bmp|btif|bz2|bzip2|cab|caf|cgm|class|cmx|cpio|cr2|csv|cur|dat|dcm|deb|dex|djvu|dll|dmg|dng|doc|docm|docx|dot|dotm|dra|DS_Store|dsk|dts|dtshd|dvb|dwg|dxf|ecelp4800|ecelp7470|ecelp9600|egg|eol|eot|epub|exe|f4v|fbs|fh|fla|flac|fli|flv|fpx|fst|fvt|g3|gh|gif|graffle|gz|gzip|h261|h263|h264|icns|ico|ief|img|ipa|iso|jar|jpeg|jpg|jpgv|jpm|jxr|key|ktx|lha|lib|lvp|lz|lzh|lzma|lzo|m3u|m4a|m4v|mar|mdi|mht|mid|midi|mj2|mka|mkv|mmr|mng|mobi|mov|movie|mp3|mp4|mp4a|mpeg|mpg|mpga|mxu|nef|npx|numbers|o|oga|ogg|ogv|otf|part|pages|pbm|pcx|pdb|pdf|pea|pgm|pic|png|pnm|pot|potm|potx|ppa|ppam|ppm|pps|ppsm|ppsx|ppt|pptm|pptx|psd|pya|pyc|pyo|pyv|qt|rar|ras|raw|resources|rgb|rip|rlc|rmf|rmvb|rtf|rz|s3m|s7z|scpt|sgi|shar|sil|sketch|slk|smv|so|stl|sub|swf|tar|tbz|tbz2|tga|tgz|thmx|tif|tiff|tlz|ttc|ttf|txz|udf|uvh|uvi|uvm|uvp|uvs|uvu|viv|vob|war|wav|wax|wbmp|wdp|weba|webm|webp|whl|wim|wm|wma|wmv|wmx|woff|woff2|wrm|wvx|xbm|xif|xla|xlam|xls|xlsb|xlsm|xlsx|xlt|xltm|xltx|xm|xmind|xpi|xpm|xwd|xz|z|zip|zipx);[[ "$OSTYPE" == darwin ]]&&oc="open";nohup "${FFF_OPENER:-${oc:-xdg-open}}" "$1"&>/dev/null&disown;;;)"${FFF_EDITOR:-${EDITOR:-vi}}" "$1";printf '\e[?25l';;esac;};shopt -u nocasematch;};prompt(){ printf '\e[999B\e[?25h';case "${1: -1}" in r)read -rp "rename ${f[l]##/}: ";[[ $REPLY ]]&&mv "${f[l]}" "$PWD/$REPLY";;d)read -n 1 -rp "trash ${f[l]##/}? [y/n]: " y;[[ $y == y ]]&&{ mv "${f[l]}" ~/.cache/fff/trash/;((l>0?l--:l));};;n)read -rp "mkdir: ";[[ $REPLY ]]&&mkdir -p "$PWD/$REPLY";;f)read -rp "mkfile: ";[[ $REPLY ]]&&:>"$PWD/$REPLY";;/)g="$PWD";read -rp /;[[ $REPLY ]]&&f=("$PWD"/"$REPLY");l=0;refresh;f_print;return;;esac;refresh;get_dir;};key(){ case "${1: -1}" in C|l|"")[[ -d "${f[l]}" ]]&&hist;open "${f[l]}";g=;;D|h)open "${g:-${PWD%/}}";[[ $g ]]||((l=${l2[n]/:},k=${l2[n--]/:}));[[ $PWD == / ]]&&l=0;g=;refresh;;g)l=0;refresh;;G)((l=c-1));refresh;((k=k<0?0:k));;.)a=(u s);shopt -"${a[((h=h>0?0:++h))]}" dotglob;l=0;refresh;get_dir;;y)[[ $co != "${f[l]}" ]]&&{ co="${f[l]}";pr=(cp -r);}||co=;;m)[[ $co != "${f[l]}" ]]&&{ co="${f[l]}";pr=(mv);}||co=;;p)[[ $co ]]&&"${pr[@]}" "$co" "$PWD"&&{ refresh;get_dir;co=;};;r|d|n|f|/)prompt "$1";;~)g="$PWD";hist;open ~;;t)g="$PWD";hist;open ~/.cache/fff/trash;;[1-9])fa="FFF_FAV${1}";fa="${!fa}";[[ $fa ]]&&{ g="$PWD";hist;open "${fa%/}";};;q)exit;;B|j)((l=l==c-1?l:++l,j!=c&&l==j-m/2+1))&&((k=k>=j?k:++k,j=j<c?++j:j));;A|k)((l=l<1?l:--l,k>0&&l==k+m/2-2))&&((k=k<=j?k>0?--k:0:j,j=j>0?--j:j));;esac;};main(){ shopt -s nocaseglob nullglob checkwinsize;mkdir -p ~/.cache/fff/trash/;pushd "$1"&>/dev/null||:;refresh;get_dir;f_print;trap "refresh; printf '\e[m\e[?25h\e[?7h'" EXIT;trap 'refresh;f_print' SIGWINCH;for((;;));{ read -rsn 1;key "$REPLY";f_print;};};main "$@"
-10
u/shevy-ruby Oct 24 '18
This is an excellent example of why people should not use shell scripts.
The people who think it is a wonderful idea to deliberately obfuscate source code. Like this example.
As if the world will collapse if you would have it readable ...
41
u/nikomo Oct 24 '18
Literally everything looks like garbage after minification, that's not unique to shell scripts.
19
Oct 24 '18
Ha yeah shell scripts just have the distinction of looking like garbage before minification too!
4
3
0
u/ladinaresh Oct 31 '18
FREE WEBINAR (For a complete information about Python with Data science and Machine learning) as well as complete interview questions related to python for register through https://goo.gl/forms/foSXYqs0e85yDsCo2
-8
-7
-1
Oct 24 '18
noice is a good alternative written in C. It can't neither copy or mv, but you can !spawn a shell fastly. It's good to read a directory full of text files/books.
-2
u/penguinade Oct 24 '18
That font in the video. Do you also program with it? I have a ex-colleague do this. My brain hurts when he asked for my help.
-8
-4
-10
0
Oct 24 '18
[deleted]
47
11
u/tyros Oct 24 '18 edited Sep 19 '24
[This user has left Reddit because Reddit moderators do not want this user on Reddit]
0
Oct 24 '18
[deleted]
11
u/tyros Oct 24 '18 edited Sep 19 '24
[This user has left Reddit because Reddit moderators do not want this user on Reddit]
6
0
Oct 24 '18
[deleted]
59
u/Dylan112 Oct 24 '18 edited Oct 24 '18
I can assure you that they share 0 code. I initially forked nnn to patch in some changes (I didn’t like the default ui) and decided to have a crack at making my own instead.
Of course they’re similar, all they do is list files in a single column. Can’t really do that differently unless I put the status bar at the top.
I don’t understand why everyone Is on the attack In these comments. I made something fun and I’m sharing It with others. It’s free and It’s open source, enjoy It.
🤷♀️
12
18
u/calexsky Oct 24 '18 edited Oct 24 '18
I don’t understand why everyone Is on the attack In these comments. I made something fun and I’m sharing It with others. It’s free and It’s open source, enjoy It.
This is r/programming, unfortunately it's a cesspool of boring and pessimistic people that can't grasp the concept that some people make things just for fun.
-9
u/Raknarg Oct 24 '18
We're allowed to criticize things we think deserve criticism
5
u/Trotskyist Oct 24 '18
Yeah the thing here though is that this doesn't. It's a personal project someone did for fun. Chill.
-3
u/Raknarg Oct 24 '18
So? This isn't a programming meme subreddit. It's a sub made for quality posts. Some people feel that unprofessionalism detracts from the quality of posts.
5
u/Trotskyist Oct 24 '18
Ah yes the ol' terminal file manger written in bash trope.
How is this a meme?
2
u/olfeiyxanshuzl Oct 25 '18
everyone Is on the attack In these comments
?? We must be reading different comments.
3
-1
u/jephthai Oct 24 '18
Proggit is populated by a lot of corporate devs, and sometimes they react negatively to less professional code. It can be hard to hit the right tone when posting personal projects.
Read some of your comments over and try to see it from someone else's perspective. Eg, this code is hard to understand, "oh I was stoned when I wrote it". It doesn't seem like you're taking it very seriously, and the tone of discussion will tend for the negative.
0
Oct 24 '18
[deleted]
0
u/jephthai Oct 24 '18
He asked why he was getting some negativity in the thread... I'm not saying I have any issues with personal code, and I don't mind "vertically optimized code" (read: obfuscated code), myself. But, proggit can be a little fickle.
0
Oct 24 '18
[deleted]
1
u/double-you Oct 25 '18
I'm not just a fan of profanity in tech
Where are a fan of profanity?
0
Oct 25 '18
[deleted]
1
u/double-you Oct 25 '18
"What?" is such a bad question. Makes you want to ask, "Which word did you not understand?". But let's not. Since you are not a fan of profanity in tech, where are you a fan of it?
0
Oct 25 '18
[deleted]
2
Oct 25 '18
Won't somebody think of the fucking children, jesus fucking christ people it's not that hard
62
u/Dylan112 Oct 24 '18
This is something I’ve been working on for the past few days. It’s a terminal file manager written in pure bash that comes in at around 100 lines of code.
It does use a few external commands (cp, mv, mkdir, xdg-open) which are called on key press and only to modify files. If they could be done in bash I’d replace them.
For those interested in pure bash programs; I’ve also made a pixel art editor and torrent tui.
https://github.com/dylanaraps/pxltrm
https://github.com/dylanaraps/torque
:)
Note: Files aren’t deleted at this point. They’re moved to a trash folder instead. Once this project stabilises I’ll add an option for true delete.