Re: [hackers] [dmenu][RFC][PATCH] History functionality

2016-01-10 Thread Silvan Jegen
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

2015-12-17 Thread Xarchus
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

2015-12-15 Thread Xarchus
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

2015-12-12 Thread Xarchus
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

2015-12-11 Thread Xarchus
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

2015-12-11 Thread Silvan Jegen
Heyho

On Fri, Dec 11, 2015 at 3:41 PM, Xarchus  wrote:
> 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

2015-12-09 Thread Roberto E. Vargas Caballero
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

2015-12-09 Thread Silvan Jegen
On Tue, Dec 8, 2015 at 8:34 PM, Silvan Jegen  wrote:
> 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

2015-12-09 Thread Silvan Jegen
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?

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

2015-12-08 Thread Silvan Jegen
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

2015-12-03 Thread Silvan Jegen
Hi

On Thu, Dec 3, 2015 at 11:57 AM, Xarchus  wrote:
> 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

2015-12-03 Thread Xarchus
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