Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I love marks but they could be better #101

Closed
CRAG666 opened this issue Dec 24, 2024 · 1 comment
Closed

I love marks but they could be better #101

CRAG666 opened this issue Dec 24, 2024 · 1 comment

Comments

@CRAG666
Copy link

CRAG666 commented Dec 24, 2024

First of all, what an incredible plugin. I love this plugin, it has really changed my workflow too much.
Today I had enough free time so I started creating a script to manage and improve the brands a little.
The first thing I did was make add behave like vim would, with add add a mark but if it already exists then delete it, something like a togle. The second thing was to add a small dialog box to add a mark, this is just for convenience.

The other thing I added was a kind of which key, to know what brands I have available
Another very useful thing I did was remove marks from an active window if it has a registered trademark.

I leave you the script in case these ideas can be put in the core by default, in the meantime I will use this script

#!/bin/bash

json_file="$HOME/.config/hypr/scripts/marks.json"

if [[ ! -f "$json_file" ]]; then
	echo '{"marks": []}' >"$json_file"
fi

add_mark() {
	active=$(hyprctl activewindow -j)
	if [[ -z "$active" ]]; then
		echo "No active window detected."
		return
	fi

	address=$(echo "$active" | jq -r '.address')

	if jq -e --arg address "$address" '.marks[] | select(.address == $address)' "$json_file" >/dev/null 2>&1; then
		current_mark=$(jq -r --arg address "$address" '.marks[] | select(.address == $address).mark' "$json_file")
		hyprctl dispatch scroller:marksdelete "$current_mark"
		jq --arg address "$address" 'del(.marks[] | select(.address == $address))' "$json_file" >tmp.json && mv tmp.json "$json_file"
		return
	fi

	new_mark=$(yad --entry --title="Marks" --text="Insert Mark" --no-buttons --center)
	if [[ -z "$new_mark" ]]; then
		yad --text="Not valid input." --title="Error" --center --no-buttons --timeout=3
		return
	elif [[ ${#new_mark} -ne 1 ]]; then
		yad --text="Only one character allowed." --title="Error" --center --no-buttons --timeout=3
		return
	fi

	if jq -e --arg mark "$new_mark" '.marks[] | select(.mark == $mark)' "$json_file" >/dev/null 2>&1; then
		jq --arg mark "$new_mark" 'del(.marks[] | select(.mark == $mark))' "$json_file" >tmp.json && mv tmp.json "$json_file"
		hyprctl dispatch scroller:marksdelete "$new_mark"
	fi

	title=$(echo "$active" | jq -r '.initialTitle')

	jq --arg address "$address" --arg mark "$new_mark" --arg title "$title" \
		'.marks += [{"address": $address, "mark": $mark, "title": $title}]' "$json_file" >tmp.json && mv tmp.json "$json_file"
	hyprctl dispatch scroller:marksadd "$new_mark"
}

delete_mark() {
	address=$(hyprctl activewindow -j | jq -r '.address')

	if jq -e --arg address "$address" '.marks[] | select(.address == $address)' "$json_file" >/dev/null 2>&1; then
		mark=$(jq -r --arg address "$address" '.marks[] | select(.address == $address).mark' "$json_file")
		hyprctl dispatch scroller:marksdelete "$mark"
		jq --arg address "$address" 'del(.marks[] | select(.address == $address))' "$json_file" >tmp.json && mv tmp.json "$json_file"
	fi
}

show_marks() {
	data=$(jq -r '.marks[] | [.mark, .title] | @tsv' "$json_file" 2>/dev/null)
	if [[ -z "$data" ]]; then
		wtype -k escape
		return
	fi
	yad_args=()
	while IFS=$'\t' read -r mark title; do
		yad_args+=("$mark" "$title")
	done <<<"$data"
	selected=$(yad --list \
		--title="Marks" \
		--text="Select a mark:" \
		--no-buttons \
		--center \
		--width=500 \
		--height=950 \
		--column="Mark" \
		--column="Title" \
		"${yad_args[@]}")
	if [[ -n "$selected" ]]; then
		mark=$(echo "$selected" | awk -F'|' '{print $1}')
		hyprctl dispatch scroller:marksvisit "$mark"
	fi
	wtype -k escape
}

go_mark() {
	local mark=$1
	killall -9 yad 2>/dev/null
	hyprctl dispatch scroller:marksvisit "$mark"
}

clean_marks() {
	echo '{"marks": []}' >"$json_file"
}

show_help() {
	echo "Usage: $0 -t | -d | -s | -g <mark> | -c"
	echo "  -t        Toggle mark (Add or delete mark)"
	echo "  -d        Delete a mark in current window"
	echo "  -s        Show all marks"
	echo "  -g <mark> Go to a specific mark"
	echo "  -c        Clean all marks"
	exit 1
}

while getopts "tdsg:c" opt; do
	case "$opt" in
	t) add_mark ;;
	d) delete_mark ;;
	s) show_marks ;;
	g)
		if [[ -n $OPTARG ]]; then
			go_mark "$OPTARG"
		else
			echo "Error: -g requires a mark."
			exit 1
		fi
		;;
	c) clean_marks ;;
	*) show_help ;;
	esac
done

if [[ $OPTIND -eq 1 ]]; then
	show_help
fi

hyprconfig

bind = SUPER, m, exec, ~/.config/hypr/scripts/marks -t

bind = SUPER, apostrophe, exec, ~/.config/hypr/scripts/marks -s
bind = SUPER, apostrophe, submap, marksvisit

submap = marksvisit

bind = , a, exec, ~/.config/hypr/scripts/marks -g a
bind = , b, exec, ~/.config/hypr/scripts/marks -g b
bind = , c, exec, ~/.config/hypr/scripts/marks -g c
bind = , d, exec, ~/.config/hypr/scripts/marks -g d
bind = , e, exec, ~/.config/hypr/scripts/marks -g e
bind = , f, exec, ~/.config/hypr/scripts/marks -g f
bind = , g, exec, ~/.config/hypr/scripts/marks -g g
bind = , h, exec, ~/.config/hypr/scripts/marks -g h
bind = , i, exec, ~/.config/hypr/scripts/marks -g i
bind = , j, exec, ~/.config/hypr/scripts/marks -g j
bind = , k, exec, ~/.config/hypr/scripts/marks -g k
bind = , l, exec, ~/.config/hypr/scripts/marks -g l
bind = , m, exec, ~/.config/hypr/scripts/marks -g m
bind = , n, exec, ~/.config/hypr/scripts/marks -g n
bind = , o, exec, ~/.config/hypr/scripts/marks -g o
bind = , p, exec, ~/.config/hypr/scripts/marks -g p
bind = , q, exec, ~/.config/hypr/scripts/marks -g q
bind = , r, exec, ~/.config/hypr/scripts/marks -g r
bind = , s, exec, ~/.config/hypr/scripts/marks -g s
bind = , t, exec, ~/.config/hypr/scripts/marks -g t
bind = , u, exec, ~/.config/hypr/scripts/marks -g u
bind = , v, exec, ~/.config/hypr/scripts/marks -g v
bind = , w, exec, ~/.config/hypr/scripts/marks -g w
bind = , x, exec, ~/.config/hypr/scripts/marks -g x
bind = , y, exec, ~/.config/hypr/scripts/marks -g y
bind = , z, exec, ~/.config/hypr/scripts/marks -g z
bind = , a, submap, reset
bind = , b, submap, reset
bind = , c, submap, reset
bind = , d, submap, reset
bind = , e, submap, reset
bind = , f, submap, reset
bind = , g, submap, reset
bind = , h, submap, reset
bind = , i, submap, reset
bind = , j, submap, reset
bind = , k, submap, reset
bind = , l, submap, reset
bind = , m, submap, reset
bind = , n, submap, reset
bind = , o, submap, reset
bind = , p, submap, reset
bind = , q, submap, reset
bind = , r, submap, reset
bind = , s, submap, reset
bind = , t, submap, reset
bind = , u, submap, reset
bind = , v, submap, reset
bind = , w, submap, reset
bind = , x, submap, reset
bind = , y, submap, reset
bind = , z, submap, reset
bind = , escape, submap, reset

submap = reset

bind = SUPERSHIFT, M, exec, ~/.config/hypr/scripts/marks -c && hyprctl dispatch scroller:marksreset
```
@dawsers
Copy link
Owner

dawsers commented Dec 24, 2024

Wow, thank you, this is very nice. I will link the README to your comment in this issue for now, so people can use your script. Added in a069a2f

I like some of the ideas to add them to the plugin, but there is an issue with dependencies. Hyprland has started including some qtutils library as a soft dependency (hard in Arch, which is what I run). I personally don't like it, because the dependency also includes some KDE stuff, which I would prefer not to need to run Hyprland. But things are like that at the moment. I see you use yad, which is like zenity but probably more advanced, and based on GTK widgets (qtutils uses QtQuick). I would rather not add dependencies out of what Hyprland already includes. So to add any UI, it would have to be using what Hyprland provides, or starting from v0.46, maybe using the forced qtutils dependency. As things are not clear right now, I would rather wait until things mature on that front before adding any kind of UI. Also, UI could be added like you did, with a script, or as a widget to the bar (waybar, ags, ignis, etc.). Maybe it is a bit beyond what a layout plugin should provide.

As for setting marks, I followed vim's way. There is no mark toggle in vim. You add a mark called awith ma. If you add a new mark also called a to another line, the first one will be deleted and the new one will be pointing to the new location, like hyprscroller does. To delete the a mark, you need to call :delmarks a. So basically hyprscroller copies what vim does. I don't know if it is the best way, but I copied that behavior on purpose thinking that is what most people would be used to.

Again, thank you very much for taking the time to write the script and posting it here. It is very useful.

@dawsers dawsers closed this as completed Dec 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants