You are not logged in.

#1 Yesterday 08:32:13

johnraff
nullglob
From: Nagoya, Japan
Registered: 2015-09-09
Posts: 13,177
Website

A jgmenu to labwc menu convertor.

This script I put together - it took a bit longer than expected, and might not be amazingly useful except perhaps for people making a new Wayland system. Aimed not so much at users as developers.

It will take a jgmenu csv menu file and print out openbox-style xml that should work with labwc. Of course some of it will need editing  - like, the "openbox" submenu will need replacing with something for labwc - but people with a long jgmenu menu might enjoy not having to type out all that XML. Just tweak a few places as needed.

A lot of the jgmenu pipemenus in BL are reusing openbox pipemenus, eg this:

Compositor,^pipe(jgmenu_run ob --cmd="bl-compositor" --tag="bl-compositor"),picom

originally came from the xml pipemenu "bl-compositor", and this converter will migrate it back to:

<menu id="bl-compositor" label="Compositor" icon="picom" execute="bl-compositor" />

Anyway, there are short help and debug options, but when you find bugs or improvements, please post!

Just copy/paste from here and either make it executable or call it with bash: 'bash scriptname -c csvfile' -x xmlfile':

#!/bin/bash

#csv2xml

debug() { :; }

HELP="Usage: ${0##*/} [OPTIONS] CSV_FILE

Convert a jgmenu CSV file
(comma‑separated, with optional """...""", ^sep, ^tag, ^checkout, ^pipe)
to a labwc‑compatible xml file.
@ widgets and . includes are ignored.

The converted xml will be printed to STDOUT, or the chosen file.

Options:
    -c, --csvfile <file>  The csv file to read.
    -x, --xmlfile <file>  The xml file to write to.
    -d, --debug     Enable debug output
    -h, --help      Show this help and exit
"

while [[ -n $1 ]]
do
    case "$1" in
        -h|--help)
            echo "$HELP"
            exit 0
            ;;
        -d|--debug)
            debug() {
                echo -e "$*" >&2
            }
            shift
            ;;
        -c|--csvfile)
            csvfile=$2
            shift 2
            ;;
        -x|--xmlfile)
            xmlfile=$2
            shift 2
            ;;
        *)
            echo "${0##*/}: $1: no such option" >&2
            exit 1
            ;;
    esac
done

if [[ -n $xmlfile ]]
then
    exec >"$xmlfile"
else
    debug 'No xml file specified, printing to STDOUT'
fi

parse_jgmenu_line() {
    local line="$1"
    local pos=0 field="" in_quotes=false

    while (( pos < ${#line} )); do
        # Check for triple-quote toggle
        if [[ "${line:$pos:3}" == '"""' ]]; then
            [[ $in_quotes = false ]] && in_quotes=true || in_quotes=false
            pos=$((pos+3))
            continue
        fi

        # Comma is a field separator only outside quotes
        if [[ "${line:$pos:1}" == ',' ]] && [[ $in_quotes = false ]]; then
            fields+=("$field")
            field=""
            pos=$((pos+1))
            continue
        fi

        # Regular character — add to current field
        field+="${line:$pos:1}"
        pos=$((pos+1))
    done

    fields+=("$field")  # Don't forget the last field

    for i in "${!fields[@]}"
    do
        fields[i]=$(strip_spaces "${fields[i]}")
    done
    # three special characters will have been pango escaped in Description (fields[0])
    fields[0]=$(pango_unescape "${fields[0]}")
}

strip_spaces(){
    local string
    string=$1
    read -r string <<<"$string"
    printf '%s' "$string"
}

pango_unescape(){
    local string
    string="${1//&amp;/\&}"
    string="${string//&lt;/<}"
    string="${string//&gt;/>}"
    printf '%s' "$string"
}

####### functions to generate labwc menu ###########################

# Each helper emits embedded newlines; caller appends with $'\n'.

OBmenuStart() {
    printf '%s' '<openbox_menu>'
}

OBmenuEnd() {
    printf '%s' '</openbox_menu>'
}

rootmenuStart() {
    printf '%s' '    <menu id="root-menu">'
}

# end any toplevel menu except the <openbox_menu>
rootmenuEnd() {
    printf '%s' '    </menu>'
}

# args: label command icon (same order as csv fields)
menuItem() {
    printf '        <item label="%s" icon="%s" >\n            <action name="Execute" command="%s" />\n        </item>' \
        "$(OBlabelEscape "$1")" "$(XMLescape "$3")" "$(XMLescape "$2")"
}

menuSeparator() {
    if [[ ${1-} ]]; then
        printf '        <separator label="%s" />' "$(OBlabelEscape "$1")"
    else
        printf '        <separator />'
    fi
}

menuSubmenuStart() {
    printf '\n    <menu id="%s" label="%s" icon="%s" >\n' \
        "$(XMLescape "$1")" "$(OBlabelEscape "$2")" "$(XMLescape "$3")"
}

menuSubmenuEnd() {
    printf '    </menu>'
}

menuSubmenuExternal() {
    printf '        <menu id="%s" />' "$(XMLescape "$1")"
}

pipemenu() {
    printf '        <menu id="%s" label="%s" icon="%s" execute="%s" />' \
        "$(XMLescape "$1")" "$(OBlabelEscape "$2")" "$(XMLescape "$3")" "$(XMLescape "$4")"
}

# escape special characters
XMLescape() {
    local string="${1//&/\&amp;}"
    string="${string//</\&lt;}"
    string="${string//>/\&gt;}"
    string="${string//\"/\&quot;}"
    string="${string//\'/\&apos;}"
    printf '%s' "$string"
}
OBlabelEscape() {
    local string
    string="$(XMLescape "$1")"
    printf '%s' "${string//_/__}"
}

########################################################################


generate_xml() {
    declare -A menus
    declare -A submenulabels
    declare -A submenuicons
    menus[root]=''
    menu=root
    debug "currently adding items to menu: $menu"
    while read -r line; do
        case "$line" in
            '')
                [[ $menu != root ]] && debug "end of submenu $menu"
                menu=root
                debug "currently adding items to menu: $menu"
                continue
                ;;
            '#'*)
                continue
                ;;
            '.'*)
                debug "ignoring sourced file: $line"
                continue
                ;;
            '@'*)
                debug "ignoring widget: $line"
                continue
                ;;
        esac
        fields=()
        parse_jgmenu_line "$line"
        case "${fields[0]}" in
        ^sep\(*\))
            title=${fields[0]#*\(}
            title=${title%\)*}
            menus["$menu"]+=$(menuSeparator "${title}")$'\n'
            ;;
        ^tag\(*\))
            id=${fields[0]#*\(}
            id=${id%\)*}
            menu=${id}
            debug "currently adding items to menu: $menu"
            continue
            ;;
        *)
            case "${fields[1]}" in
            ^back\(\))
                continue
                ;;
            ^checkout\(*\))
                id=${fields[1]#*\(}
                id=${id%\)*}
                menus["$menu"]+=$(menuSubmenuExternal "$id")$'\n'
                submenulabels["$id"]="${fields[0]}"
                submenuicons["$id"]="${fields[2]}"
                continue
                ;;
            ^pipe\(*\)) # pipemenu command needs rewriting if it's an openbox pipemenu, otherwise (csv) leave empty
                cmd=${fields[1]#*\(}
                cmd=${cmd%\)*}
                id=${cmd#*--tag=\"}
                id=${id%\"*}
                if [[ $cmd = 'jgmenu_run ob'* ]]
                then # openbox xml pipemenu
                    cmd="${cmd#*--cmd=\"}"
                    cmd="${cmd%%\"*}"
                else
                    debug "Not an xml pipemenu: $cmd"
                    cmd="<!-- $cmd -->"
                fi
                label=${fields[0]}
                icon=${fields[2]}
                menus["$menu"]+=$(pipemenu "$id" "$label" "$icon" "$cmd")$'\n'
                continue
            esac

            menus["$menu"]+=$(menuItem "${fields[@]}")$'\n'
            ;;
        esac
    done < "$csvfile"
    rootmenu="${menus[root]}"
    unset 'menus[root]'
    OBmenuStart
    echo
    printf '%s\n' '<!-- defining submenus -->'
    for i in "${!menus[@]}"
    do
        menuSubmenuStart "$i" "${submenulabels[$i]}" "${submenuicons[$i]}"
        printf '%s' "${menus[$i]}"
        menuSubmenuEnd
        echo
    done
    printf '\n%s\n\n' '<!-- root menu starts here -->'
    rootmenuStart
    echo
    printf '%s' "$rootmenu"
    rootmenuEnd
    echo
    OBmenuEnd
    echo
}

generate_xml

Last edited by johnraff (Today 06:30:53)


...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky, there's also some GitStuff )

Introduction to the Bunsenlabs Boron Desktop

Offline

Board footer

Powered by FluxBB