You are not logged in.

#276 2014-11-18 03:49:15

Rasi
Member
From: Germany
Registered: 2007-08-14
Posts: 1,912
Website

Re: Dmenu Hacking Thread

thanks, I updated the original post too..


He hoped and prayed that there wasn't an afterlife. Then he realized there was a contradiction involved here and merely hoped that there wasn't an afterlife.

Douglas Adams

Offline

#277 2015-03-16 03:09:07

bslackr
Member
Registered: 2012-01-27
Posts: 131

Re: Dmenu Hacking Thread

I found out that you can use baloo without kde. I wrote a simple python script that pipes baloo matches into dmenu.  To use it, first run the following commands:

balooctl enable
balooctl start

"balooctl start" needs to be run on login, so put it in your .xinitrc, or whatever. The script uses xyne's mimeo (an alternative to xdg-open) as it seems to open files faster than standard xdg-open, but you can replace this if you want. Name it whatever you want, e.g. mysearch. If you give it search terms as an argument it will use those, otherwise it will prompt you.

#!/usr/bin/env python3

import os
import re
import sys
import collections

from subprocess import Popen, PIPE, STDOUT

# From: http://code.activestate.com/recipes/576694/
class OrderedSet(collections.MutableSet):

    def __init__(self, iterable=None):
        self.end = end = [] 
        end += [None, end, end]         # sentinel node for doubly linked list
        self.map = {}                   # key --> [key, prev, next]
        if iterable is not None:
            self |= iterable

    def __len__(self):
        return len(self.map)

    def __contains__(self, key):
        return key in self.map

    def add(self, key):
        if key not in self.map:
            end = self.end
            curr = end[1]
            curr[2] = end[1] = self.map[key] = [key, curr, end]

    def discard(self, key):
        if key in self.map:        
            key, prev, next = self.map.pop(key)
            prev[2] = next
            next[1] = prev

    def __iter__(self):
        end = self.end
        curr = end[2]
        while curr is not end:
            yield curr[0]
            curr = curr[2]

    def __reversed__(self):
        end = self.end
        curr = end[1]
        while curr is not end:
            yield curr[0]
            curr = curr[1]

    def pop(self, last=True):
        if not self:
            raise KeyError('set is empty')
        key = self.end[1][0] if last else self.end[2][0]
        self.discard(key)
        return key

    def __repr__(self):
        if not self:
            return '%s()' % (self.__class__.__name__,)
        return '%s(%r)' % (self.__class__.__name__, list(self))

    def __eq__(self, other):
        if isinstance(other, OrderedSet):
            return len(self) == len(other) and list(self) == list(other)
        return set(self) == set(other)

def dmenu(inpipe, options=[]):
    dm = Popen(["dmenu"] + options, stdout=PIPE, stdin=PIPE)
    return dm.communicate(input=inpipe.encode('ascii'))[0].decode('ascii').strip()

if __name__ == "__main__":
    if len(sys.argv) == 1:
        search = dmenu("", ["-p", "Search Terms:"])
    else:
        search = " ".join(sys.argv[1:])

    ansi_escape = re.compile(r"\x1b[^m]*m")

    # run baloosearch
    baloo = Popen(['baloosearch', search], stdout=PIPE, stderr=STDOUT)
    findingstr = baloo.communicate()[0].decode("ascii")

    # remove color codes
    findingstr = ansi_escape.sub('', findingstr).strip()

    # extract the file paths from the string
    findings = [" ".join(x.strip().split()[1:]) for x in findingstr.split('\n') if x]

    if findings:
        # Use OrderedSet so that baloo's matches will be at the top of dmenu results.
        paths = OrderedSet(findings)
        for path in findings:
            # Add all files and subdirectories from baloo's matches into set.
            for dirpath, subdirs, files in os.walk(path):
                for i in subdirs:
                    paths.add(os.path.join(dirpath, i))
                for i in files:
                    paths.add(os.path.join(dirpath, i))

        # Pipe results into dmenu, store choice
        file_choice = dmenu("\n".join(paths), ["-l", "3"])

        # Run mimeo on choice (seems to work better than regular xdg-open).
        if file_choice:
            xdg = Popen(['mimeo', file_choice], stdin=None, stdout=None, stderr=None, close_fds=True, preexec_fn=os.setsid)
    else:
        dmenu("", ["-p", "No Results Found."])

Offline

#278 2015-03-21 12:25:28

chickenPie4tea
Member
Registered: 2012-08-21
Posts: 309

Re: Dmenu Hacking Thread

Any help combining 2 dmenu scripts into one?

I have a simple google search dmenu script that I call with a keybinding

#!/bin/bash
DMENU='dmenu -l 12 -x 200 -y 30 -w 600 -nb '#4E4E4E' -nf '#eeeeee' -sb '#5E656B' -fn Inconsolata-12'

GS=`echo | $DMENU $*`
firefox -new-tab http://www.google.co.uk/search?q="$GS"

My main Dmenu script is called with another keybinding but I would like to combine them into one script but I am too stupid to know how.
How would I add the above simple code into the more full featured version below that does the normal Dmenu stuff plus also reads an alias file so I can run alias commands.
I would like to be able to type a comma , then a search term to do the google search part, but if I don't type a comma it behaves like
the regular Dmenu.
My Main Dmenu script is:

#!/bin/bash
cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"}
if [ -d "$cachedir" ]; then
	cache=$cachedir/dmenu_run
else
	cache=$HOME/.dmenu_cache # if no xdg dir, fall back to dotfile in ~
fi

if [ -f ~/.dmenu_alias ]; then
	aliases=( ~/.dmenu_alias )
elif [ -f ~/.zsh_aliases ]; then
	aliases=( ~/.zsh_aliases )
else
	touch ~/.dmenu_alias
fi

if [ ~/.bash_functions ]; then
	functions=( ~/.bash_functions )
elif [ ~/.zsh_functions ]; then
	functions=( ~/.zsh_functions )
else
	touch ~/.bash_functions
fi

source $aliases

cmd=`(
	IFS=:
 if stest -dqr -n "$cache" $PATH || stest -fqr -n "$cache" "$aliases" || stest -fqr -n "$cache" "$functions"; then
          (
            stest -flx $PATH
	    	alias | awk -F '[ =]' '{print $2}'
	    	compgen -A function
          ) | sort -u | tee "$cache" | dmenu -l 14 -x 200 -y 30 -w 650 -nb '#4E4E4E' -nf '#eeeeee' -sb '#55C43B' -fn -misc-fixed-*-*-*-*-20-200-*-*-*-*-*-* "$@"
	else
		dmenu -l 14 -x 200 -y 30 -w 650 -nb '#4E4E4E' -nf '#eeeeee' -sb '#55C43B' -fn -misc-fixed-*-*-*-*-20-200-*-*-*-*-*-* "$@" < "$cache"
	fi
)`

if [ -f ~/.bash_alias ] || [ -f ~/.zsh_aliases ]; then
	if [ ! -z "$(grep '^alias' $aliases|cut -d'=' -f1|grep $cmd)" ] || [ -z $(which $cmd) ]; then
		echo -e "source $aliases \n $cmd" | bash -O expand_aliases &
	else
		exec $cmd &
	fi
fi

You can like linux without becoming a fanatic!

Offline

#279 2015-03-21 14:43:05

parazyd
Member
From: Amsterdam
Registered: 2012-10-14
Posts: 259
Website

Re: Dmenu Hacking Thread

Create a .bashrc alias/function with your command that runs firefox.

Offline

#280 2015-03-21 16:02:58

chickenPie4tea
Member
Registered: 2012-08-21
Posts: 309

Re: Dmenu Hacking Thread

ok will try that as it's probably the simplest, at the moment I am just using dmenu to choose between the google seach dmenu script or the general script as I havent found out how to combine them

choice="
gg '/home/dka/bin/dmenu-gs'
nn '/home/dka/bin/dmenu-aliases-multi'
"
result=$(echo "$choice" | dmenu -fn "-misc-fixed-*-*-*-*-20-200-*-*-*-*-*-*" -nb "#000000" -nf "#e0e0e0" -sb "#000000" -sf "#4abcd4")
cmd=$(echo "$result" | cut -d' ' -f2-)
[ -n "$cmd" ] && eval setsid setsid "$cmd"

Yes the alias idea works fine, I just typ ,gg  in my general dmenu
then I get another box that opens to type in my search term.

Last edited by chickenPie4tea (2015-03-21 16:21:03)


You can like linux without becoming a fanatic!

Offline

#281 2015-03-24 01:27:11

ayekat
Member
Registered: 2011-01-17
Posts: 1,373
Website

Re: Dmenu Hacking Thread

A wrapper for pass, the simple password manager.

#!/usr/bin/env sh

# Default environment variables - see man pass (1):
[ -n "$PASSWORD_STORE_DIR" ] || export PASSWORD_STORE_DIR="$HOME/.password-store"
[ -n "$PASSWORD_STORE_CLIP_TIME" ] || export PASSWORD_STORE_CLIP_TIME=45

cd "$PASSWORD_STORE_DIR"
passname="$(find * -type f | sed 's/\.gpg$//g' | dmenu "$@")"
[ -n "$passname" ] || exit 1
pass show -c "$passname" >/dev/null
notify-send \
	'Unix pass' \
	"$passname\n(will clear in $PASSWORD_STORE_CLIP_TIME seconds)"

EDIT (fix default $PASSWORD_STORE_DIR - it doesn't like the tilde)

Last edited by ayekat (2015-03-24 11:18:34)


{,META,RE}PKGBUILDSpacman-hacks (includes makemetapkg and remakepkg) │ dotfiles

Offline

#282 2015-03-24 11:05:28

parazyd
Member
From: Amsterdam
Registered: 2012-10-14
Posts: 259
Website

Re: Dmenu Hacking Thread

@ayekat That's really great! Pass is really great, never heard of it before smile

Offline

#283 2015-03-24 13:34:13

skanky
Member
From: WAIS
Registered: 2009-10-23
Posts: 1,845

Re: Dmenu Hacking Thread

You might find this script interesting (if only for comparison):

http://git.zx2c4.com/password-store/tree/contrib/dmenu
AUR: https://aur.archlinux.org/packages/passmenu-git/


"...one cannot be angry when one looks at a penguin."  - John Ruskin
"Life in general is a bit shit, and so too is the internet. And that's all there is." - scepticisle

Offline

#284 2015-03-24 13:48:24

ayekat
Member
Registered: 2011-01-17
Posts: 1,373
Website

Re: Dmenu Hacking Thread

Thanks! I didn't know of this. `pacman -Ql pass` doesn't list those files, though. The vim snippet is pretty useful.


{,META,RE}PKGBUILDSpacman-hacks (includes makemetapkg and remakepkg) │ dotfiles

Offline

#285 2015-03-24 14:16:26

skanky
Member
From: WAIS
Registered: 2009-10-23
Posts: 1,845

Re: Dmenu Hacking Thread

ayekat wrote:

Thanks! I didn't know of this. `pacman -Ql pass` doesn't list those files, though. The vim snippet is pretty useful.

Yes, my recollection is you need the aur package.
For more pass related extras, see the third paragraph on the home page: http://www.passwordstore.org/


"...one cannot be angry when one looks at a penguin."  - John Ruskin
"Life in general is a bit shit, and so too is the internet. And that's all there is." - scepticisle

Offline

#286 2015-03-30 17:35:49

ais
Member
Registered: 2015-03-30
Posts: 2

Re: Dmenu Hacking Thread

Simple script to jump to any file/folder:

#!/bin/bash

target=$(locate / | dmenu -i)

if [[ $? -eq 1 ]]; then
    exit 1
fi

st -e ranger --selectfile "$target"

Offline

#287 2015-03-30 23:20:08

Earnestly
Member
Registered: 2011-08-18
Posts: 805

Re: Dmenu Hacking Thread

Offline

#288 2015-03-31 04:30:44

ais
Member
Registered: 2015-03-30
Posts: 2

Re: Dmenu Hacking Thread

Thanks! Much faster now.

Offline

#289 2015-06-11 10:06:56

zappathustra
Member
Registered: 2014-06-15
Posts: 24

Re: Dmenu Hacking Thread

There are already several dmenu-based file managers, but here's
another one anyway... (I had fun writing it, I hope can be useful to
some people). See "fmenu --help" for details.

I invoke it as "fmenu -f -c -d" via a keyboard shortcut.

Maybe I'll try implementing favorites and/or bookmarks someday (yes, I
got somewhat carried away).

#!/bin/bash

# Defaults. {{{
showflags=false
showcurrent=false
replacehome="~"
maxcurrent=35
dmenuopt="-b -i -fn Monospace-12:normal"
file=$(pwd)
# }}}

# Help. {{{
if [[ "$@" =~ "--help" ]]; then
cat << EOF
USAGE:
  fmenu [OPTIONS]... [PATH]
  Launch fmenu in PATH, present working dir otherwise.

  If a non-dir is selected, it is opened with the default application
  if it is a file, otherwise it is executed, so e.g. entering "xterm"
  after navigating to some dir open the terminal in that dir.

  If the value entered begins with "*" followed by one or more letters,
  it is interpreted as a flag selector, turning on/off the following
  options:
    d   Sort directories before files.
    a   Show all files (including dotfiles).
    t   Sort by modification time.
    r   Reverse sort.
    s   Sort by size.
    x   Sort by extension.
  For instance "*sr" sorts by increasing size if those options where unset.

OPTIONS:
  --help     Show this message.
  -f         Show ls flags in the prompt.
  -c         Show current dir in the prompt.
  -h=STRING  Replace \$HOME at the beginning of the current dir in the prompt with STRING.
             Default is "~". If STRING is empty, nothing is done.
  -m=NUM     Max length of the prompt. If it is larger, the head is truncated.
             Default is 35.
  -o=STRING  Passes STRING as options to dmenu; default is "$dmenuopt".
  -d, -a, -t, -r, -s, -x
             Turns on the associated *-flag, see USAGE above.
EOF
exit
fi
# }}}

# Options. {{{
while [[ $# > 0 ]]; do
  case $1 in
    -f) showflags=true ;;
    -c) showcurrent=true ;;
    -h=*) replacehome="${1#*=}" ;;
    -m=*) maxcurrent="${1#*=}" ;;
    -o=*) dmenuopt="${1#*=}" ;;
    -d) dir="--group-directories-first" ;;
    -a) dot="-A" ;;
    -t) mod="-t" ;;
    -r) rev="-r" ;;
    -s) siz="-S" ;;
    -x) ext="-X" ;;
    -*) echo "Unknown option $1." && exit ;;
    *) file="$1"
  esac
  shift
done
# }}}

while [[ -d "$file" ]]; do
  cd "$file"

  # Prompt. {{{
  if $showcurrent; then
    if [[ -z "$replacehome" ]]; then
      ppt=$PWD
    else
      ppt=${PWD/$HOME/$replacehome}
    fi
    [[ ${#ppt} -gt $maxcurrent ]] && ppt="...${ppt: -($maxcurrent-3)}"
  fi

  if $showflags; then
    [[ -z "$dir" ]] && ind="-" || ind="d"
    for var in "$dot" "$mod" "$rev" "$siz" "$ext"; do
      if [[ -z "$var" ]]; then
        ind="$ind-"
      else
        var="${var:1}"
        ind="$ind${var,,}"
      fi
    done
    ind="[$ind] "
  fi
  # }}}

  file=$(ls $dir $dot $ext $mod $rev $siz -p | dmenu $dmenuopt -p "$ind$ppt")
  # Escaped, nothing returned.
  [[ -z "$file" ]] && exit

  # Flags. {{{
  if [[ "$file" =~ "*" ]]; then
    case $file in
      *d*) [[ -z "$dir" ]] && dir="--group-directories-first" || dir="";;&
      *a*) [[ -z "$dot" ]] && dot="-A" || dot="";;&
      *t*) [[ -z "$mod" ]] && mod="-t" || mod="";;&
      *r*) [[ -z "$rev" ]] && rev="-r" || rev="";;&
      *s*) [[ -z "$siz" ]] && siz="-S" || siz="";;&
      *x*) [[ -z "$ext" ]] && ext="-X" || ext="";;&
    esac
    file="."
  fi
  # }}}
 
done

[[ -f "$file" ]] && xdg-open "$file" || exec "$file"

Last edited by zappathustra (2015-06-11 10:11:15)

Offline

#290 2015-06-12 17:33:13

Rasi
Member
From: Germany
Registered: 2007-08-14
Posts: 1,912
Website

Re: Dmenu Hacking Thread

since pass was already mentioned. I also created one. using rofi though, so at least the header menu and the exit codes wont work with standard dmenu.

https://github.com/carnager/rofi-pass


He hoped and prayed that there wasn't an afterlife. Then he realized there was a contradiction involved here and merely hoped that there wasn't an afterlife.

Douglas Adams

Offline

#291 2015-08-09 07:02:17

Rasi
Member
From: Germany
Registered: 2007-08-14
Posts: 1,912
Website

Re: Dmenu Hacking Thread

and another one. a frontend for surfraw.
It can use surfraws elvis as well as custom defined searchengines
https://github.com/carnager/rofi-script … fi-surfraw


He hoped and prayed that there wasn't an afterlife. Then he realized there was a contradiction involved here and merely hoped that there wasn't an afterlife.

Douglas Adams

Offline

#292 2015-08-09 07:17:38

jasonwryan
Anarchist
From: .nz
Registered: 2009-05-09
Posts: 28,474
Website

Re: Dmenu Hacking Thread

Rasi wrote:

and another one. a frontend for surfraw.
It can use surfraws elvis as well as custom defined searchengines
https://github.com/carnager/rofi-script … fi-surfraw

Cool. You can lose some processes by just relying on awk, if you are so inclined...

custom=$(cat $HOME/.config/rofi-surfraw/searchengines | awk -F ' - ' '{ print $1 }')

Could be felineless:

custom=$(awk -F ' - ' '{ print $1 }' $HOME/.config/rofi-surfraw/searchengines)

Also,

list=$(sr -elvi | awk '{ print "?"$1 }' | tail -n +2)

can be awkified:

sr -elvi | awk '{if (NR!=1) print "?"$1 }'

Similarly grep and awk is redundant, just use awk's pattern matching.


Arch + dwm   •   Mercurial repos  •   Surfraw

Registered Linux User #482438

Online

#293 2015-09-01 11:31:23

masque
Member
Registered: 2013-02-24
Posts: 25

Re: Dmenu Hacking Thread

This is for unmounting devices mounted by udevil and devmon
(Just don't label your devices "[ALL]" smile )

With dmenurc I pass dmenu flags only, not the entire dmenu string, so I think you can replace it easily if you use rofi.

Attention: it doesn't work if your labels contains spaces.

#!/usr/bin/env bash

conf="$XDG_CONFIG_HOME/dmenu/dmenurc"
[[ -r $conf ]] && . "$conf"

# where drives are mounted by udevil/devmon
media_mounts="/media/$USER"

drive=$((awk -v mounts="$media_mounts/" '$0 ~ mounts { gsub(mounts,"",$2); print $2 }' /etc/mtab; printf "[ALL]") | dmenu "${dmenuopt[@]}" -p Unmount "$@")
case "$drive" in
    "")
        exit
        ;;
    "[ALL]")
        awk -v mounts="$media_mounts/" '$0 ~ mounts { system("udevil unmount " $2) }' /etc/mtab
        still_mounted=$(awk -v mounts="$media_mounts/" '$0 ~ mounts { gsub(mounts,"",$2); print $2 }' /etc/mtab)
        if [ -z "$still_mounted" ]; then
            notify-send Unmounted "Every shares and removable drives"
        else
            notify-send -u critical Error "There are still mounted devices: $still_mounted"
        fi
        ;;
    *)
        udevil unmount "$media_mounts/$drive"
        if [ $? -eq 0 ]; then
            notify-send Unmounted "$drive"
        elif [ $? -eq 1 ]; then
            notify-send -u critical Error "$drive is busy"
        else
            notify-send -u critical Error "Something's very wrong! ;)"
        fi
esac

Last edited by masque (2015-10-19 13:53:04)

Offline

#294 2015-09-01 12:43:21

mentat
Member
From: France
Registered: 2009-01-13
Posts: 138
Website

Re: Dmenu Hacking Thread

thanks @masque, I like it.
It's work well with rofi.

Warning with labels who contains a space character.
In my mtab the space is encode '\040'

Last edited by mentat (2015-09-01 12:43:53)

Offline

#295 2015-10-03 04:00:38

Chrysostomus
Member
Registered: 2015-09-13
Posts: 64
Website

Re: Dmenu Hacking Thread

Simple application menu that pops up on cursor openbox style. Requires xdotool, xdpyinfo, xdg-open and dmenu patched for height, x, y and preferrably mouse. It also uses as run dialog slightly modified version of dmenu_recent which has been posted earler on this thread. All of my menus source .dmenurc for theming options, and try to copy it from /usr/share/dmenu/dmenurc if it does not exist. Some menuitems also use custom scripts (terminal is wrapper for urxvt), but they can be easily modified and more can be added.

#!/bin/bash
#
# 
#
###
if ! [ -f "$HOME/.dmenurc" ]; then
	cp /usr/share/dmenu/dmenurc $HOME/.dmenurc
fi
. $HOME/.dmenurc

eval $(xdotool getmouselocation --shell)
menu_widht=200
monitor_widht=$(xdpyinfo | awk -F'[ x]+' '/dimensions:/{print $3}')
monitor_height=$(xdpyinfo | awk -F'[ x]+' '/dimensions:/{print $4}')
lines=14
menu_height=$(echo "$lines * 23" | bc)
maxx=$(echo "$monitor_widht - $menu_widht" | bc)
miny=$PANEL_HEIGHT
maxy=$(echo "$monitor_height - $menu_height" | bc)
XP=$X
[[ $XP -gt $maxx ]] && XP=$maxx
YP=$Y
[[ $YP -lt $miny ]] && YP=$miny
[[ $YP -gt $maxy ]] && YP=$maxy

#DMENU='dmenu -i -l 5 -y 30 -x 1720 -w 200 -fn sans11 -nb '#000000' -nf '#99CC99' -sb '#99CC99' -sf '#000000''
#DMENU='dmenu $DMENU_OPTIONS'
choice=$(echo -e "Run\nTerminal\nFiles\nBrowser\nEditor\nPackageManager\nKeybinds" | dmenu -i -l $lines -y $YP -x $XP -w $menu_widht -fn $DMENU_FN -nb $DMENU_NB -nf $DMENU_NF -sf $DMENU_SF -sb $DMENU_SB)

case "$choice" in
  Run) dboxrun & ;;
  Terminal) terminal & ;;
  Files) spacefm & ;;
  Browser) xdg-open https://wiki.archlinux.org/ & ;;
  Editor) $GUI_EDITOR & ;;
  PackageManager) terminal -e yaourt-gui & ;;
  Keybinds) xdg-open .config/sxhkd/sxhkdrc & ;;
esac

dboxrun

#!/bin/sh
if ! [ -f "$HOME/.dmenurc" ]; then
	cp /usr/share/dmenu/dmenurc $HOME/.dmenurc
fi
. $HOME/.dmenurc

eval $(xdotool getmouselocation --shell)
menu_widht=350
monitor_widht=$(xdpyinfo | awk -F'[ x]+' '/dimensions:/{print $3}')
monitor_height=$(xdpyinfo | awk -F'[ x]+' '/dimensions:/{print $4}')
lines=14
menu_height=$(echo "$lines * 23" | bc)
maxx=$(echo "$monitor_widht - $menu_widht" | bc)
miny=$PANEL_HEIGHT
maxy=$(echo "$monitor_height - $menu_height" | bc)
XP=$X
[[ $XP -gt $maxx ]] && XP=$maxx
YP=$Y
[[ $YP -lt $miny ]] && YP=$miny
[[ $YP -gt $maxy ]] && YP=$maxy
dmenu_recent -i -i -l $lines -y $YP -x $XP -w $menu_widht -fn $DMENU_FN -nb $DMENU_NB -nf $DMENU_NF -sf $DMENU_SF -sb $DMENU_SB

Modified dmenu_recent

#!/bin/bash

# Originally based on code by Dieter Plaetinck.
# Pretty much re-written by Mina Nagy (mnzaki)
# Edited by Chrysostomus to create/source .dmenurc

if ! [ -f "$HOME/.dmenurc" ]; then
	cp /usr/share/dmenu/dmenurc $HOME/.dmenurc
fi
. $HOME/.dmenurc

#dmenu_cmd="dmenu $DMENU_OPTIONS"
dmenu_cmd="dmenu $DMENU_OPTIONS"
terminal="urxvt -e"
max_recent=199 # Number of recent commands to track

cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/dmenu-recent"
recent_cache="$cache_dir/recent"
rest_cache="$cache_dir/all"
known_types=" background terminal terminal_hold "

config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/dmenu-recent"
mkdir -p "$cache_dir"
mkdir -p "$config_dir"
touch "$recent_cache"

# Without this, it won't remember $type
GREP_OPTIONS='--color=never'

IFS=:
if stest -dqr -n "$rest_cache" $PATH 2>/dev/null; then
     stest -flx $PATH | sort -u | grep -vf "$recent_cache" > "$rest_cache"
fi

IFS=" "
cmd=$(cat "$recent_cache" "$rest_cache" | $dmenu_cmd -p run: "$@") || exit

if ! grep -qx "$cmd" "$recent_cache" &> /dev/null; then
    grep -vx "$cmd" "$rest_cache" > "$rest_cache.$$"
    mv "$rest_cache.$$" "$rest_cache"
fi

echo "$cmd" > "$recent_cache.$$"
grep -vx "$cmd" "$recent_cache" | head -n "$max_recent" >> "$recent_cache.$$"
mv "$recent_cache.$$"  "$recent_cache"

# Figure out how to run the command based on the command name, disregarding
# arguments, if any.
word0=${cmd%% *}
match="^$word0$"

get_type () {
    while type=$(echo $known_types | xargs -n1 | $dmenu_cmd -p Type:); do
        [[ $known_types =~ " $type " ]] || continue
        echo "$word0" >> "$config_dir/$type"
        break
    done
    echo $type
}

if ! type=$(grep -lx "$match" -R "$config_dir"); then
    type=$(get_type)
else 
    type=${type##*/}
    if ! [[ $known_types =~ " $type " ]]; then
        rm "$config_dir/$type"
        type=$(get_type)
    fi
fi

[[ "$type" = "background" ]] && exec $cmd
[[ "$type" = "terminal" ]] && exec $terminal "$cmd"
[[ "$type" = "terminal_hold" ]] &&
    exec $terminal sh -c "$cmd && echo Press Enter to kill me... && read line"

dmenurc

#!/bin/bash
# ~/.dmenurc

#DMENU_FN="-zevv-peep-medium-*-normal--20-175-*-*-c-*-iso8859-15"
DMENU_FN="-*-terminus-medium-r-normal-*-20-*-*-*-*-*-iso10646-*"
#DMENU_FN="Cantarell-9"
DMENU_NB="#000000"
DMENU_NF="#DDDDDD"
DMENU_SB="#2ECC71"
DMENU_SF="#333333"
DMENU_OPTIONS="-fn $DMENU_FN -nb $DMENU_NB -nf $DMENU_NF -sf $DMENU_SF -sb $DMENU_SB"

export DMENU_FN DMENU_NB DMENU_NF DMENU_SF DMENU_SB DMENU_OPTIONS

Last edited by Chrysostomus (2015-10-03 04:05:48)


The difference between reality and fiction is that fiction has to make sense.

Offline

#296 2015-10-19 13:50:19

masque
Member
Registered: 2013-02-24
Posts: 25

Re: Dmenu Hacking Thread

mentat wrote:

thanks @masque, I like it.
It's work well with rofi.

Warning with labels who contains a space character.
In my mtab the space is encode '\040'

I noticed that... hmm
I ain't expert with awk syntax. Do you know how could I fix it?

Last edited by masque (2015-10-19 13:51:29)

Offline

#297 2015-10-27 00:01:21

Aftix
Member
Registered: 2014-08-12
Posts: 11

Re: Dmenu Hacking Thread

I have made a near fully functional irc client out of dmenu, sh, a window manager and ii (The actual irc handler). It can send messages to servers and channels (+nicks, aka pm's), read recent messages, read persistent messages, dump log files, auto complete nicks at the start of messages to a channel, copy a message's contents to xsel, get notifications of new messages (Doesn't pop up, but a keybind shows you where new messages are), auto-connect to servers, leave channels, and "paste" messages from xsel. The only thing I can think it can't do is leave servers, but I couldn't find ii functionality for that. Here is the actual dmenuirc.sh:

#!/bin/sh

templog=~/.dmenuirc/tempirc
fulllog=~/.dmenuirc/logs
thisloc=~/.i3/dmenuirc.sh

mkdir -p $templog
mkdir -p $fulllog
mkdir -p ~/.dmenuirc

function channelfix {
	server=$(ls ~/irc/ | egrep -v "^in$|^out$|.\.nick$" | dmenu -b -p "Server channel is on:")
	channel=$(ls ~/irc/$server/ | egrep -v "^out$|^in$" | dmenu -b -p "Channel:")
	cat ~/irc/$server/$channel/out > $templog/$server/$channel
}

function notify {
	#List of notifies
	notifies=""
	
	#Go through every server
	while read server; do
		if [ "$(cat ~/irc/$server/out)" != "$(touch $templog/${server}.out; cat $templog/${server}.out)" ]; then
			if [ "$notifies" != "" ]; then
				notifies=$notifies"\n"$server
			else
				notifies=$server
			fi
		fi
		#Go through every connection in the server
		while read conn; do
			if [ "$conn" != "" ]; then
				if [ "$(cat ~/irc/$server/$conn/out)" != \
				   "$(mkdir -p $templog/$server; touch $templog/$server/$conn; cat $templog/$server/$conn)" ]; then
					notifies=$notifies"\n"$server"/"$conn
				fi
			fi
		done <<< "$(ls ~/irc/$server | egrep -v 'in$|out$|.\.nick$|^$')"
	done <<< "$(ls ~/irc/ | egrep -v '^in$|^out$|.\.nick')"
	
	notifies=$(echo -e "$notifies" | grep -v "^$")
	echo -e $notifies | sed "s/ /\n/g" | dmenu -b -p "You have a message in:"
}

function perschan {
	server=$(ls $templog/ | egrep -v ".\.out" | dmenu -b -p "Server channel is on:")
	channel=$(ls $templog/$server/ | grep -v "\!me.out" | dmenu -b -p "What channel to read?")
	recent=$(cat $templog/$server/$channel | tac)
	echo "$recent" | grep -v "^$" | dmenu -b -p "Msgs from $server/$channel" | xsel -i
}

function serverread {
	server=$(ls ~/irc/ | egrep -v "^in$|^out$|.\.nick" | dmenu -b -p "Choose server to read from")
	
	touch $templog/${server}.out
	
	togrep=$(cat $templog/${server}.out)
	if [ "$togrep" != "" ]; then
		out=$(grep -F -v "$togrep" ~/irc/$server/out)
	else
		out=$(cat ~/irc/$server/out)
	fi
	
	out=$(echo -e "$out" | grep -v "^$")
	
	echo -e "$out" | tac | dmenu -b -p 'Recent messages:' | xsel -i
	echo -e "$out" >> $templog/${server}.out
}

function chanmesg {
	server=$(ls ~/irc/ | egrep -v "^in$|^out$|.\.nick" | dmenu -b -p "Server of channel:")
	channel=$(ls ~/irc/$server/ | egrep -v "in$|out$" | dmenu -b -p "Channel:")
	msg=$(xsel -o | dmenu -b -p "Msg to $channel:")
	echo "$msg" >> ~/irc/$server/$channel/in
}

function channelread {
	#Get server and channel for reading
	server=$(ls ~/irc/ | egrep -v "^in$|^out$|.\.nick" | dmenu -b -p "Server channel is on:")
	channel=$(ls ~/irc/$server | egrep -v "in$|out$" | dmenu -b -p "What channel to read?")
	
	#Make sure the persistent exists for grep
	mkdir $templog/$server -p
	touch $templog/$server/$channel
	
	#Add each line of the persistent file to $togrep
	togrep=$(cat $templog/$server/$channel)
	
	if [ "$togrep" != "" ]; then
		#If $togrep has stuff in it, set $out to be every line that does not match $togrep
		out=$(grep -F -v "$togrep" ~/irc/$server/$channel/out)
	else
		#If $togrep is empty, $out is every line
		out=$(cat ~/irc/$server/$channel/out)
	fi
	
	#Remove empty lines
	out=$(echo -e "$out" | grep -v "^$")
	#Set the correct order for dmenu, add to persistent file
	echo -e "$out" | tac | dmenu -b -p "Recent msgs from $server/$channel" | xsel -i
	echo -e "$out"  >> $templog/$server/$channel
}

function nickmsg {
	server=$(ls ~/irc/ | egrep -v "in$|out$|.\.nick" | dmenu -b -p "Server channel is on:")
	channel=$(ls ~/irc/$server/ | egrep -v "^in$|^out$|^$" | dmenu -b -p "Channel user is on: ")
	echo "/names" >> ~/irc/$server/in
	nicks=$(tac ~/irc/$server/out | grep -m 1 "= $channel")
	echo "$nicks"
	nicks=$(echo "$nicks" | sed -re "s/^[0-9]+-[0-9]+-[0-9]+ [0-9]+:[0-9]+ = $channel //g" | sed "s/ /\n/g")
	echo -e "$nicks" | dmenu -b -p "Tab complete a nick and type message:" >> ~/irc/$server/$channel/in
}

function persserv {
	server=$(ls $templog/ | egrep ".\.out|^in$|^out$" | sed "s/\.out//g" | dmenu -b -p "Choose server to read from")
	touch $templog/${server}.out
	recent=$(cat $templog/${server}.out | tac)
	echo "$recent" | grep -v "^$" | dmenu -b -p 'Msgs from $server:' | xsel -i
}

function serverfix {
	server=$(ls ~/irc/ | egrep -v "^in$|^out$|.\.nick" | dmenu -b -p "Server:")
	cat ~/irc/$server/out > $templog/${server}.out
}

function serverlist {
	ls ~/irc/ | egrep -v "^in$|^out$|.\.nick" | dmenu -b -p "Servers connected to:"
}

function channellist {
	ls ~/irc/$(ls ~/irc/ | egrep -v "^in$|^out$|.\.nick" | dmenu -b -p "List channels from:")/ | egrep -v "^in$|^out$" | dmenu -b -p "Channels connected to:"
}

function servermessage {
	server=$(ls ~/irc/ | egrep -v "^in$|^out$|.\.nick" | dmenu -b -p "Server to send to:")
	xsel -o | dmenu -b -p "Sever message:" >> ~/irc/$server/in
}

function connect {
	if [ "$1" == "chan" ]; then
		while true; do
			if [ -w ~/irc/$2/in ]; then
				break
			fi
			sleep 1
		done
		echo "/j $3 $4" >> ~/irc/$2/in
		while true; do
			chan=$(cat ~/irc/$2/out | grep "$3")
			if [ "$chan" != "" ]; then
				break;
			fi
			echo "/j $3 $4" >> ~/irc/$2/in
			sleep 2
		done
	elif [ "$1" == "" ]; then
		server=$(xsel -o | dmenu -b -p "Connect to:")
		port=$(echo "6667" | dmenu -b -p "Port:")
		nick=$(echo "$USER" | dmenu -b -p "Nick:")
	elif [ "$2" == "" ]; then
		server=$1
		port=$(echo "6667" | dmenu -b -p "Port:")
		nick=$(echo "$USER" | dmenu -b -p "Nick:")
	elif [ "$3" == "" ]; then
		server=$1
		port=$2
		nick=$(echo "$USER" | dmenu -b -p "Nick:")
	else
		server=$1
		port=$2
		nick=$3
	fi
	ii -s "$server" -p "$port" -n "$nick" &
	mkdir -p ~/irc/$server
	echo "$nick" > ~/irc/${server}.nick
}

function logdump {
	mkdir -p $fulllog
	cp $templog/* $fulllog -rf
}

function loadautorun {
	while read line; do
		line=$(echo "$line" | grep -v "^#")
		if [ "$line" != "" ]; then
			connect $line
		fi
	done < $1
}

function startup {
	pkill ii >> ~/.dmenuirc/ii.log
	rm -rf $templog/*
	rm -rf ~/irc/*
	loadautorun $1
}

$1 $2 $3 $4 $5 $6 $7 $8 $9

This is the keybindings for i3:

#pkill all ii, clear ~/irc/, start autorun ii's
exec_always "~/.i3/dmenuirc.sh startup ~/.dmenuirc/autoii"

#Mode for irc things
mode "irc" {
	#List servers you're connected to
	bindsym l exec "~/.i3/dmenuirc.sh serverlist"
	#"ls ~/irc/ | dmenu -b -p 'Servers connected to: '"
	#List channels from a specific server
	bindsym c exec "~/.i3/dmenuirc.sh channellist" 
	#"ls ~/irc/$(ls ~/irc/ | dmenu -b -p 'List channels from:')"
	#Send a message to a server
	bindsym s exec "~/.i3/dmenuirc.sh servermessage" 
	#"echo `xsel -o | dmenu -p 'Server message:' -b` >> ~/irc/$(ls ~/irc/ | dmenu -b -p 'Send message to:')/in"
	#Send a message to a channel
	bindsym m exec "~/.i3/dmenuirc.sh chanmesg"
	#Script for advanced reading of recent irc messages from Channel
	bindsym r exec "~/.i3/dmenuirc.sh channelread"
	#Script for advanced reading of recent server messages
	bindsym Shift+R exec "~/.i3/dmenuirc.sh serverread"
	#Connect to a server
	bindsym Shift+c exec "~/.i3/dmenuirc.sh connect" 
	#"ii -s `dmenu -b -p 'Connect to:'`"
	#Read persistent channel messages
	bindsym p exec "~/.i3/dmenuirc.sh perschan"
	#Read persistent server messages
	bindsym Shift+p exec "~/.i3/dmenuirc.sh persserv"
	#dump logs
	bindsym d exec "~/.i3/dmenuirc.sh logdump" 
	#"mkdir -p ~/.i3irclogs; cp ~/.i3/tempirc/* ~/.i3irclogs/ -rf"
	#Get notifications of where the new messages are :D
	bindsym n exec "~/.i3/dmenuirc.sh notify"
	#Linkopener
	bindsym Shift+L exec "~/.i3/linkopen.py"
	#Start a message with the nick of someone in the channel
	bindsym Shift+N exec "~/.i3/dmenuirc.sh nickmsg"
	#Fix that recent messages being empty but there be notifications for channels
	bindsym f exec "~/.i3/dmenuirc.sh channelfix"
	#Server fix
	bindsym Shift+F exec "~/.i3/dmenuirc.sh serverfix"
	
	#Restart dmenuirc
	bindsym q exec "~/.i3/dmenuirc.sh startup ~/.dmenuirc/autoii"
	
	#Exit this madness
	bindsym Escape mode "default"
	bindsym Return mode "default"
}

bindsym $mod+p mode "irc"
}

bindsym $mod+p mode "irc"

Basically kills all old instances, cleans dirs, then launches autorun everytime the wm is reloaded. In the autoii.sh, just run seperate instances of ii for each server like "ii -s irc.freenode.net -n aftix &". In theory you should be able to auto identify with the nickserv or auto join channels in autoii, but ii doesn't instantly create the files required so you'd need a wait command.
The "fix" is for one slight issue - Sometimes, seemingly at random, you're notification for a channel/server will be stuck on but there won't be new messages. Use the fix to fix this and read through the persistent messages to check for any lost ones.

Last edited by Aftix (2015-10-28 00:17:08)

Offline

#298 2015-11-01 14:40:59

Yggdrasil
Member
Registered: 2009-07-21
Posts: 37

Re: Dmenu Hacking Thread

I added experimental gtk support to my "HUD dmenu":
https://github.com/tetzank/qmenu_hud

As i don't use many gtk applications, it would be nice if someone else could give it a try. You need to install the unity-gtk-module for gtk support: https://aur.archlinux.org/packages/unit … alone-bzr/

Offline

#299 2015-11-11 16:16:27

nbd
Member
Registered: 2014-08-04
Posts: 370

Re: Dmenu Hacking Thread

Army wrote:

On the suckless mailing list this problem was solved in a VERY nice way!

This script depends on lsw, which is also a suckless project and available in the AUR.

#!/bin/bash

declare -i active_id
declare -i win_id

winlist=$(xprop -root _NET_CLIENT_LIST|cut -d "#" -f 2|tr "," " ")
count=$(echo $winlist|wc -w)
active_id=$(xprop -root _NET_ACTIVE_WINDOW|awk -F' ' '{ print $NF }')
foo=$(for i in $winlist; do
        win_id="${i}"
        if [ $win_id -eq $active_id ]; then
                focustag="*"
        else
                focustag=" "
        fi
          
        win_class=$(xprop -id ${win_id} WM_CLASS | cut -d'"' -f2)
        win_title=$(xprop -id ${win_id} WM_NAME | cut -d'=' -f2-)
        printf  "%10.10s${focustag}| %60.60s | 0x%7.7x\n" "${win_class}" "${win_title}" "${win_id}"
done |sort| dmenu -i -l $count)


if [ $? -eq 0 ]; then
        xdotool windowactivate $(echo $foo | awk -F'|' '{ print $NF }')
fi

Works for firefox and libreoffice as well. Perfect! (Slowly but surely it's getting hard to find a not already used shortcut for all those fine dmenu tools!)

Cannot figure out where is the dependency on lsw (it seems to run OK without lsw installed).


bing different

Offline

#300 2015-11-13 04:59:47

nbd
Member
Registered: 2014-08-04
Posts: 370

Re: Dmenu Hacking Thread

I have a question to dmenu users. On my machine transitions between menus occur not instantly: on pressing Enter, the new menu appears in about 0.3-0.5 seconds after the old menu disappears, which looks like constant flashing or flickering during menu navigating. Is such delay between menu transitions normal? Could it be reduced somehow?


bing different

Offline

Board footer

Powered by FluxBB