Git status indicator like ranger
Hey I really liked this git status indicators in ranger, wondering if lf has something similar implemented in it.
If not then can it be implemented with some custom scripts.
Nope, currently there is no way to display a git column in lf.
The best thing you can do is display the git status inside the prompt, as described in integrations.
There seems to be some interest in this feature though as seen in https://github.com/gokcehan/lf/issues/83, https://github.com/gokcehan/lf/issues/360 and https://github.com/gokcehan/lf/issues/843.
I might give it a try and try to implement it myself.
The reason why Git status indicators is not included as a feature is because lf is intended to be a file (system) manager, and not a Git repo manager. This means that the information provided by lf largely comes from readdir (list of directory entries) and stat (information about files) system calls, which have nothing to do with Git at all.
That being said, I'm not opposed to adding some user-defined type for set info like below:
# display both size and some custom user information for each file
set info size:user
And then the user would be responsible for populating this info through configuration via a command in lf:
# <command_name> <file_name> <value>
userinfo foo.txt "\033[32mA\033[0m" # Added
userinfo bar.txt "\033[33mM\033[0m" # Modified
This is probably how the dircounts feature could have been implemented (though I don't have any plans to change this), as the stat of a directory does not relate to how many files it contains.
In terms of implementing this, there's a few things to consider off the top of my head:
infocolumns should be aligned, so the size of each column is dynamic and is equal to the length of the longest string, see the implementation foruserandgroup: https://github.com/gokcehan/lf/blob/2494b3f632a9d735286f22b763a01fa20e81fdfa/ui.go#L400-L415- It should be possible to add color using escape sequences, however they should be stripped for the file currently under the cursor (like the screenshot in the OP)
- There should be certain points in time where this has to be updated (e.g. when the file is modified). Maybe it's possible to add hook commands like
on-loadfor when directories/files are loaded, but I haven't given this too much thought yet. Running a shell command for every file when loaded might also cause performance issues.
I am working on it. This is my progress so far. I used https://github.com/gokcehan/lf/issues/83#issuecomment-1030013438 as an orientation.
I update the column in newDir(). This way it gets updates when entering/reentering a directory, or automatically with set watch enabled.
https://github.com/CatsDeservePets/lf/blob/ed3767c67f3148cd5e1651b745010e529c968273/nav.go#L180C1-L191C3
However, I do notice a small delay when opening huge directories with many subdirs at the moment.
Right now, lf executes gOpts.infoScript which is a script that takes all file names of a directory as its parameter, iterates over them and for each file either returns a new value or an empty line. lf then stores the output inside a map which uses the file names as keys and the returned lines as values. I think that is more efficient than calling gOpts.infoScript for every single file.
I am not sure whether I should introduce a new new property for
type file struct {
os.FileInfo
...
}
instead of this map. Or putting it into dirContext.
Also, escape codes inside the script currently break the highlighting, I will work on this.
OK so I had a look at your implementation, I have some notes:
- For consistency, option names are just simply all lowercase, so it should be
infoscript, notinfoScript. - If this script is called when loading a directory, I would still prefer this to be a hook command like
on-load(files to be loaded can still be passed as parameters). This is more flexible as it can be used for other purposes like generating file previews (e.g. see #1537).lf -remote "send $id :<command1>; <command2>; ..."can still be used to output the actual custom info. - Currently the script only runs when a directory is loaded, if a file is modified (as opposed to added/deleted) then the changes won't be reflected.
- I think it's fine to store the custom info as a map. This can either be per
dirobject, or global in which case it should be passed viadirContext. - I suspect escape codes is going to be somewhat problematic, as the
infowas originally intended to just use the same style as the filename. They will have to be stripped out for the file under the cursor (you can have a look at theprintLengthfunction for ideas). Furthermoreprintfdoesn't understand escape sequences, so they will actually be counted when specifying the width. The resulting code might be a bit complex as a result.
Also what is the script you are currently using to test with?
I introduced a function stripAnsi() based on printLength(). As of right now, escape codes get fully removed before printing the custom column. They also no longer influence the calculation of infolen.
https://github.com/CatsDeservePets/lf/commit/9052fcc10e0575d6b0da37587d1bdb740eaffc78
The script I use for testing is the following:
#!/bin/sh
git rev-parse >/dev/null 2>&1 || exit 0
for file in "$@"; do
status=$(git status --porcelain -- "$file" | cut -c1-2 | head -n1)
if [ -n "$status" ]; then
printf "\033[1;35m%s\033[0m\n" "$status"
else
printf " \n"
fi
done
If we want to allow escape codes to modify the design of the custom column, I think we first have to separate the different parts of info. Some approaches:
- make
fileInfo()return a slice instead of a string - keep returning a string but replace
fmt.Fprintf(&info, " %-*s", customWidth, d.customInfo[f.Name()])
with something like
fmt.Fprintf(&info, "\x01%-*s\x02", customWidth, d.customInfo[f.Name()])
and later extract the parts using strings.SplitN() or strings.Cut()
Then depending of whether the cursor is on the current dir:
- concat the string and strip all escape sequences
- concat the string but make sure to put a reset sequence +
stafter the custom part- or replace the custom part of
infowith spaces before printing and print the custom part separately liketag
- or replace the custom part of
Then depending of whether the cursor is on the current dir:
- concat the string and strip all escape sequences
- concat the string but make sure to put a reset sequence +
stafter the custom part
- or replace the custom part of
infowith spaces before printing and print the custom part separately liketag
I don't recall any existing functionality for converting st into an escape sequence. It's probably easier to just reserve space for the custom info field (i.e. use space characters) and then print it out separately like tag. This means that fileInfo would additionally have to return the value of the custom field and also the print offset.
Another idea could be to just print everything in their defined color, and then for handling the cursor, add a utility function (similar to win.print) which applies a (cursor) style over the defined area. But that might end up being just as complex as the options already discussed so far.
I initially tried writing a function to convert from tcell.Style to escape sequences, but it seemed too error-prone. After experimenting with several approaches, I settled on returning the custom field and print offset in fileInfo while trying to introduce as few changes as possible.
https://github.com/CatsDeservePets/lf/commit/a5974d7905312ff5e2f3223c0836e52c0637ee12
Next step is making it a command.
Also, I am not fully understanding how the onLoad hook should work.
I created the hook command on-load like this (not committed yet):
func onLoad(app *app, path string) {
log.Println("onLoad: " + path)
if cmd, ok := gOpts.cmds["on-load"]; ok {
cmd.eval(app, []string{path})
}
}
It gets called inside the (app *app) loop():
case d := <-app.nav.dirChan:
onLoad(app, d.path)
Its this to correct way so far? Passing the path so the script can iterate over the files in there (CWD or just * is not possible when iterating over sub directories)?
Inside the script, how should I modify the map?
My previews attempt was calling the script inside readCustomInfo() and iterating over the command output to fill the map.
lines := strings.Split(string(out), "\n")
infoCol := make(map[string]string, len(names))
for i, line := range lines {
if i < len(names) {
infoCol[names[i]] = line
}
}
Should I expose a function like addInfo() that gets called by the script for every file like lf -remote "send $id addInfo '$file' '$info'"?
The overall idea looks correct to me, you can trigger on-load for dirChan (directory is loaded), and also fileChan (file is updated). I was thinking that you could just pass the list of files as arguments to the script as you originally intended, I'm not sure why you need to iterate over subdirectories though, each dir object only store information about their immediate children.
For outputting the data, I think it's fine to create a command for this. It should be all in lowercase, so maybe call it something like addcustominfo? Then the script should be able to invoke it via lf -remote "send $id ...". It's also possible to chain multiple commands using :<command1>; <command2> syntax to avoid calling lf -remote multiple times.
I'm not sure why you need to iterate over subdirectories though, each dir object only store information about their immediate children.
What I meant by this when the contents of a directory get shown inside the preview column and one would simply iterate over $PWD inside the script (in order to also have a custom info on those files like on the screenshot), it would not work because the $PWD would still be the other path.
It would only be a problem if we did not pass full filenames or the directory path to on-load.
If multiple directories are being loaded, the on-load hook would be invoked for each one. The value of $PWD would just be the current directory lf is in (since child processes inherit this from their parent), and not the actual directory being loaded.
Up until now, I don't think there are any hook commands that provide arguments - in theory this should be possible though but I haven't actually tried.
Ok, It mostly works now.
I removed the infoscript option in favor of the command addcustominfo. I decided on making it take an argument in the format of $LS_COLORS which makes it easy for on-load commmands to return multiple values at once. I also moved the customInfo map from the dir struct to dirContext (and therefore, also nav) because I could not find a way to modify the correct dir object from inside addcustominfo.
case "addcustominfo":
if len(e.args) != 1 {
app.ui.echoerr("addcustominfo: requires an argument formatted like $LS_COLORS")
return
}
for _, entry := range strings.Split(e.args[0], ":") {
if entry == "" {
continue
}
pair := strings.Split(entry, "=")
if len(pair) != 2 {
log.Printf("invalid custominfo entry: %s", entry)
return
}
k, v := pair[0], pair[1]
if len(strings.Trim(v, " ")) == 0 {
delete(app.nav.customInfo, k)
} else {
app.nav.customInfo[k] = v
}
}
In my lfrc I added a slightly modified version of my previous infoscript as an on-load cmd:
cmd on-load &{{
cd "$(dirname "$1")" || exit 1
git rev-parse >/dev/null 2>&1 || exit 0
info=""
for file in "$@"; do
status=$(git status --porcelain --ignored -- "$file" | cut -c1-2 | head -n1)
if [ -n "$status" ]; then
info="${info}${file}=$(printf '\033[1;35m%s\033[0m' $status):"
else
info="${info}${file}=:"
fi
done
lf -remote "send $id addcustominfo '$info'"
}}
Some things I noticed, I would appreciate your input here:
- There is still is a really short but noticeable delay before the custom info is shown but I don't think there is anything I can do about it. This can cause weird situations where the info is visible for a split second but then gets hidden because the
custominfomakes it too long. - When setting
nodircache, having anon-loadhook configured (even an empty one) does causelfto constantly reload the preview window. Perhaps I have to change the placement ofonLoadinside the channel receivers. - Without
watchenabled, the custom column still only updates when entering a directory as thecase f := <-app.nav.fileChan:doesn't seem to trigger otherwise. - Having an
on-loadhook configured constantly causes the logs to write "listFilesInCurrDir(): [path] is still loading, files isn't ready for remote query", even if the cmd is completely is completely empty.
Here s short screencast demonstrating the loading delay and the problems with nodircache:
https://github.com/user-attachments/assets/e3116e43-f860-4a85-83a5-28f9a220f607
Here you can see all the changes I did: https://github.com/gokcehan/lf/compare/master...CatsDeservePets:lf:feat/1994-custom-info-column
Are there any other things to consider? What are thoughts on the overall implementation?
Right the code looks better now, I still have the following feedback:
I prefer to keep the original syntax of addcustominfo (i.e. addcustominfo <path> <value>) to maintain consistency with other commands. Since you are still building the command string in a while loop, is there really all that much benefit to using LS_COLORS syntax? I found that it was possible to just build a chain of commands with the original syntax like so:
cmd on-load &{{
cd "$(dirname "$1")" || exit 1
git rev-parse >/dev/null 2>&1 || exit 0
cmds=""
for file in "$@"; do
status=$(git status --porcelain --ignored -- "$file" | cut -c1-2 | head -n1)
if [ -n "$status" ]; then
cmds="${cmds}addcustominfo ${file} \"\033[1;35m$status\033[0m\"; "
else
cmds="${cmds}addcustominfo ${file} ''; "
fi
done
lf -remote "send $id :$cmds"
}}
There is still is a really short but noticeable delay before the custom info is shown but I don't think there is anything I can do about it. This can cause weird situations where the info is visible for a split second but then gets hidden because the
custominfomakes it too long.
I'm not really sure if there's much that can be done about the delay either. If the delay is caused by the fact that a new shell process is being launched, then that is the price of using a shell-based user configuration system. It is possible that there is also some delay from calling git status once for each file instead of passing in all the files at once, but I'm not sure if the latter approach works or not.
When setting
nodircache, having anon-loadhook configured (even an empty one) does causelfto constantly reload the preview window. Perhaps I have to change the placement ofonLoadinside the channel receivers.
This is caused by an infinite loop, somewhat by design. When a shell command is run, it calls ui.loadFile to reflect any new changes to the filesystem. If the directory cache is disabled, then the current file will have to be loaded since it is not cached. And if the current file is a directory, then it will trigger app.nav.dirChan, thereby completing the loop. I guess one solution is to ensure that dircache is enabled inside onLoad before actually calling the on-load command.
Going off on a tangent, I think support for nodircache should be removed - the reason it existed in the first place was because updating the directory cache was unreliable early on during development, so users were given an option to disable it altogether. You can see #1414 for more details. but that is another story, and so far I decided to just leave it in because it normally doesn't cause much harm.
- Without
watchenabled, the custom column still only updates when entering a directory as thecase f := <-app.nav.fileChan:doesn't seem to trigger otherwise.
This is expected. Support for automatically picking up changes to individual files was practically non-existent until I implemented watch in #1667. It isn't enabled by default though, as I'm not sure if it causes many issues for users or not.
- Having an
on-loadhook configured constantly causes the logs to write "listFilesInCurrDir(): [path] is still loading, files isn't ready for remote query", even if the cmd is completely is completely empty.
I couldn't reproduce this, but I think this might be caused by the fact that the dir object passed to the app.nav.dirChan (with loading set to true) is stored after calling on-load. I would suggest to put the onLoad call towards the very end of the handling block, just before app.ui.draw is called.
Also some other things:
- The
addcustominfocommand needs to be added tocomplete.goso that the user can manually tab-complete it on the command line. - Should the
customInfomap be cleared during something likereload? stripAnsiis a utility function and should have some unit tests added
So in terms of my overall thoughts of this implementation, there's actually two different features that are being added here:
- Addition of
on-loadhook command - Support for custom
infofields
I think it is OK to add as the patch doesn't look too complex, but at the same time I'm not particularly excited about it either. I can see some potential use for on-load, but as for custom info fields, I think every time someone has mentioned this the use case is just for displaying Git statuses. Is it really all that useful to display the Git status for each file in a file manager? For me personally I think this is better handled inside a text editor (e.g. Vim plugins) since I view text editors to be more closely tied to repo development than file managers. I worry that one day users will start treating lf like a Git client and request features associated with it.
I prefer to keep the original syntax of
addcustominfo(i.e.addcustominfo <path> <value>) to maintain consistency with other commands. Since you are still building the command string in a while loop, is there really all that much benefit to usingLS_COLORSsyntax?
I only did it as a workaround because I was not able to find a way to execute multiple commands as a chain. Your approach works, so I changed it back. addcustominfo now takes either both <path> and <value> or just <path>. In the latter case, it treats <value> as empty and removes the entry.
I would suggest to put the
onLoadcall towards the very end of the handling block, just beforeapp.ui.drawis called.
Done! Doesn’t entirely eliminate the issue, but I see it much less now.
- The
addcustominfocommand needs to be added tocomplete.goso that the user can manually tab-complete it on the command line.
Done! Also, when only given a filename as <path>, addcustominfo assumes relative to CWD for easier completion. This is not how most commands work but I thought it made sense here. If not wanted, I can change this again.
- Should the
customInfomap be cleared during something likereload?
Sounds plausible to me but I don't want to be the one judging here. What do you think?
stripAnsiis a utility function and should have some unit tests added
Done! While doing that I noticed some quirks when passing strings containing broken escape sequences. Changing this also requires us updating printLength to avoid mismatches and misalignment (for me details see my code comments).
So in terms of my overall thoughts of this implementation, there's actually two different features that are being added here:
- Addition of
on-loadhook command- Support for custom
infofields
Should I create two separate pull requests for this with independent and cleaned-up git history?
Depending on your reply, the only thing that is still left is updating the help.
Again, here are my changes. https://github.com/CatsDeservePets/lf/commits/feat/1994-custom-info-column/
For me personally I think this is better handled inside a text editor (e.g. Vim plugins) since I view text editors to be more closely tied to repo development than file managers. I worry that one day users will start treating lf like a Git client and request features associated with it.
Personally, I think this generic approach is good. It does not suggest git client to me but rather Unix philosophy. We could also add other use cases for the info column to the docs.
OK so I took a look at your branch again, most of it looks fine. I think I lean towards having separate PRs for on-load and addcustominfo since they are technically two different features that happen to be useful when used together. If there are any other use cases apart from Git markers for these features, feel free to mention them in the docs.
Once you submit the PRs I will go through them in more detail (will take some time).
To respond to your other points:
I only did it as a workaround because I was not able to find a way to execute multiple commands as a chain. Your approach works, so I changed it back.
addcustominfonow takes either both<path>and<value>or just<path>. In the latter case, it treats<value>as empty and removes the entry.
I think it's fine to treat the <value> argument as an empty string if not provided.
Done! Also, when only given a filename as
<path>,addcustominfoassumes relative toCWDfor easier completion. This is not how most commands work but I thought it made sense here. If not wanted, I can change this again.
I think addcustominfo should allow both absolute and relative paths as you have done. The semantics and completion behavior should be similar to other commands like source and toggle.
Sounds plausible to me but I don't want to be the one judging here. What do you think?
Actually now that I think about it, the custom info probably should be stored as an additional field in the file object instead of a global map. That way it will automatically be cleared during a reload, and it is more intuitive since the fileInfo function extracts information from a file object. This does mean that addcustominfo will have to look up the directory cache for the relevant dir and then file object, but it sounds doable to me.
Done! While doing that I noticed some quirks when passing strings containing broken escape sequences. Changing this also requires us updating
printLengthto avoid mismatches and misalignment (for me details see my code comments).
Don't worry about this for now. It's important to keep the stripAnsi function similar to printLength, and I don't particularly want to have to make changes to printLength. In any case printLength typically only operates on input from the user (configuration settings involving escape sequences), so they should be able to fix any issues relating to broken escape sequences.
is there a working script for the git status indicator? would be nice to add to git integration section in the wiki :)
@horriblename You can find a simple example inside the docs.
Keep in mind this currently only works when compiling lf yourself from master as the features required to make this work were just merged and there isn't a new release yet.
Also, in my pull request I was made aware of potential problems with the example when having the watch option enabled.
I will update the example inside the docs soon and also add it to the wiki.
Speaking of new releases, it has been about a couple of months since r35 was released. There are already a number of upcoming changes, I think we should make a new release soon before that list piles up too much.
Right the code looks better now, I still have the following feedback:
I prefer to keep the original syntax of
addcustominfo(i.e.addcustominfo <path> <value>) to maintain consistency with other commands. Since you are still building the command string in a while loop, is there really all that much benefit to usingLS_COLORSsyntax? I found that it was possible to just build a chain of commands with the original syntax like so:cmd on-load &{{ cd "$(dirname "$1")" || exit 1 git rev-parse >/dev/null 2>&1 || exit 0 cmds="" for file in "$@"; do status=$(git status --porcelain --ignored -- "$file" | cut -c1-2 | head -n1) if [ -n "$status" ]; then cmds="${cmds}addcustominfo ${file} \"\033[1;35m$status\033[0m\"; " else cmds="${cmds}addcustominfo ${file} ''; " fi done lf -remote "send $id :$cmds" }}There is still is a really short but noticeable delay before the custom info is shown but I don't think there is anything I can do about it. This can cause weird situations where the info is visible for a split second but then gets hidden because the
custominfomakes it too long.
So this command will call git status for each file, which is costly. It could be optimized to query git status once and parse the results with bash into associative array. Eg.
cmd on-load &{{
cd "$(dirname "$1")" || exit 1
git rev-parse >/dev/null 2>&1 || exit 0
prefix=$(git rev-parse --show-prefix 2>/dev/null)
declare -A statusarray
while read -r line; do
# Extract status and file name
status="${line:0:2}"
file="${line:3}"
# Remove prefix if it exists
file="${file#"$prefix"}"
file="${file%%/*}" # Treat nested files as one
# Store in associative array
statusarray[$file]="$status"
done < <(git status --porcelain --ignored -- .)
cmds=""
for file in "$@"; do
filename="${file##*/}"
if [[ -v statusarray[$filename] ]]; then
cmds+="addcustominfo '$file' '\033[1;35m${statusarray[$filename]}\033[0m';"
else
cmds+="addcustominfo '$file' '';"
fi
done
lf -remote "send $id :$cmds"
}}
I've made a simple test to compare times and outputs of solution and it's about 3 times faster on a folder with 8 files:
The new one:
real 0m0.011s
user 0m0.004s
sys 0m0.008s
send addcustominfo /home/user/r/app/rust/.cargo '';addcustominfo /home/user/r/app/rust/test.sh '??';addcustominfo /home/user/r/app/rust/target '!!';addcustominfo /home/user/r/app/rust/Cargo.lock '!!';addcustominfo /home/user/r/app/rust/src 'M ';addcustominfo /home/user/r/app/rust/README.md '';addcustominfo /home/user/r/app/rust/Makefile '';addcustominfo /home/user/r/app/rust/cliff.toml '';addcustominfo /home/user/r/app/rust/Cargo.toml.in '';addcustominfo /home/user/r/app/rust/Cargo.toml '!!';
The original one:
real 0m0.035s
user 0m0.045s
sys 0m0.011s
send addcustominfo /home/user/r/app/rust/.cargo ''; addcustominfo /home/user/r/app/rust/test.sh "??"; addcustominfo /home/user/r/app/rust/target "!!"; addcustominfo /home/user/r/app/rust/Cargo.lock "!!"; addcustominfo /home/user/r/app/rust/src "A "; addcustominfo /home/user/r/app/rust/README.md ''; addcustominfo /home/user/r/app/rust/Makefile ''; addcustominfo /home/user/r/app/rust/cliff.toml ''; addcustominfo /home/user/r/app/rust/Cargo.toml.in ''; addcustominfo /home/user/r/app/rust/Cargo.toml "!!"
Using a faster solution obviously provides to a better, snappier experience. 😎
Hello, @mibli.
As someone who is not that deep into unix shell scripting, it is nice to see people coming up with more efficient solutions. Faster is always better!
Those are just my thoughts about this implementation:
- First of all, the speed gain is really noticeable!
- While my version runs fine just using
sh, yours specifically requiresbash 4+which makes it less portable (for example,MacOSonly comes withbash 3.2preinstalled) and requires eitherset shell "bash"or wrapping the command inside abash -ccall with more verbose escaping. If your version gets merged, we should mention this in a sentence as it silently fails without the user noticing. - Your version doesn't handle the
ANSI escape sequencescorrectly. Here is a simple fix:
cmds+="addcustominfo '$file' \"\033[1;35m${statusarray[$filename]}\033[0m\"; "
- You might want to slightly update your version to align with the latest version of the docs as that one ignores/skips
.gitdirectories. For more information, read the comments inside the pull request (also the version in the docs no longer includes thoseANSI codes, I only used them during testing).
cmd on-load &{{
cd "$(dirname "$1")" || exit 1
[ "$(git rev-parse --is-inside-git-dir 2>/dev/null)" = false ] || exit 0
cmds=""
for file in "$@"; do
case "$file" in
*/.git|*/.git/*) continue;;
esac
status=$(git status --porcelain --ignored -- "$file" | cut -c1-2 | head -n1)
if [ -n "$status" ]; then
cmds="${cmds}addcustominfo ${file} \"$status\"; "
else
cmds="${cmds}addcustominfo ${file} ''; "
fi
done
lf -remote "send $id :$cmds"
}}
Hey @CatsDeservePets
First of all, thanks for amazing feedback. To be honest I didn't take bash variations into consideration, I'm so used to these features being present on linux for so long, that one can forget about the rest of the world :D
- While my version runs fine just using
sh, yours specifically requiresbash 4+which makes it less portable (for example,MacOSonly comes withbash 3.2preinstalled) and requires eitherset shell "bash"or wrapping the command inside abash -ccall with more verbose escaping. If your version gets merged, we should mention this in a sentence as it silently fails without the user noticing.
I have to give it to You that if we wanted to use pure sh the original proposition couldn't be made much faster, because we still would need to make a bunch of system calls (and I've tested it).
- Your version doesn't handle the
ANSI escape sequencescorrectly. Here is a simple fix:cmds+="addcustominfo '$file' "\033[1;35m${statusarray[$filename]}\033[0m"; "
![]()
Yeah this is weird because it worked for me, so I guess the double quotes really do matter! Good catch!
So Yeah I've spent a little time this morning to prepare a version that's for bash 3.2, and tested a couple of approaches (mostly using command line utils, and they were slow). The resulting mostly pure bash solution it's actually still pretty damn fast 😎. It gets close to O(n * log(n)) complexity of the original proposition, by reducing the size of the array for each match. It doesn't do any system calls aside from the necessary ones. It could be added as an option, although it is noticably more complex, it could be a good boilerplate for advanced parsing (if you have different statuses for a directory for example).
cmd on-load &{{
cd "$(dirname "$1")" || exit 1
[ "$(git rev-parse --is-inside-git-dir 2>/dev/null)" = false ] || exit 0
prefix=$(git rev-parse --show-prefix 2>/dev/null)
array=()
lastfile=""
while read -r line; do
status="${line:0:2}"
file="${line:3}"
file="${file#"$prefix"}"
file="${file%%/*}"
if [ "$status" = " " ]; then
continue
fi
if [ "$file" = "$lastfile" ]; then
continue
fi
array+=( "$status $file" )
done < <(git status --porcelain --ignored -- .)
cmds=""
for file in "$@"; do
case "$file" in
*/.git|*/.git/*) continue;;
esac
filename="${file##*/}"
status=""
idx=0
for line in "${array[@]}"; do
if [[ "${line:3}" == "$filename" ]]; then
status="\\033[1;35m${line:0:2}\\033[0m"
break
fi
idx=$((idx + 1))
done
if [ -n "$status" ]; then
unset "array[$idx]"
fi
cmds+="addcustominfo '$file' \"$status\";"
done
lf -remote "send $id :$cmds"
}}
And then again, thanks for coming up with this amazing feature!
