Re: [hackers] [dmenu][RFC][PATCH] History functionality
Heyho and sorry for not answering earlier. I thought you were not waiting for any OK from me but would apply it as soon as possible. On Thu, Dec 17, 2015 at 05:07:38AM -0800, Xarchus wrote: > Attached is the version of the text that will go under the "scripts" > section, in a separate page. Let me know if all is OK, any changes, etc. LGTM! > It will have a link pointing to it from the main "scripts/" > list: > > * > [dmenu_run_history](http://tools.suckless.org/dmenu/scripts/dmenu_run_with_command_history) > > As a separate page, I think it will also show up in the left vertical bar, > under "scripts/". > > I will deal with moving or deleting the old history patch later, I'm > thinking of starting a thread in the wiki list about the fate of the > "legacy" section, although I doubt there will be much interest. > dmenu_run with command history > == > > A self-contained alternative to dmenu_run which also handles history. > > History is saved in a file in `$XDG_CACHE_HOME`, with fallback to a dot > file in `$HOME`. Change as necessary. > > In addition to the above, dmenu_run_history will launch each entry > immediately on `Ctrl-Return` (multiselect). > > The script can be used with the 4.6 version of dmenu. > > Download > > > [dmenu_run_history](dmenu_run_history) (20151217) > > Authors > === > > * Silvan Jegen Since I did not really contribute a lot of code a "Contributor" tag may be more apt here. I don't mind either way. > * Xarchus Cheers and thanks for the work! Silvan
Re: [hackers] [dmenu][RFC][PATCH] History functionality
Attached is the version of the text that will go under the "scripts" section, in a separate page. Let me know if all is OK, any changes, etc. It will have a link pointing to it from the main "scripts/" list: * [dmenu_run_history](http://tools.suckless.org/dmenu/scripts/dmenu_run_with_command_history) As a separate page, I think it will also show up in the left vertical bar, under "scripts/". I will deal with moving or deleting the old history patch later, I'm thinking of starting a thread in the wiki list about the fate of the "legacy" section, although I doubt there will be much interest. dmenu_run with command history == A self-contained alternative to dmenu_run which also handles history. History is saved in a file in `$XDG_CACHE_HOME`, with fallback to a dot file in `$HOME`. Change as necessary. In addition to the above, dmenu_run_history will launch each entry immediately on `Ctrl-Return` (multiselect). The script can be used with the 4.6 version of dmenu. Download [dmenu_run_history](dmenu_run_history) (20151217) Authors === * Silvan Jegen * Xarchus
Re: [hackers] [dmenu][RFC][PATCH] History functionality
On Mon, Dec 14, 2015 at 06:57:34PM +0100, Silvan Jegen wrote: > Heyolo [...] No problem, I'll take care of the trailing spaces. > > I think it can go on the site like that. I would vote for it superseding > the old history patch which integrated the history functionality in > dmenu's C code and does not apply to tip anymore. Yes, there is a lot of cruft accumulated in the patches section ... To be super-safe, that history patch can be moved into the "legacy" section. The script itself is indeed ancient and obsolete, but the description might be useful, it can give people good hints of what can be done (i.e. some sort of integration with surf, etc.) But there is also a distinction between that one and the new thing. The old patch, as invasive as it was (modifying dmenu itself), allowed the option to use history (or not) wherever dmenu was used, on a case by case basis. By having the file supplied by the caller to dmenu, multiple history contexts could be maintained, and not only for executables, but for URLs, plain strings or whatever the other instances of dmenu were getting fed with. (You could still achieve a similar effect with a general wrapper that offers history, but the generality would add a bit of complexity as I guess you've already noticed) This dmenu_run_history, the culmination of our last couple of weeks of discussion, is what the name implies, a *global* (per-user) history mechanism *for* *dmenu_run*. Nothing more. In any other context where a history is desired (say, as in the way the old patch's author was suggesting about using it in surf), it would require some changes. Which of course, can be left as an exercise for the reader. It's not difficult at all, just that each situation will need specific customizations. But it's good to set the expectations, so I think the title should be something like "dmenu_run replacement providing history" or something like that. Another thing is that this dmenu_run_history is, technically, almost a 'script' and not a 'patch'. (well, in between, 80% script, 20% patch ?) demnu_run_history can be run in place of dmenu_run, but doesn't change demnu_run, which can still coexist with it. Hmmm... I noticed in the dmenu wiki area, there is a section for scripts: I rarely ventured there, but indeed it exists. To my surprise, it even has a very old attempt at adding history into dmenu_path, but in a bit of a process-heavy pipe-festival kind of way. Also, its history file saves every command invocation, multiple times, which is a bit funny, but, hey, in the end the whole thing is quite compact and it seems to do the job. So another alternative would be to stick this dmenu_run_history there, in the 'scripts' section, although I would try to make its own entry, in the same way each patch has its own page under "patches/". To summarize: For the old 'history' patch: A1. Move it into legacy A2. Keep it A3. Delete it For the new stuff: B. Create patch entry (under "patches/") for "dmenu_run with history" C. Create entry under "scripts/" for "dmenu_run with history" You kind of voted for A3 and B , is that correct ? I would be tempted to do A1 and B, although I would feel more accurate to do a C instead of B ... But I don't mind either way.
Re: [hackers] [dmenu][RFC][PATCH] History functionality
Yes, I feel strongly that if dmenu_path used to keep its file in a standard place (XDG_CACHE_HOME or as a dot in HOME), then the history should be placed in the same location. It's just clean, uniform design. I also realized that all the functionality of dmenu_run with history can be kept inside one single file, removing the dependency on dmenu_path. Basically merging dmenu_run and dmenu_path together with the history stuff into one self-contained shell script: dmenu_run_history. And the instructions on the wiki should simply say: dmenu_run_history, a self-contained alternative to dmenu_run which also handles history. History is saved in a file in XDG_CACHE_HOME, with fallback to a dot file in $HOME. Change as necessary. In addition to the above, dmenu_run_history will launch each entry immediately on Ctrl-Return (multiselect). diff --git a/dmenu_run_history b/dmenu_run_history new file mode 100755 index 000..6ef353d --- /dev/null +++ b/dmenu_run_history @@ -0,0 +1,50 @@ +#!/bin/sh + +cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"} +if [ -d "$cachedir" ]; then + cache=$cachedir/dmenu_run + historyfile=$cachedir/dmenu_history +else # if no xdg dir, fall back to dotfiles in ~ + cache=$HOME/.dmenu_cache + historyfile=$HOME/.dmenu_history +fi + +IFS=: +if stest -dqr -n "$cache" $PATH; then + stest -flx $PATH | sort -u > "$cache" +fi +unset IFS + +awk -v histfile=$historyfile ' + BEGIN { + while( (getline < histfile) > 0 ) { + sub("^[0-9]+\t","") + print + x[$0]=1 + } + } !x[$0]++ ' "$cache" \ + | dmenu "$@" \ + | awk -v histfile=$historyfile ' + BEGIN { + FS=OFS="\t" + while ( (getline < histfile) > 0 ) { + count=$1 + sub("^[0-9]+\t","") + fname=$0 + history[fname]=count + } + close(histfile) + } + + { + history[$0]++ + print + } + + END { + if(!NR) exit + for (f in history) + print history[f],f | "sort -t '\t' -k1rn >" histfile + } + ' \ + | while read cmd; do ${SHELL:-"/bin/sh"} -c "$cmd" & done
Re: [hackers] [dmenu][RFC][PATCH] History functionality
On Wed, Dec 09, 2015 at 11:16:07AM +0100, Silvan Jegen wrote: > On Wed, Dec 9, 2015 at 11:12 AM, Roberto E. Vargas Caballero >wrote: > > On Wed, Dec 09, 2015 at 10:31:09AM +0100, Silvan Jegen wrote: > >> I realized that I am not dealing with the case that the history file > >> does not exist already. I added a simple check for that (although I > >> was considering just putting in a comment saying that it has to). > >> > > > >> +if [ ! -e $historyfile ]; then > >> + touch $historyfile > >> +fi > > > > Why the if?, why not directly touch the file? > > Removing the if is even simpler. To paraphrase Roberto: Why the touch?, why not just let awk create the file? ;) That is removing the touch is even simpler. (try it: remove the touch, delete the file, run the stuff: in the END block in dmenu_run the redirection will create the file) > I realized that I am not dealing with the case that the history file > does not exist already. I added a simple check for that (although I > was considering just putting in a comment saying that it has to). You are actually conflating a few things about that history file. First of all, let's talk about the variable that holds the name of the file. Such a variable, be it in shell or in awk, should exist and be non-empty in order to have some history working. So, to keep things clear, when you said ... > I also missed the opportunity to remove file checks from the awk code. ... Those checks were guarding against the case when the _variable_ is empty/not set, and they had nothing to do with the existence of the actual file. But since you expressed the preference to have some history specified at all times, I will assume for the remaining of the explanation that such a variable exists and has a non-empty value. OK, now the file *name* exists in the code. Such a name can be obviously a file *path*. Here are, roughly, the main cases: A. The location pointed by the path does not exist. What I mean here is the `dirname` of that path does not exist; a non-existent file can be created, but if one of the intermediate directories does not exist, that's bad and the whole dmenu_run fails ugly. Do you want to 'mkdir -p $(dirname $HISTORY)' ? B. The actual file does not exist. As I've shown above when talking about the extraneous 'touch', the code was already handling that. C. The path is accessible but not writable (including the case the file already exists and is not writable). Updating the history will fail with an error message, but other than that, no disasters. This will manifest as a "frozen" history. (The ' stest -v -qfrw "$HISTORY" ' in my initial version of dmenu_path was meant to guard against that.) To recap, B is not a problem, C is rare and relatively benign, I can live with it; but A is a bit of a problem. Which brings me back to your preference to hardcode a certain value for the history file path. One problem with hardcoded values is to pick one that works in all cases. You picked ~/.cache/dmenu/history . I guess because all those intermediate directories exist on _your_ machine. But for other people that could cause a failure of type A. What if this is an account that does not have ~/.cache ? Or what if the owner of that account sets XDG_CACHE_HOME to some other value (and again ~/.cache does not exist ?) If you'll always create the path (with that 'mkdir -p' I've shown earlier), or if you just use a file directly in $HOME, you might pollute someone's home dir. Are you sure they are ok with that ? (maybe they explicitly set that XDG_CACHE_HOME for a reason ? :) ). The stock 'dmenu_path' handles similar cases for its cache file: locates the correct .cache if it exists, otherwise *falls back* to something in the home dir. All that is *guaranteed* to work. It is just tidy to do a similar thing with the history. Which brings me to a bit of discussion about principles. You might say "works for me as it is, I will add comments in the file as instructions... Let the others edit it themselves". I think the courteous thing to do is have a general version of the patch that works as is no matter what. And if you want to change things, just edit your local copy. How about that? To summarize, have HISTORY set at all times (so no extra checks in the awk), but with a code similar to what dmenu_path does for the cache. Also, no code to guard against a non-writable path. Agree? (and BTW, I found a small optimization but we can talk about that later)
Re: [hackers] [dmenu][RFC][PATCH] History functionality
Heyho On Fri, Dec 11, 2015 at 3:41 PM, Xarchuswrote: > On Wed, Dec 09, 2015 at 11:16:07AM +0100, Silvan Jegen wrote: >> On Wed, Dec 9, 2015 at 11:12 AM, Roberto E. Vargas Caballero >> wrote: >> > On Wed, Dec 09, 2015 at 10:31:09AM +0100, Silvan Jegen wrote: >> >> I realized that I am not dealing with the case that the history file >> >> does not exist already. I added a simple check for that (although I >> >> was considering just putting in a comment saying that it has to). >> >> >> > >> >> +if [ ! -e $historyfile ]; then >> >> + touch $historyfile >> >> +fi >> > >> > Why the if?, why not directly touch the file? >> >> Removing the if is even simpler. > > To paraphrase Roberto: > Why the touch?, why not just let awk create the file? ;) Because when I ran dmenu_run awk complained (and may then have created the file?) and dmenu showed no entries. I think it is bad behaviour for a program to behave differently when being run two times in a row with the same arguments. > That is removing the touch is even simpler. > (try it: remove the touch, delete the file, run the stuff: in the END block > in dmenu_run the redirection will create the file) > >> I realized that I am not dealing with the case that the history file >> does not exist already. I added a simple check for that (although I >> was considering just putting in a comment saying that it has to). > > You are actually conflating a few things about that history file. > > First of all, let's talk about the variable that holds the name of the > file. Such a variable, be it in shell or in awk, should exist and be > non-empty in order to have some history working. As I said before, I don't agree with you on this. > So, to keep things clear, when you said ... >> I also missed the opportunity to remove file checks from the awk code. > ... Those checks were guarding against the case when the _variable_ is > empty/not set, and they had nothing to do with the existence of the actual > file. Could be, but it the difference does not matter if you hard code the file location like I do. > But since you expressed the preference to have some history specified at > all times, I will assume for the remaining of the explanation that such a > variable exists and has a non-empty value. > > OK, now the file *name* exists in the code. Such a name can be obviously a > file *path*. Here are, roughly, the main cases: > > A. The location pointed by the path does not exist. > > What I mean here is the `dirname` of that path does not exist; a > non-existent file can be created, but if one of the intermediate > directories does not exist, that's bad and the whole dmenu_run fails ugly. > Do you want to 'mkdir -p $(dirname $HISTORY)' ? > > B. The actual file does not exist. > >As I've shown above when talking about the extraneous 'touch', the code > was already handling that. > > C. The path is accessible but not writable (including the case the file > already exists and is not writable). > >Updating the history will fail with an error message, but other than > that, no disasters. This will manifest as a "frozen" history. (The ' stest > -v -qfrw "$HISTORY" ' in my initial version of dmenu_path was meant to > guard against that.) > > To recap, B is not a problem, C is rare and relatively benign, I can live > with it; but A is a bit of a problem. > > Which brings me back to your preference to hardcode a certain value for the > history file path. One problem with hardcoded values is to pick one that > works in all cases. The whole point is that the person downloading the patch looks at the script and adjusts the variable to point to a destination he wants to use. That renders all the above concerns moot. The ~/.cache/dmenu/history I put there is just what I use. I would add a comment above the variable like # Adjust to the location you want to be used for the history file but even that seems rather redundant given the variable name and the value. > You picked ~/.cache/dmenu/history . I guess because all those intermediate > directories exist on _your_ machine. But for other people that could cause > a failure of type A. > > What if this is an account that does not have ~/.cache ? Or what if the > owner of that account sets XDG_CACHE_HOME to some other value (and again > ~/.cache does not exist ?) > > If you'll always create the path (with that 'mkdir -p' I've shown earlier), > or if you just use a file directly in $HOME, you might pollute someone's > home dir. Are you sure they are ok with that ? (maybe they explicitly set > that XDG_CACHE_HOME for a reason ? :) ). > > > The stock 'dmenu_path' handles similar cases for its cache file: locates the > correct .cache if it exists, otherwise *falls back* to something in the > home dir. All that is *guaranteed* to work. It is just tidy to do a similar > thing with the history. I don't agree because the whole point of the history patch is to use the history so it has to
Re: [hackers] [dmenu][RFC][PATCH] History functionality
On Wed, Dec 09, 2015 at 10:31:09AM +0100, Silvan Jegen wrote: > I realized that I am not dealing with the case that the history file > does not exist already. I added a simple check for that (although I > was considering just putting in a comment saying that it has to). > > +if [ ! -e $historyfile ]; then > + touch $historyfile > +fi Why the if?, why not directly touch the file? Regards,
Re: [hackers] [dmenu][RFC][PATCH] History functionality
On Tue, Dec 8, 2015 at 8:34 PM, Silvan Jegenwrote: > Heyhey > > On Thu, Dec 03, 2015 at 02:57:52AM -0800, Xarchus wrote: >> [...] >> >> - improved the history/cache parsing/de-duplication awk one-liner in >> dmenu_path; the former 'NR==FNR' test was not enough: in case of a not >> supplied or empty history file it attempted to remove a count followed by a >> tab from the file names in the cache. Obviously to find such an occurrence >> would be crazy rare, so it was quite harmless (I suppose that you don't >> have any executables in your path of the form "count\tname", do you ? >> Anyway, now you can :) ) >> >> New patch attached. > > I have tested it briefly and it works for me. I would remove all the > checks as done in the attached version of the patch. > > If you are happy with this version we should put it on the website. The > question is whether we should replace the current version that does not > apply to tip or just add it as an alternate history patch. I realized that I am not dealing with the case that the history file does not exist already. I added a simple check for that (although I was considering just putting in a comment saying that it has to). I also missed the opportunity to remove file checks from the awk code. Find a new patch containing these changes attached. diff --git a/dmenu_path b/dmenu_path old mode 100644 new mode 100755 index 338bac4..c928173 --- a/dmenu_path +++ b/dmenu_path @@ -1,4 +1,6 @@ #!/bin/sh +HISTORY="$1" + cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"} if [ -d "$cachedir" ]; then cache=$cachedir/dmenu_run @@ -7,7 +9,6 @@ else fi IFS=: if stest -dqr -n "$cache" $PATH; then - stest -flx $PATH | sort -u | tee "$cache" -else - cat "$cache" + stest -flx $PATH | sort -u > "$cache" fi +awk '!cache { sub("^[0-9]+\t","") } !x[$0]++' "$HISTORY" cache=1 "$cache" diff --git a/dmenu_run b/dmenu_run index 834ede5..ef7c579 100755 --- a/dmenu_run +++ b/dmenu_run @@ -1,2 +1,31 @@ #!/bin/sh -dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} & + +historyfile=~/.cache/dmenu/history +if [ ! -e $historyfile ]; then + touch $historyfile +fi + +dmenu_path $historyfile | dmenu "$@" \ + | awk -v histfile=$historyfile ' + BEGIN { + FS=OFS="\t" + while ( (getline < histfile) > 0 ) { +count=$1 +sub("^[0-9]+\t","") +fname=$0 +history[fname]=count + } + close(histfile) + } + + { + history[$0]++ + print + } + + END { + for (f in history) +print history[f],f | "sort -t '\t' -k1rn >" histfile + } + ' \ + | while read cmd; do ${SHELL:-"/bin/sh"} -c "$cmd" & done
Re: [hackers] [dmenu][RFC][PATCH] History functionality
On Wed, Dec 9, 2015 at 11:12 AM, Roberto E. Vargas Caballerowrote: > On Wed, Dec 09, 2015 at 10:31:09AM +0100, Silvan Jegen wrote: >> I realized that I am not dealing with the case that the history file >> does not exist already. I added a simple check for that (although I >> was considering just putting in a comment saying that it has to). >> > >> +if [ ! -e $historyfile ]; then >> + touch $historyfile >> +fi > > Why the if?, why not directly touch the file? You are right. I confused the history file with the cache file. The cache file's time stamp is compared to the directories in the PATH to determine if it has to be updated or not. Removing the if is even simpler.
Re: [hackers] [dmenu][RFC][PATCH] History functionality
Heyhey On Thu, Dec 03, 2015 at 02:57:52AM -0800, Xarchus wrote: > [...] > > - improved the history/cache parsing/de-duplication awk one-liner in > dmenu_path; the former 'NR==FNR' test was not enough: in case of a not > supplied or empty history file it attempted to remove a count followed by a > tab from the file names in the cache. Obviously to find such an occurrence > would be crazy rare, so it was quite harmless (I suppose that you don't > have any executables in your path of the form "count\tname", do you ? > Anyway, now you can :) ) > > New patch attached. I have tested it briefly and it works for me. I would remove all the checks as done in the attached version of the patch. If you are happy with this version we should put it on the website. The question is whether we should replace the current version that does not apply to tip or just add it as an alternate history patch. Cheers, Silvan diff --git a/dmenu_path b/dmenu_path old mode 100644 new mode 100755 index 338bac4..c928173 --- a/dmenu_path +++ b/dmenu_path @@ -1,4 +1,6 @@ #!/bin/sh +HISTORY="$1" + cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"} if [ -d "$cachedir" ]; then cache=$cachedir/dmenu_run @@ -7,7 +9,6 @@ else fi IFS=: if stest -dqr -n "$cache" $PATH; then - stest -flx $PATH | sort -u | tee "$cache" -else - cat "$cache" + stest -flx $PATH | sort -u > "$cache" fi +awk '!cache { sub("^[0-9]+\t","") } !x[$0]++' "$HISTORY" cache=1 "$cache" diff --git a/dmenu_run b/dmenu_run index 834ede5..cfb8323 100755 --- a/dmenu_run +++ b/dmenu_run @@ -1,2 +1,32 @@ #!/bin/sh -dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} & + +historyfile=~/.cache/dmenu/history + +dmenu_path $historyfile | dmenu "$@" \ + | awk -v histfile=$historyfile ' + BEGIN { + FS=OFS="\t" + if(histfile) { +while ( (getline < histfile) > 0 ) { + count=$1 + sub("^[0-9]+\t","") + fname=$0 + history[fname]=count +} +close(histfile) + } + } + + { + history[$0]++ + print + } + + END { + if(!histfile) +exit + for (f in history) +print history[f],f | "sort -t '\t' -k1rn >" histfile + } + ' \ + | while read cmd; do ${SHELL:-"/bin/sh"} -c "$cmd" & done
Re: [hackers] [dmenu][RFC][PATCH] History functionality
Hi On Thu, Dec 3, 2015 at 11:57 AM, Xarchuswrote: > And a couple of fixes for the 'history' patch: > > - fixed the code in the BEGIN block of the inline awk program in dmenu_run; > if no history file was supplied the awk script was just ignoring any > output from dmenu > > - improved the history/cache parsing/de-duplication awk one-liner in > dmenu_path; the former 'NR==FNR' test was not enough: in case of a not > supplied or empty history file it attempted to remove a count followed by a > tab from the file names in the cache. Obviously to find such an occurrence > would be crazy rare, so it was quite harmless (I suppose that you don't > have any executables in your path of the form "count\tname", do you ? > Anyway, now you can :) ) > > New patch attached. Thanks! At the moment I don't have time to test the patch I am afraid but I will test it as soon as I find the time. I would prefer to not deal with the case the HISTORY is unset and just assume it is. The reason being that if people don't want to use the history functionality, they should not use this patch. Under this assumption the code can be further simplified. I also prefer setting the HISTORY variable to a file name explicitly as opposed to in an environment variable with fallback code but that may only be me. Setting the history file name directly in dmenu_run is not any harder than setting an environment variable and checking for default location would also not be needed then. Cheers, Silvan
Re: [hackers] [dmenu][RFC][PATCH] History functionality
And a couple of fixes for the 'history' patch: - fixed the code in the BEGIN block of the inline awk program in dmenu_run; if no history file was supplied the awk script was just ignoring any output from dmenu - improved the history/cache parsing/de-duplication awk one-liner in dmenu_path; the former 'NR==FNR' test was not enough: in case of a not supplied or empty history file it attempted to remove a count followed by a tab from the file names in the cache. Obviously to find such an occurrence would be crazy rare, so it was quite harmless (I suppose that you don't have any executables in your path of the form "count\tname", do you ? Anyway, now you can :) ) New patch attached. diff --git a/dmenu_path b/dmenu_path old mode 100644 new mode 100755 index 338bac4..b81a85a --- a/dmenu_path +++ b/dmenu_path @@ -1,4 +1,10 @@ #!/bin/sh +HISTORY="$1" + +if stest -v -qfrw "$HISTORY"; then + unset HISTORY +fi + cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"} if [ -d "$cachedir" ]; then cache=$cachedir/dmenu_run @@ -7,7 +13,7 @@ else fi IFS=: if stest -dqr -n "$cache" $PATH; then - stest -flx $PATH | sort -u | tee "$cache" -else - cat "$cache" + stest -flx $PATH | sort -u > "$cache" fi +awk '!cache { sub("^[0-9]+\t","") } !x[$0]++' "$HISTORY" cache=1 "$cache" + diff --git a/dmenu_run b/dmenu_run index 834ede5..e93a790 100755 --- a/dmenu_run +++ b/dmenu_run @@ -1,2 +1,43 @@ #!/bin/sh -dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} & + +historyfile="$DMENU_RUN_USE_HISTORY" + +if [ -n "$historyfile" ]; then + if [ "$historyfile" = "DEFAULT" ]; then + cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"} + if [ -d "$cachedir" ]; then + historyfile=$cachedir/dmenu_history + else + historyfile=$HOME/.dmenu_history # if no xdg dir, fall back to dotfile in ~ + fi + fi +fi + +dmenu_path $historyfile | dmenu "$@" \ + | awk -v histfile=$historyfile ' + BEGIN { + FS=OFS="\t" + if(histfile) { + while ( (getline < histfile) > 0 ) { + count=$1 + sub("^[0-9]+\t","") + fname=$0 + history[fname]=count + } + close(histfile) + } + } + + { + history[$0]++ + print + } + + END { + if(!histfile) + exit + for (f in history) + print history[f],f | "sort -t '\t' -k1rn >" histfile + } + ' \ + | while read cmd; do ${SHELL:-"/bin/sh"} -c "$cmd" & done