Initial Push.
This commit is contained in:
1
home/.local/usr/bin/ShadowPCBeta.AppImage
Symbolic link
1
home/.local/usr/bin/ShadowPCBeta.AppImage
Symbolic link
@@ -0,0 +1 @@
|
||||
/home/th3r00t/Downloads/ShadowPCBeta.AppImage
|
||||
67
home/.local/usr/bin/addpass
Executable file
67
home/.local/usr/bin/addpass
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
source $HOME/.config/rofi-pass/config
|
||||
|
||||
if [[ -n "$3" && "$2" == "--root" ]]; then
|
||||
root="${2}"
|
||||
elif [[ -n $root ]]; then
|
||||
root=$root
|
||||
elif [[ -n $PASSWORD_STORE_DIR ]]; then
|
||||
root=$PASSWORD_STORE_DIR
|
||||
else
|
||||
root="$HOME/.password-store"
|
||||
fi
|
||||
|
||||
if [[ $1 == "--help" || $1 == "-h" ]]; then
|
||||
echo "add pass files for rofi-pass"
|
||||
echo "(C) 2015 Rasmus Steinke <rasi at xssn dot at>"
|
||||
echo ""
|
||||
echo "--name \"foobar\" Mandatory first argument - filename of password file"
|
||||
echo "--root \"foobar\" Optional second argument - Absolute path to password store"
|
||||
echo ""
|
||||
echo "+FIELD \"barbaz\" Every field name has to start with \"+\""
|
||||
echo " Values should be quoted"
|
||||
echo ""
|
||||
echo "Example:"
|
||||
echo "addpass --name \"my password file\" --root \"$HOME/passwords\" +user \"Richard\" +foo \"bar\" +autotype \"foo :tab user :tab pass\""
|
||||
exit
|
||||
else
|
||||
echo "$1"
|
||||
if [[ $1 != "--name" ]]; then
|
||||
echo "Missing --name option. Try --help"
|
||||
exit
|
||||
elif [[ $1 == "--name" ]]; then
|
||||
Name="$2"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Using database \"$root\""
|
||||
|
||||
OIFS=$IFS;
|
||||
IFS="+";
|
||||
|
||||
fields="$@";
|
||||
fieldsArray=($fields);
|
||||
read -p "Enter password for entry \"${Name}\" > " -s pass
|
||||
|
||||
cd "${root}"
|
||||
group=$(echo -e "No Group\n---\n$(find -type d -not -iwholename '*.git*' -printf '%d\t%P\n' | sort -r -nk1 | cut -f2-)" | rofi -dmenu -p "Choose Group > ")
|
||||
|
||||
echo -e "\n\nStoring file ${Name} in group ${group}"
|
||||
|
||||
printEntry () {
|
||||
echo -e "$pass\n---"
|
||||
for ((i=1; i<${#fieldsArray[@]}; ++i)); do
|
||||
field=$(echo "${fieldsArray[$i]}" | awk -F' ' '{print $1}')
|
||||
option=$(echo "${fieldsArray[$i]}" | cut -d ' ' -f 2- | sed -e 's/[[:blank:]]\+$//')
|
||||
echo "$field: $option" | grep -Ev 'name:|--root|root:|^:' #${fieldsArray[$i]}";
|
||||
done
|
||||
}
|
||||
|
||||
if [[ "$group" == "No Group" ]]; then
|
||||
printEntry | PASSWORD_STORE_DIR="${root}" pass insert -m "${Name}"
|
||||
elif [[ "$group" == "" ]]; then
|
||||
exit
|
||||
else
|
||||
printEntry | PASSWORD_STORE_DIR="${root}" pass insert -m "${group}/${Name}"
|
||||
fi
|
||||
7
home/.local/usr/bin/baraction.sh
Executable file
7
home/.local/usr/bin/baraction.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
SLEEP_SEC=5
|
||||
COUNT=0
|
||||
while :; do
|
||||
let COUNT=$COUNT+1
|
||||
echo -e " HELLO $COUNT"
|
||||
sleep $SLEEP_SEC
|
||||
done
|
||||
1
home/.local/usr/bin/blightmud
Symbolic link
1
home/.local/usr/bin/blightmud
Symbolic link
@@ -0,0 +1 @@
|
||||
/home/th3r00t/.local/build/Blightmud/target/release/blightmud
|
||||
2
home/.local/usr/bin/butlerianjihad.sh
Executable file
2
home/.local/usr/bin/butlerianjihad.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env sh
|
||||
mpv /mnt/audiobooks/Dune\ -\ Audiobook\ Collection\ 2015/03\ -\ Legends\ of\ Dune/01.\ The\ Butlerian\ Jihad.m4b
|
||||
56
home/.local/usr/bin/capture-note.sh
Executable file
56
home/.local/usr/bin/capture-note.sh
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set directory path for Vimwiki files
|
||||
WIKI_DIR="$HOME/org/wiki" # Replace with the path to your Vimwiki directory
|
||||
# Get the list of existing note titles, replacing underscores with spaces for display
|
||||
EXISTING_TITLES=$(find "$WIKI_DIR/notes" -type f -name "*.wiki" -exec basename {} .wiki \; | tr '_' ' ')
|
||||
# Use fzf to let the user select an existing title or type a new one
|
||||
TITLE=$( (echo "$EXISTING_TITLES" && echo "[New Note]") | fzf --prompt="Select or enter title: " --print-query)
|
||||
|
||||
# Check if the user chose an existing title or opted for a new note
|
||||
if [[ "$TITLE" = "[New Note]" || -z "$TITLE" ]]; then
|
||||
# Prompt for a new title if "New Note" was selected
|
||||
TITLE=$(echo "" | fzf --prompt="Enter title for new entry: ")
|
||||
fi
|
||||
|
||||
# Exit if no title was entered
|
||||
if [[ -z "$TITLE" ]]; then
|
||||
echo "No title entered. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Format the filename by replacing spaces with underscores and lowercasing
|
||||
FILENAME_TIMESTAMP=$(date +"%Y%m%d%H%M")
|
||||
FILENAME="${FILENAME_TIMESTAMP}-$(echo "$TITLE" | tr ' ' '_' | tr '[:upper:]' '[:lower:]').wiki"
|
||||
NEW_FILE="$WIKI_DIR/notes/$FILENAME"
|
||||
|
||||
# Check if a file with this title already exists
|
||||
EXISTING_FILE=$(find "$WIKI_DIR/notes" -type f -name "$(echo "$TITLE" | tr ' ' '_' | tr '[:upper:]' '[:lower:]').wiki")
|
||||
|
||||
if [[ -n "$EXISTING_FILE" ]]; then
|
||||
# Open the existing file in Neovim if found
|
||||
nvim "$EXISTING_FILE"
|
||||
else
|
||||
# Create a new file with the specified template if it does not exist
|
||||
TIMESTAMP=$(date +"%Y-%m-%d %H:%M")
|
||||
|
||||
echo "= $TITLE =
|
||||
*Created:* $TIMESTAMP
|
||||
|
||||
== Summary ==
|
||||
|
||||
== Tasks ==
|
||||
|
||||
== Notes ==
|
||||
|
||||
== Resources ==
|
||||
* [[wiki link]] for additional content
|
||||
* [[other wiki link|Desc]]
|
||||
" > "$NEW_FILE"
|
||||
|
||||
# Add a link to the new file at the bottom of index.wiki
|
||||
echo "- [[$FILENAME|$TITLE]]" >> "$WIKI_DIR/index.wiki"
|
||||
|
||||
# Open the new file in Neovim
|
||||
nvim "$NEW_FILE"
|
||||
fi
|
||||
14
home/.local/usr/bin/chatgpt.js
Executable file
14
home/.local/usr/bin/chatgpt.js
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { ChatGPTAPIBrowser } from 'chatgpt'
|
||||
|
||||
async function example() {
|
||||
const api = new ChatGPTAPIBrowser({
|
||||
email: process.env.OPENAI_EMAIL,
|
||||
password: process.env.OPENAI_PASSWORD
|
||||
})
|
||||
|
||||
await api.initSession()
|
||||
const result = await api.sendMessage("Hello World")
|
||||
console.log(result.rseponse)
|
||||
}
|
||||
24
home/.local/usr/bin/dotfile-picker.sh
Executable file
24
home/.local/usr/bin/dotfile-picker.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Set the directory where your dotfiles are located
|
||||
DOTFILES_DIR="${HOME}/.dotfiles"
|
||||
|
||||
# Use fzf to select a file
|
||||
file=$(find "$DOTFILES_DIR" -type f -name "*.*" | \
|
||||
fzf --delimiter / --with-nth=-1 --keep-right \
|
||||
--prompt="Dotfiles " \
|
||||
--tmux left,40 --reverse \
|
||||
)
|
||||
|
||||
# Check if a directory was selected
|
||||
if [[ -n "$file" ]]; then
|
||||
projectname="${file##*/}"
|
||||
escprojectname = $(printf '%q' "$projectname")
|
||||
# Check if a tmux window with the project name already exists
|
||||
if tmux list-windows -F "#{window_name}" | grep -q "^$escprojectname$"; then
|
||||
tmux select-window -t "$projectname"
|
||||
else
|
||||
# Create a new tmux window with the project name and open nvim in the folder
|
||||
tmux new-window -n "$projectname" "nvim '$file'"
|
||||
fi
|
||||
fi
|
||||
2
home/.local/usr/bin/dropdown
Executable file
2
home/.local/usr/bin/dropdown
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
urxvt -name dropdown -e tmux attach Dropdown &
|
||||
898
home/.local/usr/bin/emojicherrypick.py
Executable file
898
home/.local/usr/bin/emojicherrypick.py
Executable file
@@ -0,0 +1,898 @@
|
||||
#!/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
import argparse
|
||||
import json
|
||||
import urllib.request
|
||||
import subprocess
|
||||
import random
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Tuple
|
||||
from typing import TypeAlias
|
||||
|
||||
CompletedProcess: TypeAlias = subprocess.CompletedProcess
|
||||
|
||||
|
||||
class App:
|
||||
""" Contains all settings and meta information for the application. """
|
||||
|
||||
name: str = 'emojicherrypick'
|
||||
version: str = '0.2'
|
||||
|
||||
def __init__(self, args: argparse.Namespace) -> None:
|
||||
""" Construct application attributes used as settings. """
|
||||
|
||||
self.list_version: bool = args.version
|
||||
self.frozen: bool = bool(getattr(sys, 'frozen', False)
|
||||
and hasattr(sys, '_MEIPASS'))
|
||||
self.wipe_cache: bool = args.wipe_cache
|
||||
self.offline: bool = args.offline
|
||||
self.menu: str = args.menu
|
||||
self.url: str = args.url
|
||||
self.cache_dir: Path = fullpath(args.cache_dir)
|
||||
self.db_source: Path = Path(self.cache_dir / 'emojis.json')
|
||||
self.noemojis: bool = args.noemojis
|
||||
self.db_filtered: Path | None = None
|
||||
if not self.noemojis:
|
||||
self.db_filtered = self.db_source.with_suffix('.cherry')
|
||||
self.nofavorites: bool = args.nofavorites
|
||||
self.db_favorites: Path | None = None
|
||||
if not self.nofavorites:
|
||||
self.db_favorites = fullpath(args.favorites)
|
||||
self.recents_size: int = args.recents_size
|
||||
self.norecents: bool = args.norecents
|
||||
self.db_recents: Path | None = None
|
||||
if not self.norecents:
|
||||
self.db_recents = fullpath(args.recents)
|
||||
self.font_family: str = args.font_family
|
||||
self.font_size: int = args.font_size
|
||||
self.list_size: int = args.list_size
|
||||
self.selected_emoji: str | None = None
|
||||
self.selected_desc: str | None = None
|
||||
self.stdout: bool = args.stdout and not args.nostdout
|
||||
self.clipboard: bool = args.clipboard and not args.noclipboard
|
||||
self.notify: bool = args.notify and not args.nonotify
|
||||
self.typing: bool = args.typing and not args.notyping
|
||||
self.ignore_case: bool = args.ignore_case and not args.noignore_case
|
||||
self.ignore_skin: bool = args.ignore_skin
|
||||
self.matching_rofi: str = args.matching_rofi
|
||||
self.pattern: str = args.pattern
|
||||
self.prompt: str = args.prompt
|
||||
self.list_programs: bool = args.list_programs
|
||||
self.programs: dict[str, Path] = {
|
||||
'Python': Path(sys.executable),
|
||||
'rofi': App.which(args.rofi),
|
||||
'dmenu': App.which(args.dmenu),
|
||||
'pmenu': App.which(args.pmenu),
|
||||
'fzf': App.which(args.fzf),
|
||||
'xclip': App.which(args.xclip),
|
||||
'xdotool': App.which(args.xdotool),
|
||||
'notify-send': App.which(args.notifysend),
|
||||
}
|
||||
|
||||
if self.wipe_cache:
|
||||
self.wipe_cache_files()
|
||||
if not self.offline or not self.noemojis:
|
||||
self.download_db_source()
|
||||
self.filter_db_source()
|
||||
|
||||
def load_emoji_list(self, aslist=False) -> str | list:
|
||||
""" Read all emojis, recents and favorites into a single string. """
|
||||
|
||||
emoji_list: str = ''
|
||||
filtered_list: str = ''
|
||||
recents_list: str = ''
|
||||
favorites_list: str = ''
|
||||
if (not self.norecents
|
||||
and self.db_recents
|
||||
and self.db_recents.exists()):
|
||||
recents_list = self.db_recents.read_text().strip('\n')
|
||||
recents_top: list = recents_list.splitlines()
|
||||
recents_top.reverse()
|
||||
recents_top = list(dict.fromkeys(recents_top))
|
||||
recents_top = recents_top[0:self.recents_size]
|
||||
recents_list = '\n'.join(recents_top)
|
||||
if (not self.nofavorites
|
||||
and self.db_favorites
|
||||
and self.db_favorites.exists()):
|
||||
favorites_list = self.db_favorites.read_text().strip('\n')
|
||||
if (not self.noemojis
|
||||
and self.db_filtered
|
||||
and self.db_filtered.exists()):
|
||||
filtered_list = self.db_filtered.read_text().strip('\n')
|
||||
if recents_list:
|
||||
emoji_list += '\n' + recents_list
|
||||
if favorites_list:
|
||||
emoji_list += '\n' + favorites_list
|
||||
if filtered_list:
|
||||
emoji_list += '\n' + filtered_list
|
||||
elist: list[str] = list(dict.fromkeys(emoji_list.splitlines()))
|
||||
if aslist:
|
||||
return elist
|
||||
else:
|
||||
emoji_list = '\n'.join(elist)
|
||||
return emoji_list.lstrip('\n')
|
||||
|
||||
def wipe_cache_files(self) -> None:
|
||||
""" Clean cache by deleting all known files in it. """
|
||||
|
||||
if self.db_source:
|
||||
self.db_source.unlink(missing_ok=True)
|
||||
if self.db_filtered:
|
||||
self.db_filtered.unlink(missing_ok=True)
|
||||
if self.db_recents:
|
||||
self.db_recents.unlink(missing_ok=True)
|
||||
return None
|
||||
|
||||
def download_db_source(self, force=False):
|
||||
""" Download emojis.json database source from URL to cache. """
|
||||
|
||||
if force:
|
||||
self.db_source.unlink(missing_ok=True)
|
||||
if not self.db_source.exists():
|
||||
self.cache_dir.mkdir(exist_ok=True)
|
||||
self.db_filtered.unlink(missing_ok=True)
|
||||
response = urllib.request.urlopen(self.url)
|
||||
data = response.read()
|
||||
text = data.decode('utf-8')
|
||||
self.db_source.write_text(text)
|
||||
|
||||
def filter_db_source(self, force=False):
|
||||
""" Convert, filter and sort cached database to a small text file. """
|
||||
|
||||
def sorted_by_order(elem):
|
||||
""" Used to determined sort key by 'order' for sorted(). """
|
||||
|
||||
return elem['order']
|
||||
|
||||
if force:
|
||||
self.db_filtered.unlink(missing_ok=True)
|
||||
if self.db_filtered and not self.db_filtered.exists():
|
||||
source = json.loads(self.db_source.read_text())
|
||||
filtered: str = ''
|
||||
emojis_face: str = ''
|
||||
emojis_finger: str = ''
|
||||
emojis_other: str = ''
|
||||
for emoji in sorted(source['emojis'], key=sorted_by_order):
|
||||
|
||||
# Exclude emojis that have "skin" in their names, as they are
|
||||
# mostly color variations of the main emoji.
|
||||
not_ignored_by_skin = 'skin' not in emoji['name'] \
|
||||
and 'skin_tone' not in emoji['shortname'] if self.ignore_skin \
|
||||
else True
|
||||
if (not_ignored_by_skin and emoji['name']):
|
||||
|
||||
# Format:
|
||||
# ☺️ smiling face Smileys & Emotion (face-affection)
|
||||
str_emoji: str = (emoji['emoji'].strip()
|
||||
+ ' '
|
||||
+ emoji['name'].strip()
|
||||
+ ' ~ '
|
||||
+ emoji['category'].strip())
|
||||
|
||||
# Create multiple lists with emojis, so later it can be put
|
||||
# together for sorted groups.
|
||||
if ('face' in emoji['name']
|
||||
or 'face' in emoji['category']):
|
||||
emojis_face += str_emoji + '\n'
|
||||
elif 'finger' in emoji['category']:
|
||||
emojis_finger += str_emoji + '\n'
|
||||
else:
|
||||
emojis_other += str_emoji + '\n'
|
||||
|
||||
filtered = emojis_face + emojis_finger + emojis_other
|
||||
self.db_filtered.write_text(filtered.strip('\n'))
|
||||
|
||||
def update_selected_emoji(self, emoji: list | None) -> str | None:
|
||||
""" Update last selected emoji and return by stripping newlines. """
|
||||
|
||||
if emoji is None:
|
||||
self.selected_emoji = None
|
||||
self.selected_desc = None
|
||||
else:
|
||||
try:
|
||||
emoji = [emoji[0].strip('\n'), emoji[1].strip('\n')]
|
||||
self.selected_emoji = emoji[0]
|
||||
self.selected_desc = emoji[1]
|
||||
self.append_recents()
|
||||
except (ValueError, AttributeError, IndexError):
|
||||
self.selected_emoji = None
|
||||
self.selected_desc = None
|
||||
return self.selected_emoji
|
||||
|
||||
def select_by_none(self):
|
||||
""" Selects nothing and resets last selected emoji. """
|
||||
|
||||
return self.update_selected_emoji(None)
|
||||
|
||||
def select_by_random(self):
|
||||
""" Selects an emoji by random chance. """
|
||||
|
||||
random_set: set = set(self.load_emoji_list(aslist=True))
|
||||
random_set.discard('')
|
||||
random_list: list = list(random_set)
|
||||
random.shuffle(random_list)
|
||||
emoji = random_list[0].split(' ', 1)
|
||||
return self.update_selected_emoji(emoji)
|
||||
|
||||
def select_by_filter(self) -> str | None:
|
||||
""" Select an emoji without a menu but first match on a filter. """
|
||||
|
||||
emoji_list: str | list = self.load_emoji_list(aslist=True)
|
||||
if self.ignore_case:
|
||||
emoji_list = list(filter(
|
||||
lambda line: self.pattern.lower() in line.lower(),
|
||||
emoji_list
|
||||
))
|
||||
else:
|
||||
emoji_list = list(filter(
|
||||
lambda line: self.pattern in line,
|
||||
emoji_list
|
||||
))
|
||||
try:
|
||||
emoji = emoji_list[0].split(' ', 1)
|
||||
except (ValueError, AttributeError, IndexError):
|
||||
emoji = None
|
||||
return self.update_selected_emoji(emoji)
|
||||
|
||||
def select_by_dmenu(self):
|
||||
""" Select an emoji with dmenu and get emoji and desc tuple. """
|
||||
|
||||
command: list[str] = []
|
||||
command.append(self.programs['dmenu'].as_posix())
|
||||
command.append('-p')
|
||||
command.append(self.prompt)
|
||||
command.append('-l')
|
||||
command.append(str(self.list_size))
|
||||
command.append('-fn')
|
||||
command.append(f'"{self.font_family}-{str(self.font_size)}"')
|
||||
emoji_list = self.load_emoji_list()
|
||||
if self.ignore_case:
|
||||
emoji_list = emoji_list.lower()
|
||||
emoji = App.select_command_emoji(command, emoji_list)
|
||||
return self.update_selected_emoji(emoji)
|
||||
|
||||
def select_by_rofi(self):
|
||||
""" Select an emoji with rofi and get emoji and desc tuple. """
|
||||
|
||||
command: list[str] = []
|
||||
command.append(self.programs['rofi'].as_posix())
|
||||
command.append('-dmenu')
|
||||
command.append('-steal-focus')
|
||||
command.append('-p')
|
||||
command.append(self.prompt)
|
||||
command.append('-title')
|
||||
command.append(self.name)
|
||||
command.append('-l')
|
||||
command.append(str(self.list_size))
|
||||
command.append('-font')
|
||||
command.append(f'"{self.font_family} {str(self.font_size)}"')
|
||||
command.append('-no-custom')
|
||||
command.append('-matching')
|
||||
command.append(self.matching_rofi)
|
||||
if self.ignore_case:
|
||||
command.append('-i')
|
||||
command.append('-nocase-sensitive')
|
||||
emoji_list = self.load_emoji_list()
|
||||
emoji = App.select_command_emoji(command, emoji_list)
|
||||
return self.update_selected_emoji(emoji)
|
||||
|
||||
def select_by_pmenu(self):
|
||||
""" Select an emoji with pmenu and get emoji and desc tuple. """
|
||||
|
||||
command: list[str] = []
|
||||
command.append(self.programs['pmenu'].as_posix())
|
||||
command.append('-p')
|
||||
command.append(self.prompt)
|
||||
emoji_list = self.load_emoji_list()
|
||||
if self.ignore_case:
|
||||
emoji_list = emoji_list.lower()
|
||||
emoji = App.select_command_emoji(command, emoji_list)
|
||||
return self.update_selected_emoji(emoji)
|
||||
|
||||
def select_by_fzf(self):
|
||||
""" Select an emoji with fzf and get emoji and desc tuple. """
|
||||
|
||||
command: list[str] = []
|
||||
command.append(self.programs['fzf'].as_posix())
|
||||
command.append('--layout')
|
||||
command.append('reverse')
|
||||
command.append('--prompt')
|
||||
command.append(self.prompt)
|
||||
if self.pattern:
|
||||
command.append('--filter')
|
||||
command.append(self.pattern)
|
||||
if self.ignore_case:
|
||||
command.append('-i')
|
||||
emoji_list = self.load_emoji_list()
|
||||
emoji = App.select_command_emoji(command, emoji_list)
|
||||
return self.update_selected_emoji(emoji)
|
||||
|
||||
@classmethod
|
||||
def select_command_emoji(
|
||||
cls,
|
||||
command,
|
||||
emoji_list) -> Tuple[str, str] | Tuple[None, None]:
|
||||
""" Return selected emoji and desc from list using custom command. """
|
||||
|
||||
output_p: CompletedProcess | None = None
|
||||
try:
|
||||
output_p = subprocess.run(command,
|
||||
input=emoji_list,
|
||||
stdout=subprocess.PIPE,
|
||||
text=True)
|
||||
except FileNotFoundError:
|
||||
raise subprocess.SubprocessError
|
||||
if output_p and output_p.stdout:
|
||||
try:
|
||||
emoji, desc = output_p.stdout.split(' ', 1)
|
||||
return emoji.strip(' \n'), desc.strip(' \n')
|
||||
except ValueError:
|
||||
return None, None
|
||||
else:
|
||||
return None, None
|
||||
|
||||
def send_emoji_to_stdout(self, newline=True) -> None:
|
||||
""" Print out emoji to stdout. """
|
||||
|
||||
if newline:
|
||||
print(self.selected_emoji)
|
||||
else:
|
||||
print(self.selected_emoji, end='')
|
||||
|
||||
def send_emoji_to_clipboard(self) -> subprocess.Popen | None:
|
||||
""" Copy emoji to systems clipboard. """
|
||||
|
||||
command: list[str] = []
|
||||
command.append(self.programs['xclip'].as_posix())
|
||||
command.append('-rmlastnl')
|
||||
command.append('-selection')
|
||||
command.append('clipboard')
|
||||
xclip_p: subprocess.Popen | None = None
|
||||
xclip_p = subprocess.Popen(command,
|
||||
stdin=subprocess.PIPE,
|
||||
text=True)
|
||||
if xclip_p:
|
||||
try:
|
||||
xclip_p.communicate(input=(self.selected_emoji), timeout=2)
|
||||
if xclip_p.returncode:
|
||||
raise subprocess.SubprocessError
|
||||
except subprocess.TimeoutExpired:
|
||||
xclip_p.kill()
|
||||
xclip_p = None
|
||||
raise subprocess.SubprocessError
|
||||
else:
|
||||
xclip_p = None
|
||||
raise subprocess.SubprocessError
|
||||
return xclip_p
|
||||
|
||||
def send_emoji_to_typing(self) -> CompletedProcess | None:
|
||||
""" Output emoji to active window as if user typed it on keyboard. """
|
||||
|
||||
command: list[str] = []
|
||||
command.append(self.programs['xdotool'].as_posix())
|
||||
command.append('getwindowfocus')
|
||||
command.append('windowfocus')
|
||||
command.append('--sync')
|
||||
command.append('type')
|
||||
command.append('--clearmodifiers')
|
||||
command.append('--delay')
|
||||
command.append('25')
|
||||
if self.selected_emoji:
|
||||
command.append(self.selected_emoji)
|
||||
xdotool_p: CompletedProcess | None = None
|
||||
xdotool_p = subprocess.run(command,
|
||||
stdin=subprocess.PIPE,
|
||||
text=True,
|
||||
check=True,
|
||||
timeout=1)
|
||||
return xdotool_p
|
||||
|
||||
def send_emoji_to_notify(self) -> CompletedProcess | None:
|
||||
""" Send the emoji as a notification message. """
|
||||
|
||||
command: list[str] = []
|
||||
command.append(self.programs['notify-send'].as_posix())
|
||||
command.append('--urgency=low')
|
||||
if self.selected_emoji:
|
||||
command.append(self.selected_emoji)
|
||||
notify_p: CompletedProcess | None = None
|
||||
notify_p = subprocess.run(command,
|
||||
stdin=subprocess.PIPE,
|
||||
text=True,
|
||||
check=True,
|
||||
timeout=1)
|
||||
return notify_p
|
||||
|
||||
def append_recents(self) -> bool:
|
||||
""" Append the last selected emoji entry to the recents file. """
|
||||
|
||||
if (not self.norecents
|
||||
and self.db_recents
|
||||
and self.selected_emoji
|
||||
and self.selected_desc):
|
||||
line: str = ''
|
||||
if self.db_recents.exists():
|
||||
line = '\n'
|
||||
self.trim_recents_file()
|
||||
line += self.selected_emoji + ' ' + self.selected_desc
|
||||
with open(self.db_recents, 'a') as file:
|
||||
file.write(line)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def trim_recents_file(self) -> bool:
|
||||
""" Shortens and strips recents file if it gets big. """
|
||||
|
||||
max_byte_size: int = 4096
|
||||
max_list_entries: int = 50
|
||||
if (self.db_recents
|
||||
and self.db_recents.stat().st_size > max_byte_size):
|
||||
data: str = self.db_recents.read_text().strip('\n')
|
||||
recents_list: list = data.splitlines()
|
||||
recents_list.reverse()
|
||||
recents_list = list(dict.fromkeys(recents_list))
|
||||
recents_list = recents_list[0:max_list_entries]
|
||||
recents_list.reverse()
|
||||
data = '\n'.join(recents_list)
|
||||
self.db_recents.unlink(missing_ok=True)
|
||||
self.db_recents.write_text(data)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def print_version(self):
|
||||
""" Print version and frozen state of this program. """
|
||||
|
||||
if self.frozen:
|
||||
frozen = ' (pyinstaller)'
|
||||
else:
|
||||
frozen = ''
|
||||
print(f'{self.name} v{self.version}{frozen}')
|
||||
|
||||
def print_list_programs(self):
|
||||
""" Print all program names and paths to stdout. """
|
||||
|
||||
for name, path in self.programs.items():
|
||||
print(name + ':', path.as_posix())
|
||||
|
||||
@classmethod
|
||||
def which(cls, command: str) -> Path:
|
||||
""" Find command in $PATH or get fullpath. """
|
||||
|
||||
program: str | None = shutil.which(command)
|
||||
path: Path
|
||||
if program:
|
||||
path = Path(program)
|
||||
else:
|
||||
path = fullpath(command)
|
||||
if not path.is_file():
|
||||
path = Path(command)
|
||||
return path
|
||||
|
||||
|
||||
def fullpath(file: str) -> Path:
|
||||
""" Transform str to path, resolve env vars, tilde and make absolute. """
|
||||
|
||||
expandedfile: str = os.path.expandvars(file)
|
||||
path: Path = Path(expandedfile).expanduser().resolve()
|
||||
return path
|
||||
|
||||
|
||||
def parse_arguments(args: list[str] | None = None) -> argparse.Namespace:
|
||||
""" Programs CLI options. """
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=('🍒⛏️ Emoji Cherry Pick - Select an emoji and go wild.'),
|
||||
epilog=('Copyright © 2022 Tuncay D. '
|
||||
'<https://github.com/thingsiplay/emojicherrypick>'),
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--version',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='print version and exit'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--list-programs',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='list available programs and exit'
|
||||
)
|
||||
|
||||
p_enable_output = parser.add_argument_group('enable output')
|
||||
|
||||
p_enable_output.add_argument(
|
||||
'-o', '--stdout',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=('write selected emoji to stdout, unless option "--nostdout" '
|
||||
'is in effect')
|
||||
)
|
||||
|
||||
p_enable_output.add_argument(
|
||||
'-t', '--typing',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=('simulate typing out the emoji on the keyboard, unless option '
|
||||
'"--notyping" is in effect, typing can be unreliable and not '
|
||||
'all applications may accept or play nice with it')
|
||||
)
|
||||
|
||||
p_enable_output.add_argument(
|
||||
'-c', '--clipboard',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=('copy selected emoji to system clipboard, unless option '
|
||||
'"--noclipboard" is in effect')
|
||||
)
|
||||
|
||||
p_enable_output.add_argument(
|
||||
'-n', '--notify',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=('send selected emoji as a notification message, unless option '
|
||||
'"--nonotify" is in effect')
|
||||
)
|
||||
|
||||
p_disable_output = parser.add_argument_group('disable output')
|
||||
|
||||
p_disable_output.add_argument(
|
||||
'-O', '--nostdout',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='disable interaction with stdout, regardless of other options'
|
||||
)
|
||||
|
||||
p_disable_output.add_argument(
|
||||
'-T', '--notyping',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=('disable simulated typing to active window, regardless of '
|
||||
'other options')
|
||||
)
|
||||
|
||||
p_disable_output.add_argument(
|
||||
'-C', '--noclipboard',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=('disable interaction with clipboard, regardless of other '
|
||||
'options')
|
||||
)
|
||||
|
||||
p_disable_output.add_argument(
|
||||
'-N', '--nonotify',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=('do not send any notification messages, regardless of other '
|
||||
'options')
|
||||
)
|
||||
|
||||
p_programs = parser.add_argument_group('programs')
|
||||
|
||||
p_programs.add_argument(
|
||||
'--rofi',
|
||||
metavar='CMD',
|
||||
default='rofi',
|
||||
help=('name or path to "rofi" program when option "--menu" is set to '
|
||||
'"rofi"')
|
||||
)
|
||||
|
||||
p_programs.add_argument(
|
||||
'--dmenu',
|
||||
metavar='CMD',
|
||||
default='dmenu',
|
||||
help=('name or path to "dmenu" program when option "--menu" is set to '
|
||||
'"dmenu"')
|
||||
)
|
||||
|
||||
p_programs.add_argument(
|
||||
'--pmenu',
|
||||
metavar='CMD',
|
||||
default='pmenu',
|
||||
help=('name or path to "pmenu" program when option "--menu" is set to '
|
||||
'"pmenu"')
|
||||
)
|
||||
|
||||
p_programs.add_argument(
|
||||
'--fzf',
|
||||
metavar='CMD',
|
||||
default='fzf',
|
||||
help=('name or path to "fzf" program when option "--menu" is set to '
|
||||
'"fzf"')
|
||||
)
|
||||
|
||||
p_programs.add_argument(
|
||||
'--xclip',
|
||||
metavar='CMD',
|
||||
default='xclip',
|
||||
help=('name or path to "xclip" program to handle clipboard when '
|
||||
'option "--clipboard" is active')
|
||||
)
|
||||
|
||||
p_programs.add_argument(
|
||||
'--xdotool',
|
||||
metavar='CMD',
|
||||
default='xdotool',
|
||||
help=('name or path to "xdotool" program to handle typing when option '
|
||||
'"--typing" is active')
|
||||
)
|
||||
|
||||
p_programs.add_argument(
|
||||
'--notifysend',
|
||||
metavar='CMD',
|
||||
default='notify-send',
|
||||
help=('name or path to "notify-send" program to handle notifications '
|
||||
'when option "--notify" is active')
|
||||
)
|
||||
|
||||
p_menufilter = parser.add_argument_group('engines and filters')
|
||||
|
||||
default_menu: str = 'rofi'
|
||||
p_menufilter.add_argument(
|
||||
'-M', '--menu',
|
||||
metavar='SYSTEM',
|
||||
default=default_menu,
|
||||
choices=['rofi', 'dmenu', 'pmenu', 'fzf', 'filter', 'random', 'none'],
|
||||
help=('change menu engine to select emojis, available systems: '
|
||||
'"rofi", "dmenu", "pmenu", "fzf", "filter", "random", "none", '
|
||||
'system "none" disables selection, "filter" won\'t display a '
|
||||
'menu but choose first entry in the list that matches the text '
|
||||
'at option "--pattern", systems "fzf" and "pmenu" are terminal '
|
||||
'programs, "random" won\'t display a menu but choose an entry '
|
||||
f'by random chance, defaults to: "{default_menu}"')
|
||||
)
|
||||
|
||||
p_menufilter.add_argument(
|
||||
'-p', '--pattern',
|
||||
metavar='filter',
|
||||
default='',
|
||||
help=('simple text filter, used when option "--menu" is set to '
|
||||
'"filter" or "fzf", causes in both cases to non interactive '
|
||||
'selection of first emoji that matches the pattern')
|
||||
)
|
||||
|
||||
default_matching_rofi: str = 'normal'
|
||||
p_menufilter.add_argument(
|
||||
'-m', '--matching-rofi',
|
||||
metavar='MODE',
|
||||
default=default_matching_rofi,
|
||||
choices=['normal', 'regex', 'glob', 'fuzzy', 'prefix'],
|
||||
help=('set matching algorithm for search in rofi, available modes: '
|
||||
'"normal", "regex", "glob", "fuzzy", "prefix", defaults to: '
|
||||
f'"{default_matching_rofi}"')
|
||||
)
|
||||
|
||||
p_menufilter.add_argument(
|
||||
'-i', '--ignore-case',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=('ignore case sensitivity when searching list of emojis, '
|
||||
'unless option "--noignore-case" is in effect')
|
||||
)
|
||||
|
||||
p_menufilter.add_argument(
|
||||
'-I', '--noignore-case',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='case sensitive search of emojis, regardless of other options'
|
||||
)
|
||||
|
||||
p_cache = parser.add_argument_group('cache files')
|
||||
|
||||
default_url = ('https://gist.githubusercontent.com/thingsiplay/'
|
||||
'1f500459bc117cf0b63e1f5c11e03963/raw/'
|
||||
'd8e4b78cfe66862cf3809443c1dba017f37b61db/emojis.json')
|
||||
p_cache.add_argument(
|
||||
'-u', '--url',
|
||||
metavar='URL',
|
||||
default=(default_url),
|
||||
help=('source web address to download file "emojis.json", defaults '
|
||||
f'to: "{default_url}"')
|
||||
)
|
||||
|
||||
p_cache.add_argument(
|
||||
'-U', '--offline',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='prohibit downloading files from network, mainly "emojis.json"'
|
||||
)
|
||||
|
||||
default_cache: str = "~/.cache/emojicherrypick"
|
||||
p_cache.add_argument(
|
||||
'-d', '--cache-dir',
|
||||
metavar='DIR',
|
||||
default=default_cache,
|
||||
help=('directory for downloads and other long-lived temporary files '
|
||||
f'used for quick access, defaults to: "{default_cache}"')
|
||||
)
|
||||
|
||||
p_cache.add_argument(
|
||||
'-w', '--wipe-cache',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=('delete temporary cache files, redownload and recreate them '
|
||||
'unless option "--offline" is in effect')
|
||||
)
|
||||
|
||||
p_cache.add_argument(
|
||||
'-E', '--noemojis',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=('disable loading from main emojis database created from '
|
||||
'"emojis.json"')
|
||||
)
|
||||
|
||||
default_recents: str = "~/.cache/emojicherrypick/recents.cherry"
|
||||
p_cache.add_argument(
|
||||
'-r', '--recents',
|
||||
metavar='FILE',
|
||||
default=default_recents,
|
||||
help=('program keeps track of last used emojis and saves them to '
|
||||
'a history file, the last entries will be displayed at the top '
|
||||
'of each emoji listing in the menus, same format as '
|
||||
'"--favorites" file, use option "--recents-size" to set number '
|
||||
f'of entries to show blah, defaults to: "{default_recents}"')
|
||||
)
|
||||
|
||||
p_cache.add_argument(
|
||||
'-R', '--norecents',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='disable recents file specified at option "--recents"'
|
||||
)
|
||||
|
||||
default_recents_size: int = 2
|
||||
p_cache.add_argument(
|
||||
'-k', '--recents-size',
|
||||
metavar='NUM',
|
||||
default=default_recents_size,
|
||||
type=int,
|
||||
choices=range(0, 200),
|
||||
help=('read number of recently used emojis and ignore rest of file, '
|
||||
'can be used for displaying in the menu or at filters, '
|
||||
f'defaults to: "{default_recents_size}"')
|
||||
)
|
||||
|
||||
p_cache.add_argument(
|
||||
'--ignore-skin',
|
||||
default=True,
|
||||
action=argparse.BooleanOptionalAction,
|
||||
help='ignore emoji skin variations when creating the cache'
|
||||
)
|
||||
|
||||
p_config = parser.add_argument_group('config files')
|
||||
|
||||
default_favorites: str = "~/.config/emojicherrypick/favorites.cherry"
|
||||
p_config.add_argument(
|
||||
'-f', '--favorites',
|
||||
metavar='FILE',
|
||||
default=default_favorites,
|
||||
help=('user list of emojis to list at the beginning of each emoji '
|
||||
'listing in the menus, 1 line per emoji set, each set starts '
|
||||
'with an emoji or any text and goes until first space is found, '
|
||||
'rest of the line are names, descripion and keywords, defaults '
|
||||
f'to: "{default_favorites}"')
|
||||
)
|
||||
|
||||
p_config.add_argument(
|
||||
'-F', '--nofavorites',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='disable favorites file specified at option "--favorites"'
|
||||
)
|
||||
|
||||
p_menuinterface = parser.add_argument_group('menu interface')
|
||||
|
||||
default_prompt: str = '🍒'
|
||||
p_menuinterface.add_argument(
|
||||
'-@', '--prompt',
|
||||
metavar='TEXT',
|
||||
default=default_prompt,
|
||||
help=('set custom prompt on user input menu left of entry field, '
|
||||
f'defaults to: "{default_prompt}"')
|
||||
)
|
||||
|
||||
default_font_family: str = 'Noto Color Emoji'
|
||||
p_menuinterface.add_argument(
|
||||
'-g', '--font-family',
|
||||
metavar='NAME',
|
||||
default=default_font_family,
|
||||
help=('font name to use for dispaly with the menu, defaults to: '
|
||||
f'"{default_font_family}"')
|
||||
)
|
||||
|
||||
default_font_size: int = 16
|
||||
p_menuinterface.add_argument(
|
||||
'-s', '--font-size',
|
||||
metavar='NUM',
|
||||
default=default_font_size,
|
||||
type=int,
|
||||
choices=range(4, 256),
|
||||
help=('font size of emojis and text to display in the menu, '
|
||||
f'defaults to: "{default_font_size}"')
|
||||
)
|
||||
|
||||
default_list_size: int = 15
|
||||
p_menuinterface.add_argument(
|
||||
'-l', '--list-size',
|
||||
metavar='NUM',
|
||||
default=default_list_size,
|
||||
type=int,
|
||||
choices=range(1, 200),
|
||||
help=('number of rows to display in the menu, defaults to: '
|
||||
f'"{default_list_size}"')
|
||||
)
|
||||
|
||||
if args is None:
|
||||
return parser.parse_args()
|
||||
else:
|
||||
return parser.parse_args(args)
|
||||
|
||||
|
||||
def main(args: list[str] | None = None) -> int:
|
||||
""" Run the application. """
|
||||
|
||||
app: App
|
||||
if not args and not sys.argv[1:]:
|
||||
args_default: list[str] = [os.getenv('EMOJICHERRYPICK_DEFAULT',
|
||||
default='-con')]
|
||||
app = App(parse_arguments(args_default))
|
||||
else:
|
||||
app = App(parse_arguments(args))
|
||||
|
||||
if app.list_version:
|
||||
app.print_version()
|
||||
return 0
|
||||
elif app.list_programs:
|
||||
app.print_list_programs()
|
||||
return 0
|
||||
|
||||
try:
|
||||
if app.menu == 'rofi':
|
||||
app.select_by_rofi()
|
||||
elif app.menu == 'dmenu':
|
||||
app.select_by_dmenu()
|
||||
elif app.menu == 'pmenu':
|
||||
app.select_by_pmenu()
|
||||
elif app.menu == 'fzf':
|
||||
app.select_by_fzf()
|
||||
elif app.menu == 'filter':
|
||||
app.select_by_filter()
|
||||
elif app.menu == 'random':
|
||||
app.select_by_random()
|
||||
elif app.menu == 'none':
|
||||
app.select_by_none()
|
||||
else:
|
||||
raise RuntimeError('Unkown menu option.')
|
||||
return -1
|
||||
except subprocess.SubprocessError:
|
||||
return 1
|
||||
|
||||
if app.selected_emoji:
|
||||
try:
|
||||
if app.stdout:
|
||||
app.send_emoji_to_stdout()
|
||||
if app.clipboard:
|
||||
app.send_emoji_to_clipboard()
|
||||
if app.typing:
|
||||
app.send_emoji_to_typing()
|
||||
if app.notify:
|
||||
app.send_emoji_to_notify()
|
||||
except subprocess.SubprocessError:
|
||||
return 3
|
||||
elif app.menu == 'none':
|
||||
return 0
|
||||
else:
|
||||
return 2
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
14
home/.local/usr/bin/foot-smart
Executable file
14
home/.local/usr/bin/foot-smart
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
if footclient "$@" 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exec foot --server &
|
||||
|
||||
sleep 0.2
|
||||
|
||||
exec footclient "$@" || {
|
||||
echo "Failed to connect to foot server." >&2
|
||||
exit 1
|
||||
}
|
||||
329
home/.local/usr/bin/fzf-git.sh
Executable file
329
home/.local/usr/bin/fzf-git.sh
Executable file
@@ -0,0 +1,329 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2024 Junegunn Choi
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
# shellcheck disable=SC2039
|
||||
[[ $0 = - ]] && return
|
||||
|
||||
__fzf_git_color() {
|
||||
if [[ -n $NO_COLOR ]]; then
|
||||
echo never
|
||||
elif [[ $# -gt 0 ]] && [[ -n $FZF_GIT_PREVIEW_COLOR ]]; then
|
||||
echo "$FZF_GIT_PREVIEW_COLOR"
|
||||
else
|
||||
echo "${FZF_GIT_COLOR:-always}"
|
||||
fi
|
||||
}
|
||||
|
||||
__fzf_git_cat() {
|
||||
if [[ -n $FZF_GIT_CAT ]]; then
|
||||
echo "$FZF_GIT_CAT"
|
||||
return
|
||||
fi
|
||||
|
||||
# Sometimes bat is installed as batcat
|
||||
_fzf_git_bat_options="--style='${BAT_STYLE:-full}' --color=$(__fzf_git_color .) --pager=never"
|
||||
if command -v batcat > /dev/null; then
|
||||
echo "batcat $_fzf_git_bat_options"
|
||||
elif command -v bat > /dev/null; then
|
||||
echo "bat $_fzf_git_bat_options"
|
||||
else
|
||||
echo cat
|
||||
fi
|
||||
}
|
||||
|
||||
__fzf_git_pager() {
|
||||
local pager
|
||||
pager="${FZF_GIT_PAGER:-${GIT_PAGER:-$(git config --get core.pager 2>/dev/null)}}"
|
||||
echo "${pager:-cat}"
|
||||
}
|
||||
|
||||
if [[ $# -eq 1 ]]; then
|
||||
branches() {
|
||||
git branch "$@" --sort=-committerdate --sort=-HEAD --format=$'%(HEAD) %(color:yellow)%(refname:short) %(color:green)(%(committerdate:relative))\t%(color:blue)%(subject)%(color:reset)' --color=$(__fzf_git_color) | column -ts$'\t'
|
||||
}
|
||||
refs() {
|
||||
git for-each-ref "$@" --sort=-creatordate --sort=-HEAD --color=$(__fzf_git_color) --format=$'%(if:equals=refs/remotes)%(refname:rstrip=-2)%(then)%(color:magenta)remote-branch%(else)%(if:equals=refs/heads)%(refname:rstrip=-2)%(then)%(color:brightgreen)branch%(else)%(if:equals=refs/tags)%(refname:rstrip=-2)%(then)%(color:brightcyan)tag%(else)%(if:equals=refs/stash)%(refname:rstrip=-2)%(then)%(color:brightred)stash%(else)%(color:white)%(refname:rstrip=-2)%(end)%(end)%(end)%(end)\t%(color:yellow)%(refname:short) %(color:green)(%(creatordate:relative))\t%(color:blue)%(subject)%(color:reset)' | column -ts$'\t'
|
||||
}
|
||||
hashes() {
|
||||
git log --date=short --format="%C(green)%C(bold)%cd %C(auto)%h%d %s (%an)" --graph --color=$(__fzf_git_color) "$@"
|
||||
}
|
||||
case "$1" in
|
||||
branches)
|
||||
echo $'CTRL-O (open in browser) ╱ ALT-A (show all branches)\n'
|
||||
branches
|
||||
;;
|
||||
all-branches)
|
||||
echo $'CTRL-O (open in browser)\n'
|
||||
branches -a
|
||||
;;
|
||||
hashes)
|
||||
echo $'CTRL-O (open in browser) ╱ CTRL-D (diff)\nCTRL-S (toggle sort) ╱ ALT-A (show all hashes)\n'
|
||||
hashes
|
||||
;;
|
||||
all-hashes)
|
||||
echo $'CTRL-O (open in browser) ╱ CTRL-D (diff)\nCTRL-S (toggle sort)\n'
|
||||
hashes --all
|
||||
;;
|
||||
refs)
|
||||
echo $'CTRL-O (open in browser) ╱ ALT-E (examine in editor) ╱ ALT-A (show all refs)\n'
|
||||
refs --exclude='refs/remotes'
|
||||
;;
|
||||
all-refs)
|
||||
echo $'CTRL-O (open in browser) ╱ ALT-E (examine in editor)\n'
|
||||
refs
|
||||
;;
|
||||
nobeep) ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
elif [[ $# -gt 1 ]]; then
|
||||
set -e
|
||||
|
||||
branch=$(git rev-parse --abbrev-ref HEAD 2> /dev/null)
|
||||
if [[ $branch = HEAD ]]; then
|
||||
branch=$(git describe --exact-match --tags 2> /dev/null || git rev-parse --short HEAD)
|
||||
fi
|
||||
|
||||
# Only supports GitHub for now
|
||||
case "$1" in
|
||||
commit)
|
||||
hash=$(grep -o "[a-f0-9]\{7,\}" <<< "$2")
|
||||
path=/commit/$hash
|
||||
;;
|
||||
branch|remote-branch)
|
||||
branch=$(sed 's/^[* ]*//' <<< "$2" | cut -d' ' -f1)
|
||||
remote=$(git config branch."${branch}".remote || echo 'origin')
|
||||
branch=${branch#$remote/}
|
||||
path=/tree/$branch
|
||||
;;
|
||||
remote)
|
||||
remote=$2
|
||||
path=/tree/$branch
|
||||
;;
|
||||
file) path=/blob/$branch/$(git rev-parse --show-prefix)$2 ;;
|
||||
tag) path=/releases/tag/$2 ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
|
||||
remote=${remote:-$(git config branch."${branch}".remote || echo 'origin')}
|
||||
remote_url=$(git remote get-url "$remote" 2> /dev/null || echo "$remote")
|
||||
|
||||
if [[ $remote_url =~ ^git@ ]]; then
|
||||
url=${remote_url%.git}
|
||||
url=${url#git@}
|
||||
url=https://${url/://}
|
||||
elif [[ $remote_url =~ ^http ]]; then
|
||||
url=${remote_url%.git}
|
||||
fi
|
||||
|
||||
case "$(uname -s)" in
|
||||
Darwin) open "$url$path" ;;
|
||||
*) xdg-open "$url$path" ;;
|
||||
esac
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ $- =~ i ]]; then
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Redefine this function to change the options
|
||||
_fzf_git_fzf() {
|
||||
fzf --height=50% --tmux 90%,70% \
|
||||
--layout=reverse --multi --min-height=20 --border \
|
||||
--border-label-pos=2 \
|
||||
--color='header:italic:underline,label:blue' \
|
||||
--preview-window='right,50%,border-left' \
|
||||
--bind='ctrl-/:change-preview-window(down,50%,border-top|hidden|)' "$@"
|
||||
}
|
||||
|
||||
_fzf_git_check() {
|
||||
git rev-parse HEAD > /dev/null 2>&1 && return
|
||||
|
||||
[[ -n $TMUX ]] && tmux display-message "Not in a git repository"
|
||||
return 1
|
||||
}
|
||||
|
||||
__fzf_git=${BASH_SOURCE[0]:-${(%):-%x}}
|
||||
__fzf_git=$(readlink -f "$__fzf_git" 2> /dev/null || /usr/bin/ruby --disable-gems -e 'puts File.expand_path(ARGV.first)' "$__fzf_git" 2> /dev/null)
|
||||
|
||||
_fzf_git_files() {
|
||||
_fzf_git_check || return
|
||||
local root query
|
||||
root=$(git rev-parse --show-toplevel)
|
||||
[[ $root != "$PWD" ]] && query='!../ '
|
||||
|
||||
(git -c color.status=$(__fzf_git_color) status --short --no-branch
|
||||
git ls-files "$root" | grep -vxFf <(git status -s | grep '^[^?]' | cut -c4-; echo :) | sed 's/^/ /') |
|
||||
_fzf_git_fzf -m --ansi --nth 2..,.. \
|
||||
--border-label '📁 Files' \
|
||||
--header $'CTRL-O (open in browser) ╱ ALT-E (open in editor)\n\n' \
|
||||
--bind "ctrl-o:execute-silent:bash $__fzf_git file {-1}" \
|
||||
--bind "alt-e:execute:${EDITOR:-vim} {-1} > /dev/tty" \
|
||||
--query "$query" \
|
||||
--preview "git diff --no-ext-diff --color=$(__fzf_git_color .) -- {-1} | $(__fzf_git_pager); $(__fzf_git_cat) {-1}" "$@" |
|
||||
cut -c4- | sed 's/.* -> //'
|
||||
}
|
||||
|
||||
_fzf_git_branches() {
|
||||
_fzf_git_check || return
|
||||
bash "$__fzf_git" branches |
|
||||
_fzf_git_fzf --ansi \
|
||||
--border-label '🌲 Branches' \
|
||||
--header-lines 2 \
|
||||
--tiebreak begin \
|
||||
--preview-window down,border-top,40% \
|
||||
--color hl:underline,hl+:underline \
|
||||
--no-hscroll \
|
||||
--bind 'ctrl-/:change-preview-window(down,70%|hidden|)' \
|
||||
--bind "ctrl-o:execute-silent:bash $__fzf_git branch {}" \
|
||||
--bind "alt-a:change-border-label(🌳 All branches)+reload:bash \"$__fzf_git\" all-branches" \
|
||||
--preview "git log --oneline --graph --date=short --color=$(__fzf_git_color .) --pretty='format:%C(auto)%cd %h%d %s' \$(sed s/^..// <<< {} | cut -d' ' -f1) --" "$@" |
|
||||
sed 's/^..//' | cut -d' ' -f1
|
||||
}
|
||||
|
||||
_fzf_git_tags() {
|
||||
_fzf_git_check || return
|
||||
git tag --sort -version:refname |
|
||||
_fzf_git_fzf --preview-window right,70% \
|
||||
--border-label '📛 Tags' \
|
||||
--header $'CTRL-O (open in browser)\n\n' \
|
||||
--bind "ctrl-o:execute-silent:bash $__fzf_git tag {}" \
|
||||
--preview "git show --color=$(__fzf_git_color .) {} | $(__fzf_git_pager)" "$@"
|
||||
}
|
||||
|
||||
_fzf_git_hashes() {
|
||||
_fzf_git_check || return
|
||||
bash "$__fzf_git" hashes |
|
||||
_fzf_git_fzf --ansi --no-sort --bind 'ctrl-s:toggle-sort' \
|
||||
--border-label '🍡 Hashes' \
|
||||
--header-lines 3 \
|
||||
--bind "ctrl-o:execute-silent:bash $__fzf_git commit {}" \
|
||||
--bind "ctrl-d:execute:grep -o '[a-f0-9]\{7,\}' <<< {} | head -n 1 | xargs git diff --color=$(__fzf_git_color) > /dev/tty" \
|
||||
--bind "alt-a:change-border-label(🍇 All hashes)+reload:bash \"$__fzf_git\" all-hashes" \
|
||||
--color hl:underline,hl+:underline \
|
||||
--preview "grep -o '[a-f0-9]\{7,\}' <<< {} | head -n 1 | xargs git show --color=$(__fzf_git_color .) | $(__fzf_git_pager)" "$@" |
|
||||
awk 'match($0, /[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]*/) { print substr($0, RSTART, RLENGTH) }'
|
||||
}
|
||||
|
||||
_fzf_git_remotes() {
|
||||
_fzf_git_check || return
|
||||
git remote -v | awk '{print $1 "\t" $2}' | uniq |
|
||||
_fzf_git_fzf --tac \
|
||||
--border-label '📡 Remotes' \
|
||||
--header $'CTRL-O (open in browser)\n\n' \
|
||||
--bind "ctrl-o:execute-silent:bash $__fzf_git remote {1}" \
|
||||
--preview-window right,70% \
|
||||
--preview "git log --oneline --graph --date=short --color=$(__fzf_git_color .) --pretty='format:%C(auto)%cd %h%d %s' '{1}/$(git rev-parse --abbrev-ref HEAD)' --" "$@" |
|
||||
cut -d$'\t' -f1
|
||||
}
|
||||
|
||||
_fzf_git_stashes() {
|
||||
_fzf_git_check || return
|
||||
git stash list | _fzf_git_fzf \
|
||||
--border-label '🥡 Stashes' \
|
||||
--header $'CTRL-X (drop stash)\n\n' \
|
||||
--bind 'ctrl-x:reload(git stash drop -q {1}; git stash list)' \
|
||||
-d: --preview "git show --color=$(__fzf_git_color .) {1} | $(__fzf_git_pager)" "$@" |
|
||||
cut -d: -f1
|
||||
}
|
||||
|
||||
_fzf_git_lreflogs() {
|
||||
_fzf_git_check || return
|
||||
git reflog --color=$(__fzf_git_color) --format="%C(blue)%gD %C(yellow)%h%C(auto)%d %gs" | _fzf_git_fzf --ansi \
|
||||
--border-label '📒 Reflogs' \
|
||||
--preview "git show --color=$(__fzf_git_color .) {1} | $(__fzf_git_pager)" "$@" |
|
||||
awk '{print $1}'
|
||||
}
|
||||
|
||||
_fzf_git_each_ref() {
|
||||
_fzf_git_check || return
|
||||
bash "$__fzf_git" refs | _fzf_git_fzf --ansi \
|
||||
--nth 2,2.. \
|
||||
--tiebreak begin \
|
||||
--border-label '☘️ Each ref' \
|
||||
--header-lines 2 \
|
||||
--preview-window down,border-top,40% \
|
||||
--color hl:underline,hl+:underline \
|
||||
--no-hscroll \
|
||||
--bind 'ctrl-/:change-preview-window(down,70%|hidden|)' \
|
||||
--bind "ctrl-o:execute-silent:bash $__fzf_git {1} {2}" \
|
||||
--bind "alt-e:execute:${EDITOR:-vim} <(git show {2}) > /dev/tty" \
|
||||
--bind "alt-a:change-border-label(🍀 Every ref)+reload:bash \"$__fzf_git\" all-refs" \
|
||||
--preview "git log --oneline --graph --date=short --color=$(__fzf_git_color .) --pretty='format:%C(auto)%cd %h%d %s' {2} --" "$@" |
|
||||
awk '{print $2}'
|
||||
}
|
||||
|
||||
_fzf_git_worktrees() {
|
||||
_fzf_git_check || return
|
||||
git worktree list | _fzf_git_fzf \
|
||||
--border-label '🌴 Worktrees' \
|
||||
--header $'CTRL-X (remove worktree)\n\n' \
|
||||
--bind 'ctrl-x:reload(git worktree remove {1} > /dev/null; git worktree list)' \
|
||||
--preview "
|
||||
git -c color.status=$(__fzf_git_color .) -C {1} status --short --branch
|
||||
echo
|
||||
git log --oneline --graph --date=short --color=$(__fzf_git_color .) --pretty='format:%C(auto)%cd %h%d %s' {2} --
|
||||
" "$@" |
|
||||
awk '{print $1}'
|
||||
}
|
||||
|
||||
if [[ -n "${BASH_VERSION:-}" ]]; then
|
||||
__fzf_git_init() {
|
||||
bind -m emacs-standard '"\er": redraw-current-line'
|
||||
bind -m emacs-standard '"\C-z": vi-editing-mode'
|
||||
bind -m vi-command '"\C-z": emacs-editing-mode'
|
||||
bind -m vi-insert '"\C-z": emacs-editing-mode'
|
||||
|
||||
local o c
|
||||
for o in "$@"; do
|
||||
c=${o:0:1}
|
||||
bind -m emacs-standard '"\C-g\C-'$c'": " \C-u \C-a\C-k`_fzf_git_'$o'`\e\C-e\C-y\C-a\C-y\ey\C-h\C-e\er \C-h"'
|
||||
bind -m vi-command '"\C-g\C-'$c'": "\C-z\C-g\C-'$c'\C-z"'
|
||||
bind -m vi-insert '"\C-g\C-'$c'": "\C-z\C-g\C-'$c'\C-z"'
|
||||
bind -m emacs-standard '"\C-g'$c'": " \C-u \C-a\C-k`_fzf_git_'$o'`\e\C-e\C-y\C-a\C-y\ey\C-h\C-e\er \C-h"'
|
||||
bind -m vi-command '"\C-g'$c'": "\C-z\C-g'$c'\C-z"'
|
||||
bind -m vi-insert '"\C-g'$c'": "\C-z\C-g'$c'\C-z"'
|
||||
done
|
||||
}
|
||||
elif [[ -n "${ZSH_VERSION:-}" ]]; then
|
||||
__fzf_git_join() {
|
||||
local item
|
||||
while read item; do
|
||||
echo -n "${(q)item} "
|
||||
done
|
||||
}
|
||||
|
||||
__fzf_git_init() {
|
||||
local m o
|
||||
for o in "$@"; do
|
||||
eval "fzf-git-$o-widget() { local result=\$(_fzf_git_$o | __fzf_git_join); zle reset-prompt; LBUFFER+=\$result }"
|
||||
eval "zle -N fzf-git-$o-widget"
|
||||
for m in emacs vicmd viins; do
|
||||
eval "bindkey -M $m '^g^${o[1]}' fzf-git-$o-widget"
|
||||
eval "bindkey -M $m '^g${o[1]}' fzf-git-$o-widget"
|
||||
done
|
||||
done
|
||||
}
|
||||
fi
|
||||
__fzf_git_init files branches tags remotes hashes stashes lreflogs each_ref worktrees
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
fi
|
||||
1
home/.local/usr/bin/getMusic
Executable file
1
home/.local/usr/bin/getMusic
Executable file
@@ -0,0 +1 @@
|
||||
#!/usr/env python
|
||||
3
home/.local/usr/bin/gettmuxLayout
Executable file
3
home/.local/usr/bin/gettmuxLayout
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/bash
|
||||
layout=$( tmux display-message -p "#{window_layout}" )
|
||||
echo $layout
|
||||
16
home/.local/usr/bin/igrep
Executable file
16
home/.local/usr/bin/igrep
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Check if the first argument is a path and assign it to SEARCH_PATH
|
||||
SEARCH_PATH="${1:-.}"
|
||||
|
||||
# Shift the arguments so any additional arguments are treated as the search pattern for `rg`
|
||||
shift
|
||||
|
||||
# Execute `rg` in the specified path with the search pattern
|
||||
rg --color=always --line-number --no-heading --smart-case --hidden "${*:-}" "$SEARCH_PATH" |
|
||||
fzf --ansi \
|
||||
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
||||
--delimiter : \
|
||||
--preview 'bat --color=always {1} --highlight-line {2}' \
|
||||
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3' \
|
||||
--bind 'enter:become(nvim {1} +{2})'
|
||||
9
home/.local/usr/bin/inotify_test_pytest.sh
Executable file
9
home/.local/usr/bin/inotify_test_pytest.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
while true; do
|
||||
inotifywait -e modify,create,delete -r ./src ./tests/
|
||||
clear
|
||||
echo "File change detected. Running tests..."
|
||||
pytest -s
|
||||
echo "Waiting for changes..."
|
||||
done
|
||||
9
home/.local/usr/bin/inotify_test_rust.sh
Executable file
9
home/.local/usr/bin/inotify_test_rust.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
while true; do
|
||||
inotifywait -e modify,create,delete -r ./src/
|
||||
clear
|
||||
echo "File change detected. Running build..."
|
||||
cargo build
|
||||
echo "Waiting for changes..."
|
||||
done
|
||||
9
home/.local/usr/bin/inotify_test_zig.sh
Executable file
9
home/.local/usr/bin/inotify_test_zig.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
while true; do
|
||||
inotifywait -e modify,create,delete -r ./build.zig ./build.zig.zon ./src/*
|
||||
clear
|
||||
echo "File change detected. Running tests..."
|
||||
zig build run
|
||||
echo "Waiting for changes..."
|
||||
done
|
||||
3
home/.local/usr/bin/nestX
Executable file
3
home/.local/usr/bin/nestX
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
Xephyr -br -ac -noreset -screen 1366x768 :1
|
||||
10
home/.local/usr/bin/popuptmux
Executable file
10
home/.local/usr/bin/popuptmux
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
width=${2:-100%}
|
||||
# width=${2:-80%}
|
||||
height=${2:-30%}
|
||||
if [ "$(tmux display-message -p -F "#{session_name}")" = "popup" ];then
|
||||
tmux detach-client
|
||||
else
|
||||
tmux popup -d '#{pane_current_path}' -xC -y1 -w$width -h$height -E "tmux attach -t popup || tmux new -s popup"
|
||||
# tmux popup -d '#{pane_current_path}' -xC -yC -w$width -h$height -E "tmux attach -t popup || tmux new -s popup"
|
||||
fi
|
||||
25
home/.local/usr/bin/project-picker.sh
Executable file
25
home/.local/usr/bin/project-picker.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Set the directory where your projects are located
|
||||
PROJECTS_DIR="${HOME}/Projects/"
|
||||
|
||||
# Use fzf to select a directory
|
||||
folder=$(find "$PROJECTS_DIR" -type d -maxdepth 1 | \
|
||||
fzf --delimiter / --with-nth=-1 --keep-right \
|
||||
--prompt="Projects " \
|
||||
--tmux left,40 --reverse \
|
||||
)
|
||||
|
||||
# Check if a directory was selected
|
||||
if [[ -n "$folder" ]]; then
|
||||
projectname="${folder##*/}"
|
||||
# Check if a tmux window with the project name already exists
|
||||
if tmux list-windows -F "#{window_name}" | grep -q "^$projectname$"; then
|
||||
tmux select-window -t "$projectname"
|
||||
else
|
||||
# Create a new tmux window with the project name and open nvim in the folder
|
||||
# tmux new-window -n "$projectname" "cd '$folder' &&"
|
||||
tmux new-window -n "$projectname" "cd '$folder' && nvim"
|
||||
fi
|
||||
fi
|
||||
|
||||
BIN
home/.local/usr/bin/pytui
Executable file
BIN
home/.local/usr/bin/pytui
Executable file
Binary file not shown.
304
home/.local/usr/bin/qute-pass
Executable file
304
home/.local/usr/bin/qute-pass
Executable file
@@ -0,0 +1,304 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# SPDX-FileCopyrightText: Chris Braun (cryzed) <cryzed@googlemail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
"""
|
||||
Insert login information using pass and a dmenu-compatible application (e.g. dmenu, rofi -dmenu, ...). A short
|
||||
demonstration can be seen here: https://i.imgur.com/KN3XuZP.gif.
|
||||
"""
|
||||
|
||||
USAGE = """The domain of the site has to appear as a segment in the pass path,
|
||||
for example: "github.com/cryzed" or "websites/github.com". Alternatively the
|
||||
parameter `--unfiltered` may be used to get a list of all passwords. How the
|
||||
username and password are determined is freely configurable using the CLI
|
||||
arguments. As an example, if you instead store the username as part of the
|
||||
secret (and use a site's name as filename), instead of the default configuration,
|
||||
use `--username-target secret` and `--username-pattern "username: (.+)"`.
|
||||
|
||||
The login information is inserted by emulating key events using qutebrowser's
|
||||
fake-key command in this manner: [USERNAME]<Tab>[PASSWORD], which is compatible
|
||||
with almost all login forms.
|
||||
|
||||
If you use gopass with multiple mounts, use the CLI switch --mode gopass to switch to gopass mode.
|
||||
|
||||
Suggested bindings similar to Uzbl's `formfiller` script:
|
||||
|
||||
config.bind('<z><l>', 'spawn --userscript qute-pass')
|
||||
config.bind('<z><u><l>', 'spawn --userscript qute-pass --username-only')
|
||||
config.bind('<z><p><l>', 'spawn --userscript qute-pass --password-only')
|
||||
config.bind('<z><o><l>', 'spawn --userscript qute-pass --otp-only')
|
||||
"""
|
||||
|
||||
EPILOG = """Dependencies: tldextract (Python 3 module), pass, pass-otp (optional).
|
||||
|
||||
WARNING: The login details are viewable as plaintext in qutebrowser's debug log (qute://log) and might be shared if
|
||||
you decide to submit a crash report!"""
|
||||
|
||||
import argparse
|
||||
import enum
|
||||
import fnmatch
|
||||
import functools
|
||||
import idna
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import unicodedata
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import tldextract
|
||||
|
||||
|
||||
def expanded_path(path):
|
||||
# Expand potential ~ in paths, since this script won't be called from a shell that does it for us
|
||||
expanded = os.path.expanduser(path)
|
||||
# Add trailing slash if not present
|
||||
return os.path.join(expanded, '')
|
||||
|
||||
|
||||
argument_parser = argparse.ArgumentParser(description=__doc__, usage=USAGE, epilog=EPILOG)
|
||||
argument_parser.add_argument('url', nargs='?', default=os.getenv('QUTE_URL'))
|
||||
argument_parser.add_argument('--password-store', '-p',
|
||||
default=expanded_path(os.getenv('PASSWORD_STORE_DIR', default='~/.password-store')),
|
||||
help='Path to your pass password-store (only used in pass-mode)', type=expanded_path)
|
||||
argument_parser.add_argument('--mode', '-M', choices=['pass', 'gopass'], default="pass",
|
||||
help='Select mode [gopass] to use gopass instead of the standard pass.')
|
||||
argument_parser.add_argument('--prefix', type=str,
|
||||
help='Search only the given subfolder of the store (only used in gopass-mode)')
|
||||
argument_parser.add_argument('--username-pattern', '-u', default=r'.*/(.+)',
|
||||
help='Regular expression that matches the username')
|
||||
argument_parser.add_argument('--username-target', '-U', choices=['path', 'secret'], default='path',
|
||||
help='The target for the username regular expression')
|
||||
argument_parser.add_argument('--password-pattern', '-P', default=r'(.*)',
|
||||
help='Regular expression that matches the password')
|
||||
argument_parser.add_argument('--dmenu-invocation', '-d', default='rofi -dmenu',
|
||||
help='Invocation used to execute a dmenu-provider')
|
||||
argument_parser.add_argument('--no-insert-mode', '-n', dest='insert_mode', action='store_false',
|
||||
help="Don't automatically enter insert mode")
|
||||
argument_parser.add_argument('--io-encoding', '-i', default='UTF-8',
|
||||
help='Encoding used to communicate with subprocesses')
|
||||
argument_parser.add_argument('--merge-candidates', '-m', action='store_true',
|
||||
help='Merge pass candidates for fully-qualified and registered domain name')
|
||||
argument_parser.add_argument('--extra-url-suffixes', '-s', default='',
|
||||
help='Comma-separated string containing extra suffixes (e.g local)')
|
||||
argument_parser.add_argument('--unfiltered', dest='unfiltered', action='store_true',
|
||||
help='Show an unfiltered selection of all passwords in the store')
|
||||
argument_parser.add_argument('--always-show-selection', dest='always_show_selection', action='store_true',
|
||||
help='Always show selection, even if there is only a single match')
|
||||
group = argument_parser.add_mutually_exclusive_group()
|
||||
group.add_argument('--username-only', '-e', action='store_true', help='Only insert username')
|
||||
group.add_argument('--password-only', '-w', action='store_true', help='Only insert password')
|
||||
group.add_argument('--otp-only', '-o', action='store_true', help='Only insert OTP code')
|
||||
|
||||
stderr = functools.partial(print, file=sys.stderr)
|
||||
|
||||
|
||||
class ExitCodes(enum.IntEnum):
|
||||
SUCCESS = 0
|
||||
FAILURE = 1
|
||||
# 1 is automatically used if Python throws an exception
|
||||
NO_PASS_CANDIDATES = 2
|
||||
COULD_NOT_MATCH_USERNAME = 3
|
||||
COULD_NOT_MATCH_PASSWORD = 4
|
||||
|
||||
|
||||
class CouldNotMatchUsername(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class CouldNotMatchPassword(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def qute_command(command):
|
||||
with open(os.environ['QUTE_FIFO'], 'w') as fifo:
|
||||
fifo.write(command + '\n')
|
||||
fifo.flush()
|
||||
|
||||
# Encode candidate string parts as Internationalized Domain Name, doing
|
||||
# Unicode normalization before. This allows to properly match (non-ASCII)
|
||||
# pass entries with the corresponding domain names.
|
||||
def idna_encode(name):
|
||||
# Do Unicode normalization first, we use form NFKC because:
|
||||
# 1. Use the compatibility normalization because these sequences have "the same meaning in some contexts"
|
||||
# 2. idna.encode() below requires the Unicode strings to be in normalization form C
|
||||
# See https://en.wikipedia.org/wiki/Unicode_equivalence#Normal_forms
|
||||
unicode_normalized = unicodedata.normalize("NFKC", name)
|
||||
# Empty strings can not be encoded, they appear for example as empty
|
||||
# parts in split_path. If something like this happens, we just fall back
|
||||
# to the unicode representation (which may already be ASCII then).
|
||||
try:
|
||||
idna_encoded = idna.encode(unicode_normalized)
|
||||
except idna.IDNAError:
|
||||
idna_encoded = unicode_normalized
|
||||
return idna_encoded
|
||||
|
||||
def find_pass_candidates(domain, unfiltered=False):
|
||||
candidates = []
|
||||
|
||||
if arguments.mode == "gopass":
|
||||
gopass_args = ["gopass", "list", "--flat"]
|
||||
if arguments.prefix:
|
||||
gopass_args.append(arguments.prefix)
|
||||
all_passwords = subprocess.run(gopass_args, stdout=subprocess.PIPE).stdout.decode("UTF-8").splitlines()
|
||||
|
||||
for password in all_passwords:
|
||||
if unfiltered or domain in password:
|
||||
candidates.append(password)
|
||||
else:
|
||||
idna_domain = idna_encode(domain)
|
||||
for path, directories, file_names in os.walk(arguments.password_store, followlinks=True):
|
||||
secrets = fnmatch.filter(file_names, '*.gpg')
|
||||
if not secrets:
|
||||
continue
|
||||
|
||||
# Strip password store path prefix to get the relative pass path
|
||||
pass_path = path[len(arguments.password_store):]
|
||||
split_path = pass_path.split(os.path.sep)
|
||||
idna_split_path = [idna_encode(part) for part in split_path]
|
||||
for secret in secrets:
|
||||
secret_base = os.path.splitext(secret)[0]
|
||||
idna_secret_base = idna_encode(secret_base)
|
||||
if not unfiltered and idna_domain not in (idna_split_path + [idna_secret_base]):
|
||||
continue
|
||||
|
||||
# Append the unencoded Unicode path/name since this is how pass uses them
|
||||
candidates.append(os.path.join(pass_path, secret_base))
|
||||
return candidates
|
||||
|
||||
|
||||
def _run_pass(pass_arguments):
|
||||
# The executable is conveniently named after it's mode [pass|gopass].
|
||||
pass_command = [arguments.mode]
|
||||
env = os.environ.copy()
|
||||
env['PASSWORD_STORE_DIR'] = arguments.password_store
|
||||
process = subprocess.run(pass_command + pass_arguments, env=env, stdout=subprocess.PIPE)
|
||||
return process.stdout.decode(arguments.io_encoding).strip()
|
||||
|
||||
|
||||
def pass_(path):
|
||||
return _run_pass(['show', path])
|
||||
|
||||
|
||||
def pass_otp(path):
|
||||
if arguments.mode == "gopass":
|
||||
return _run_pass(['otp', '-o', path])
|
||||
return _run_pass(['otp', path])
|
||||
|
||||
|
||||
def dmenu(items, invocation):
|
||||
command = shlex.split(invocation)
|
||||
process = subprocess.run(command, input='\n'.join(items).encode(arguments.io_encoding), stdout=subprocess.PIPE)
|
||||
return process.stdout.decode(arguments.io_encoding).strip()
|
||||
|
||||
|
||||
def fake_key_raw(text):
|
||||
for character in text:
|
||||
# Escape all characters by default, space requires special handling
|
||||
sequence = '" "' if character == ' ' else r'\{}'.format(character)
|
||||
qute_command('fake-key {}'.format(sequence))
|
||||
|
||||
|
||||
def extract_password(secret, pattern):
|
||||
match = re.match(pattern, secret)
|
||||
if not match:
|
||||
raise CouldNotMatchPassword("Pattern did not match target")
|
||||
try:
|
||||
return match.group(1)
|
||||
except IndexError:
|
||||
raise CouldNotMatchPassword("Pattern did not contain capture group, please use capture group. Example: (.*)")
|
||||
|
||||
|
||||
def extract_username(target, pattern):
|
||||
match = re.search(pattern, target, re.MULTILINE)
|
||||
if not match:
|
||||
raise CouldNotMatchUsername("Pattern did not match target")
|
||||
try:
|
||||
return match.group(1)
|
||||
except IndexError:
|
||||
raise CouldNotMatchUsername("Pattern did not contain capture group, please use capture group. Example: (.*)")
|
||||
|
||||
|
||||
def main(arguments):
|
||||
if not arguments.url:
|
||||
argument_parser.print_help()
|
||||
return ExitCodes.FAILURE
|
||||
|
||||
extractor = tldextract.TLDExtract(extra_suffixes=arguments.extra_url_suffixes.split(','))
|
||||
extract_result = extractor(arguments.url)
|
||||
|
||||
# Try to find candidates using targets in the following order: fully-qualified domain name (includes subdomains),
|
||||
# the registered domain name, the IPv4 address if that's what the URL represents and finally the private domain
|
||||
# (if a non-public suffix was used), and the URL netloc.
|
||||
candidates = set()
|
||||
attempted_targets = []
|
||||
|
||||
private_domain = ''
|
||||
if not extract_result.suffix:
|
||||
private_domain = ('.'.join((extract_result.subdomain, extract_result.domain))
|
||||
if extract_result.subdomain else extract_result.domain)
|
||||
|
||||
netloc = urlparse(arguments.url).netloc
|
||||
|
||||
for target in filter(None, [extract_result.fqdn, extract_result.registered_domain, extract_result.ipv4, private_domain, netloc]):
|
||||
attempted_targets.append(target)
|
||||
target_candidates = find_pass_candidates(target, unfiltered=arguments.unfiltered)
|
||||
if not target_candidates:
|
||||
continue
|
||||
|
||||
candidates.update(target_candidates)
|
||||
if not arguments.merge_candidates:
|
||||
break
|
||||
else:
|
||||
if not candidates:
|
||||
stderr('No pass candidates for URL {!r} found! (I tried {!r})'.format(arguments.url, attempted_targets))
|
||||
return ExitCodes.NO_PASS_CANDIDATES
|
||||
|
||||
if len(candidates) == 1 and not arguments.always_show_selection:
|
||||
selection = candidates.pop()
|
||||
else:
|
||||
selection = dmenu(sorted(candidates), arguments.dmenu_invocation)
|
||||
|
||||
# Nothing was selected, simply return
|
||||
if not selection:
|
||||
return ExitCodes.SUCCESS
|
||||
|
||||
# If username-target is path and user asked for username-only, we don't need to run pass.
|
||||
# Or if using otp-only, it will run pass on its own.
|
||||
secret = None
|
||||
if not (arguments.username_target == 'path' and arguments.username_only) and not arguments.otp_only:
|
||||
secret = pass_(selection)
|
||||
username_target = selection if arguments.username_target == 'path' else secret
|
||||
try:
|
||||
if arguments.username_only:
|
||||
fake_key_raw(extract_username(username_target, arguments.username_pattern))
|
||||
elif arguments.password_only:
|
||||
fake_key_raw(extract_password(secret, arguments.password_pattern))
|
||||
elif arguments.otp_only:
|
||||
otp = pass_otp(selection)
|
||||
fake_key_raw(otp)
|
||||
else:
|
||||
# Enter username and password using fake-key and <Tab> (which seems to work almost universally), then switch
|
||||
# back into insert-mode, so the form can be directly submitted by hitting enter afterwards
|
||||
fake_key_raw(extract_username(username_target, arguments.username_pattern))
|
||||
qute_command('fake-key <Tab>')
|
||||
fake_key_raw(extract_password(secret, arguments.password_pattern))
|
||||
except CouldNotMatchPassword as e:
|
||||
stderr('Failed to match password, target: secret, error: {}'.format(e))
|
||||
return ExitCodes.COULD_NOT_MATCH_PASSWORD
|
||||
except CouldNotMatchUsername as e:
|
||||
stderr('Failed to match username, target: {}, error: {}'.format(arguments.username_target, e))
|
||||
return ExitCodes.COULD_NOT_MATCH_USERNAME
|
||||
|
||||
if arguments.insert_mode:
|
||||
qute_command('mode-enter insert')
|
||||
|
||||
return ExitCodes.SUCCESS
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
arguments = argument_parser.parse_args()
|
||||
sys.exit(main(arguments))
|
||||
900
home/.local/usr/bin/rofi-pass
Executable file
900
home/.local/usr/bin/rofi-pass
Executable file
@@ -0,0 +1,900 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# rofi-pass
|
||||
# (c) 2015 Rasmus Steinke <rasi@xssn.at>
|
||||
basecommand="$0"
|
||||
|
||||
# set default settings
|
||||
_rofi () {
|
||||
rofi -no-auto-select -i "$@"
|
||||
}
|
||||
|
||||
_pwgen () {
|
||||
pwgen -y "$@"
|
||||
}
|
||||
|
||||
_image_viewer () {
|
||||
feh -
|
||||
}
|
||||
|
||||
_clip_in_primary() {
|
||||
xclip
|
||||
}
|
||||
|
||||
_clip_in_clipboard() {
|
||||
xclip -selection clipboard
|
||||
}
|
||||
|
||||
_clip_out_primary() {
|
||||
xclip -o
|
||||
}
|
||||
|
||||
_clip_out_clipboard() {
|
||||
xclip --selection clipboard -o
|
||||
}
|
||||
|
||||
export PASSWORD_STORE_DIR="${HOME}/.passwords/"
|
||||
config_dir=${XDG_CONFIG_HOME:-$HOME/.config}
|
||||
cache_dir=${XDG_CACHE_HOME:-$HOME/.cache}
|
||||
|
||||
# We expect to find these fields in pass(1)'s output
|
||||
URL_field='url'
|
||||
USERNAME_field='user'
|
||||
AUTOTYPE_field='autotype'
|
||||
OTPmethod_field='otp_method'
|
||||
|
||||
default_autotype="user :tab pass"
|
||||
delay=2
|
||||
wait=0.2
|
||||
xdotool_delay=12
|
||||
default_do='menu' # menu, copyPass, typeUser, typePass, copyUser, copyUrl, viewEntry, typeMenu, actionMenu, copyMenu, openUrl
|
||||
auto_enter='false'
|
||||
notify='false'
|
||||
help_color=""
|
||||
clip=primary
|
||||
clip_clear=45
|
||||
default_user="${ROFI_PASS_DEFAULT_USER-$(whoami)}"
|
||||
default_user2=john_doe
|
||||
password_length=12
|
||||
fix_layout=false
|
||||
|
||||
# default shortcuts
|
||||
autotype="Alt+1"
|
||||
type_user="Alt+2"
|
||||
type_pass="Alt+3"
|
||||
open_url="Alt+4"
|
||||
copy_name="Alt+u"
|
||||
copy_url="Alt+l"
|
||||
copy_pass="Alt+p"
|
||||
show="Alt+o"
|
||||
copy_menu="Alt+c"
|
||||
action_menu="Alt+a"
|
||||
type_menu="Alt+t"
|
||||
help="Alt+h"
|
||||
switch="Alt+x"
|
||||
insert_pass="Alt+n"
|
||||
qrcode="Alt+q"
|
||||
previous_root="Shift+Left"
|
||||
next_root="Shift+Right"
|
||||
|
||||
# Safe permissions
|
||||
umask 077
|
||||
|
||||
has_qrencode() {
|
||||
command -v qrencode >/dev/null 2>&1
|
||||
}
|
||||
|
||||
listgpg () {
|
||||
mapfile -d '' pw_list < <(find -L . -name '*.gpg' -print0)
|
||||
pw_list=("${pw_list[@]#./}")
|
||||
printf '%s\n' "${pw_list[@]}" | sort -n
|
||||
}
|
||||
|
||||
# get all password files and output as newline-delimited text
|
||||
list_passwords() {
|
||||
cd "${root}" || exit
|
||||
mapfile -t pw_list < <(listgpg)
|
||||
printf '%s\n' "${pw_list[@]%.gpg}" | sort -n
|
||||
}
|
||||
|
||||
doClip () {
|
||||
case "$clip" in
|
||||
"primary") _clip_in_primary ;;
|
||||
"clipboard") _clip_in_clipboard ;;
|
||||
"both") _clip_in_primary; _clip_out_primary | _clip_in_clipboard;;
|
||||
esac
|
||||
}
|
||||
|
||||
checkIfPass () {
|
||||
printf '%s\n' "${root}: $selected_password" >| "$cache_dir/rofi-pass/last_used"
|
||||
}
|
||||
|
||||
|
||||
autopass () {
|
||||
x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
|
||||
xset r off
|
||||
|
||||
rm -f "$cache_dir/rofi-pass/last_used"
|
||||
printf '%s\n' "${root}: $selected_password" > "$cache_dir/rofi-pass/last_used"
|
||||
for word in ${stuff["$AUTOTYPE_field"]}; do
|
||||
case "$word" in
|
||||
":tab") xdotool key Tab;;
|
||||
":space") xdotool key space;;
|
||||
":delay") sleep "${delay}";;
|
||||
":enter") xdotool key Return;;
|
||||
":otp") printf '%s' "$(generateOTP)" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -;;
|
||||
"pass") printf '%s' "${password}" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -;;
|
||||
"path") printf '%s' "${selected_password}" | rev | cut -d'/' -f1 | rev | xdotool type --clearmodifiers --file -;;
|
||||
*) printf '%s' "${stuff[${word}]}" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ${auto_enter} == "true" ]]; then
|
||||
xdotool key Return
|
||||
fi
|
||||
|
||||
xset r "$x_repeat_enabled"
|
||||
unset x_repeat_enabled
|
||||
clearUp
|
||||
}
|
||||
|
||||
generateQrCode() {
|
||||
has_qrencode
|
||||
|
||||
if [[ $? -eq "1" ]]; then
|
||||
printf '%s\n' "qrencode not found" | _rofi -dmenu
|
||||
exit_code=$?
|
||||
if [[ $exit_code -eq "1" ]]; then
|
||||
exit
|
||||
else
|
||||
"${basecommand}"
|
||||
fi
|
||||
fi
|
||||
|
||||
checkIfPass
|
||||
pass "$selected_password" | head -n 1 | qrencode -d 300 -v 8 -l H -o - | _image_viewer
|
||||
if [[ $? -eq "1" ]]; then
|
||||
printf '%s\n' "" | _rofi -dmenu -mesg "Image viewer not defined or cannot read from pipe"
|
||||
exit_value=$?
|
||||
if [[ $exit_value -eq "1" ]]; then
|
||||
exit
|
||||
else
|
||||
"${basecommand}"
|
||||
fi
|
||||
fi
|
||||
clearUp
|
||||
}
|
||||
|
||||
openURL () {
|
||||
checkIfPass
|
||||
$BROWSER "$(PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep "${URL_field}: " | gawk '{sub(/:/,"")}{print $2}1' | head -1)"; exit;
|
||||
clearUp
|
||||
}
|
||||
|
||||
typeUser () {
|
||||
checkIfPass
|
||||
|
||||
x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
|
||||
xset r off
|
||||
|
||||
printf '%s' "${stuff[${USERNAME_field}]}" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -
|
||||
|
||||
xset r "$x_repeat_enabled"
|
||||
unset x_repeat_enabled
|
||||
|
||||
clearUp
|
||||
}
|
||||
|
||||
typePass () {
|
||||
checkIfPass
|
||||
|
||||
x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
|
||||
xset r off
|
||||
|
||||
printf '%s' "${password}" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -
|
||||
|
||||
if [[ $notify == "true" ]]; then
|
||||
if [[ "${stuff[notify]}" == "false" ]]; then
|
||||
:
|
||||
else
|
||||
notify-send "rofi-pass" "finished typing password";
|
||||
fi
|
||||
elif [[ $notify == "false" ]]; then
|
||||
if [[ "${stuff[notify]}" == "true" ]]; then
|
||||
notify-send "rofi-pass" "finished typing password";
|
||||
else
|
||||
:
|
||||
fi
|
||||
fi
|
||||
|
||||
xset r "$x_repeat_enabled"
|
||||
unset x_repeat_enabled
|
||||
clearUp
|
||||
}
|
||||
|
||||
typeField () {
|
||||
checkIfPass
|
||||
local to_type
|
||||
|
||||
x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
|
||||
xset r off
|
||||
|
||||
case $typefield in
|
||||
"OTP") to_type="$(generateOTP)" ;;
|
||||
*) to_type="${stuff[${typefield}]}" ;;
|
||||
esac
|
||||
|
||||
printf '%s' "$to_type" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -
|
||||
|
||||
xset r "$x_repeat_enabled"
|
||||
unset x_repeat_enabled
|
||||
unset to_type
|
||||
|
||||
clearUp
|
||||
}
|
||||
|
||||
generateOTP () {
|
||||
checkIfPass
|
||||
|
||||
# First, we check if there is a non-conventional OTP command in the pass file
|
||||
if PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep -q "${OTPmethod_field}: "; then
|
||||
# We execute the commands after otp_method: AS-IS
|
||||
bash -c "$(PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep "${OTPmethod_field}: " | cut -d' ' -f2-)"
|
||||
else
|
||||
# If there is no method defined, fallback to pass-otp
|
||||
PASSWORD_STORE_DIR="${root}" pass otp "$selected_password"
|
||||
fi
|
||||
|
||||
clearUp
|
||||
}
|
||||
|
||||
copyUser () {
|
||||
checkIfPass
|
||||
printf '%s' "${stuff[${USERNAME_field}]}" | doClip
|
||||
clearUp
|
||||
}
|
||||
|
||||
copyField () {
|
||||
checkIfPass
|
||||
printf '%s' "${stuff[${copyfield}]}" | doClip
|
||||
clearUp
|
||||
}
|
||||
|
||||
copyURL () {
|
||||
checkIfPass
|
||||
printf '%s' "${stuff[${URL_field}]}" | doClip
|
||||
clearUp
|
||||
}
|
||||
|
||||
copyPass () {
|
||||
checkIfPass
|
||||
printf '%s' "$password" | doClip
|
||||
if [[ $notify == "true" ]]; then
|
||||
notify-send "rofi-pass" "Copied Password\\nClearing in $clip_clear seconds"
|
||||
fi
|
||||
|
||||
if [[ $notify == "true" ]]; then
|
||||
(sleep $clip_clear; printf '%s' "" | _clip_in_primary; printf '%s' "" | _clip_in_clipboard | notify-send "rofi-pass" "Clipboard cleared") &
|
||||
elif [[ $notify == "false" ]]; then
|
||||
(sleep $clip_clear; printf '%s' "" | _clip_in_primary; printf '%s' "" | _clip_in_clipboard) &
|
||||
fi
|
||||
}
|
||||
|
||||
viewEntry () {
|
||||
checkIfPass
|
||||
showEntry "${selected_password}"
|
||||
}
|
||||
|
||||
generatePass () {
|
||||
askmenu_content=(
|
||||
"Yes"
|
||||
"No"
|
||||
)
|
||||
|
||||
askGenMenu=$(printf '%s\n' "${askmenu_content[@]}" | _rofi -dmenu -p "Generate new Password for ${selected_password}? > ")
|
||||
askgen_exit=$?
|
||||
|
||||
if [[ $askgen_exit -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
if [[ $askGenMenu == "Yes" ]]; then
|
||||
true
|
||||
elif [[ $askGenMenu == "No" ]]; then
|
||||
actionMenu
|
||||
fi
|
||||
|
||||
checkIfPass
|
||||
|
||||
symbols_content=(
|
||||
"0 Cancel"
|
||||
"1 Yes"
|
||||
"2 No"
|
||||
)
|
||||
|
||||
symbols=$(printf '%s\n' "${symbols_content[@]}" | _rofi -dmenu -p "Use Symbols? > ")
|
||||
symbols_val=$?
|
||||
|
||||
if [[ $symbols_val -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
if [[ $symbols == "0 Cancel" ]]; then
|
||||
mainMenu;
|
||||
elif [[ $symbols == "1 Yes" ]]; then
|
||||
symbols="";
|
||||
elif [[ $symbols == "2 No" ]]; then
|
||||
symbols="-n";
|
||||
fi
|
||||
|
||||
HELP="<span color='$help_color'>Enter Number or hit Enter to use default length</span>"
|
||||
length=$(printf '%s' "" | _rofi -dmenu -mesg "${HELP}" -p "Password length? (Default: ${password_length}) > ")
|
||||
length_exit=$?
|
||||
|
||||
if [[ $length_exit -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
if [[ $length == "" ]]; then
|
||||
PASSWORD_STORE_DIR="${root}" pass generate ${symbols} -i "$selected_password" "${password_length}" > /dev/null;
|
||||
else
|
||||
PASSWORD_STORE_DIR="${root}" pass generate ${symbols} -i "$selected_password" "${length}" > /dev/null;
|
||||
fi
|
||||
}
|
||||
|
||||
# main Menu
|
||||
mainMenu () {
|
||||
if [[ $1 == "--bmarks" ]]; then
|
||||
selected_password="$(list_passwords 2>/dev/null \
|
||||
| _rofi -mesg "Bookmarks Mode. ${switch} to switch" \
|
||||
-dmenu \
|
||||
-kb-custom-10 "${switch}" \
|
||||
-select "$entry" \
|
||||
-p "rofi-pass > ")"
|
||||
|
||||
rofi_exit=$?
|
||||
|
||||
if [[ $rofi_exit -eq 1 ]]; then
|
||||
exit
|
||||
elif [[ $rofi_exit -eq 19 ]]; then
|
||||
${basecommand}
|
||||
elif [[ $rofi_exit -eq 0 ]]; then
|
||||
openURL
|
||||
fi
|
||||
else
|
||||
unset selected_password
|
||||
|
||||
args=( -dmenu
|
||||
-kb-custom-1 "${autotype}"
|
||||
-kb-custom-2 "${type_user}"
|
||||
-kb-custom-3 "${type_pass}"
|
||||
-kb-custom-4 "${open_url}"
|
||||
-kb-custom-5 "${copy_name}"
|
||||
-kb-custom-6 "${copy_pass}"
|
||||
-kb-custom-7 "${show}"
|
||||
-kb-custom-8 "${copy_url}"
|
||||
-kb-custom-9 "${type_menu}"
|
||||
-kb-custom-10 "${previous_root}"
|
||||
-kb-custom-11 "${next_root}"
|
||||
-kb-custom-14 "${action_menu}"
|
||||
-kb-custom-15 "${copy_menu}"
|
||||
-kb-custom-16 "${help}"
|
||||
-kb-custom-17 "${switch}"
|
||||
-kb-custom-18 "${insert_pass}"
|
||||
-kb-custom-19 "${qrcode}"
|
||||
)
|
||||
args+=( -kb-mode-previous "" # These keyboard shortcut options are needed, because
|
||||
-kb-mode-next "" # Shift+<Left|Right> are otherwise taken by rofi.
|
||||
-select "$entry"
|
||||
-p "> " )
|
||||
|
||||
if [[ ${#roots[@]} -gt "1" || $custom_root == "true" ]]; then
|
||||
args+=(-mesg "PW Store: ${root}")
|
||||
fi
|
||||
|
||||
selected_password="$(list_passwords 2>/dev/null | _rofi "${args[@]}")"
|
||||
|
||||
rofi_exit=$?
|
||||
if [[ $rofi_exit -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
# Actions based on exit code, which do not need the entry.
|
||||
# The exit code for -kb-custom-X is X+9.
|
||||
case "${rofi_exit}" in
|
||||
19) roots_index=$(( (roots_index-1+roots_length) % roots_length)); root=${roots[$roots_index]}; mainMenu; return;;
|
||||
20) roots_index=$(( (roots_index+1) % roots_length)); root=${roots[$roots_index]}; mainMenu; return;;
|
||||
25) helpMenu; return;;
|
||||
26) ${basecommand} --bmarks; return;;
|
||||
esac
|
||||
|
||||
mapfile -t password_temp < <(PASSWORD_STORE_DIR="${root}" pass show "$selected_password")
|
||||
password=${password_temp[0]}
|
||||
|
||||
if [[ ${password} == "#FILE="* ]]; then
|
||||
pass_file="${password#*=}"
|
||||
mapfile -t password_temp2 < <(PASSWORD_STORE_DIR="${root}" pass show "${pass_file}")
|
||||
password=${password_temp2[0]}
|
||||
fi
|
||||
|
||||
fields=$(printf '%s\n' "${password_temp[@]:1}" | awk '$1 ~ /:$/ || /otpauth:\/\// {$1=$1;print}')
|
||||
declare -A stuff
|
||||
stuff["pass"]=${password}
|
||||
|
||||
if [[ -n $fields ]]; then
|
||||
while read -r LINE; do
|
||||
unset _id _val
|
||||
case "$LINE" in
|
||||
"otpauth://"*|"${OTPmethod_field}"*)
|
||||
_id="OTP"
|
||||
_val=""
|
||||
;;
|
||||
*)
|
||||
_id="${LINE%%: *}"
|
||||
_val="${LINE#* }"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ -n "$_id" ]]; then
|
||||
stuff["${_id}"]=${_val}
|
||||
fi
|
||||
done < <(printf '%s\n' "${fields}")
|
||||
|
||||
if test "${stuff['autotype']+autotype}"; then
|
||||
:
|
||||
else
|
||||
stuff["autotype"]="${USERNAME_field} :tab pass"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "${stuff["${AUTOTYPE_field}"]}" ]]; then
|
||||
if [[ -n $default_autotype ]]; then
|
||||
stuff["${AUTOTYPE_field}"]="${default_autotype}"
|
||||
fi
|
||||
fi
|
||||
if [[ -z "${stuff["${USERNAME_field}"]}" ]]; then
|
||||
if [[ -n $default_user ]]; then
|
||||
if [[ "$default_user" == ":filename" ]]; then
|
||||
stuff["${USERNAME_field}"]="$(basename "$selected_password")"
|
||||
else
|
||||
stuff["${USERNAME_field}"]="${default_user}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
pass_content="$(for key in "${!stuff[@]}"; do printf '%s\n' "${key}: ${stuff[$key]}"; done)"
|
||||
|
||||
# actions based on keypresses
|
||||
# The exit code for -kb-custom-X is X+9.
|
||||
case "${rofi_exit}" in
|
||||
0) typeMenu;;
|
||||
10) sleep $wait; autopass;;
|
||||
11) sleep $wait; typeUser;;
|
||||
12) sleep $wait; typePass;;
|
||||
13) openURL;;
|
||||
14) copyUser;;
|
||||
15) copyPass;;
|
||||
16) viewEntry;;
|
||||
17) copyURL;;
|
||||
18) default_do="menu" typeMenu;;
|
||||
23) actionMenu;;
|
||||
24) copyMenu;;
|
||||
27) insertPass;;
|
||||
28) generateQrCode;;
|
||||
esac
|
||||
clearUp
|
||||
}
|
||||
|
||||
|
||||
clearUp () {
|
||||
password=''
|
||||
selected_password=''
|
||||
unset stuff
|
||||
unset password
|
||||
unset selected_password
|
||||
unset password_temp
|
||||
unset stuff
|
||||
}
|
||||
|
||||
helpMenu () {
|
||||
_rofi -dmenu -mesg "Hint: All hotkeys are configurable in config file" -p "Help > " <<- EOM
|
||||
${autotype}: Autotype
|
||||
${type_user}: Type Username
|
||||
${type_pass}: Type Password
|
||||
${qrcode}: Generate and display qrcode
|
||||
---
|
||||
${copy_name}: Copy Username
|
||||
${copy_pass}: Copy Password
|
||||
${copy_url}: Copy URL
|
||||
${open_url}: Open URL
|
||||
${copy_menu}: Copy Custom Field
|
||||
---
|
||||
${action_menu}: Edit, Move, Delete, Re-generate Submenu
|
||||
${show}: Show Password File
|
||||
${insert_pass}: Insert new Pass Entry
|
||||
${switch}: Switch Pass/Bookmark Mode
|
||||
---
|
||||
${previous_root}: Switch to previous password store (--root)
|
||||
${next_root}: Switch to next password store (--root)
|
||||
EOM
|
||||
help_val=$?
|
||||
|
||||
if [[ $help_val -eq 1 ]]; then
|
||||
exit;
|
||||
else
|
||||
unset helptext; mainMenu;
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
typeMenu () {
|
||||
if [[ -n $default_do ]]; then
|
||||
if [[ $default_do == "menu" ]]; then
|
||||
checkIfPass
|
||||
local -a keys=("${!stuff[@]}")
|
||||
keys=("${keys[@]/$AUTOTYPE_field}")
|
||||
typefield=$({ printf '%s' "${AUTOTYPE_field}" ; printf '%s\n' "${keys[@]}" | sort; } | _rofi -dmenu -p "Choose Field to type > ")
|
||||
typefield_exit=$?
|
||||
if [[ $typefield_exit -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
case "$typefield" in
|
||||
'') exit;;
|
||||
'pass') sleep $wait; typePass;;
|
||||
"${AUTOTYPE_field}") sleep $wait; autopass;;
|
||||
*) sleep $wait; typeField
|
||||
esac
|
||||
clearUp
|
||||
elif [[ $default_do == "${AUTOTYPE_field}" ]]; then
|
||||
sleep $wait; autopass
|
||||
else
|
||||
${default_do}
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
copyMenu () {
|
||||
checkIfPass
|
||||
copyfield=$(printf '%s\n' "${!stuff[@]}" | sort | _rofi -dmenu -p "Choose Field to copy > ")
|
||||
val=$?
|
||||
if [[ $val -eq 1 ]]; then
|
||||
exit;
|
||||
fi
|
||||
if [[ $copyfield == "pass" ]]; then
|
||||
copyPass;
|
||||
else
|
||||
copyField
|
||||
fi
|
||||
clearUp
|
||||
}
|
||||
|
||||
actionMenu () {
|
||||
checkIfPass
|
||||
action_content=("< Return"
|
||||
"---"
|
||||
"1 Move Password File"
|
||||
"2 Copy Password File"
|
||||
"3 Delete Password File"
|
||||
"4 Edit Password File"
|
||||
"5 Generate New Password"
|
||||
)
|
||||
|
||||
action=$(printf '%s\n' "${action_content[@]}" | _rofi -dmenu -p "Choose Action > ")
|
||||
if [[ ${action} == "1 Move Password File" ]]; then
|
||||
manageEntry move;
|
||||
elif [[ ${action} == "3 Delete Password File" ]]; then
|
||||
manageEntry delete;
|
||||
elif [[ ${action} == "2 Copy Password File" ]]; then
|
||||
manageEntry copy;
|
||||
elif [[ ${action} == "4 Edit Password File" ]]; then
|
||||
manageEntry edit;
|
||||
elif [[ ${action} == "5 Generate New Password" ]]; then
|
||||
generatePass;
|
||||
elif [[ ${action} == "< Return" ]]; then
|
||||
mainMenu;
|
||||
elif [[ ${action} == "" ]]; then
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
showEntry () {
|
||||
if [[ -z $pass_content ]]; then
|
||||
pass_temp=$(PASSWORD_STORE_DIR="${root}" pass show "$selected_password")
|
||||
password="${pass_temp%%$'\n'*}"
|
||||
pass_key_value=$(printf '%s\n' "${pass_temp}" | tail -n+2 | grep ': ')
|
||||
declare -A stuff
|
||||
|
||||
while read -r LINE; do
|
||||
_id="${LINE%%: *}"
|
||||
_val="${LINE#* }"
|
||||
stuff["${_id}"]=${_val}
|
||||
done < <(printf '%s\n' "${pass_key_value}")
|
||||
|
||||
stuff["pass"]=${password}
|
||||
|
||||
if test "${stuff['autotype']+autotype}"; then
|
||||
:
|
||||
else
|
||||
stuff["autotype"]="${USERNAME_field} :tab pass"
|
||||
fi
|
||||
|
||||
pass_content="$(for key in "${!stuff[@]}"; do printf '%s\n' "${key}: ${stuff[$key]}"; done)"
|
||||
fi
|
||||
|
||||
bla_content=("< Return"
|
||||
"${pass_content}"
|
||||
)
|
||||
|
||||
bla=$(printf '%s\n' "${bla_content[@]}" | _rofi -dmenu -mesg "Enter: Copy entry to clipboard" -p "> ")
|
||||
rofi_exit=$?
|
||||
|
||||
word=$(printf '%s' "$bla" | gawk -F': ' '{print $1}')
|
||||
|
||||
if [[ ${rofi_exit} -eq 1 ]]; then
|
||||
exit
|
||||
elif [[ ${rofi_exit} -eq 0 ]]; then
|
||||
if [[ ${bla} == "< Return" ]]; then
|
||||
mainMenu
|
||||
else
|
||||
if [[ -z $(printf '%s' "${stuff[${word}]}") ]]; then
|
||||
printf '%s' "$word" | doClip
|
||||
else
|
||||
printf '%s' "${stuff[${word}]}" | doClip
|
||||
fi
|
||||
if [[ $notify == "true" ]]; then
|
||||
notify-send "rofi-pass" "Copied Password\\nClearing in $clip_clear seconds"
|
||||
fi
|
||||
if [[ $notify == "true" ]]; then
|
||||
(sleep $clip_clear; printf '%s' "" | _clip_in_primary; printf '%s' "" | _clip_in_clipboard | notify-send "rofi-pass" "Clipboard cleared") &
|
||||
elif [[ $notify == "false" ]]; then
|
||||
(sleep $clip_clear; printf '%s' "" | _clip_in_primary; printf '%s' "" | _clip_in_clipboard) &
|
||||
fi
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
exit
|
||||
unset stuff
|
||||
unset password
|
||||
unset selected_password
|
||||
unset password_temp
|
||||
unset stuff
|
||||
exit
|
||||
}
|
||||
|
||||
manageEntry () {
|
||||
if [[ "$1" == "edit" ]]; then
|
||||
EDITOR=$EDITOR PASSWORD_STORE_DIR="${root}" pass edit "${selected_password}"
|
||||
mainMenu
|
||||
elif [[ $1 == "move" ]]; then
|
||||
cd "${root}" || exit
|
||||
group_array=(*/)
|
||||
group=$(printf '%s\n' "${group_array[@]%/}" | _rofi -dmenu -p "Choose Group > ")
|
||||
if [[ $group == "" ]]; then
|
||||
exit
|
||||
fi
|
||||
PASSWORD_STORE_DIR="${root}" pass mv "$selected_password" "${group}"
|
||||
mainMenu
|
||||
elif [[ $1 == "copy" ]]; then
|
||||
cd "${root}" || exit
|
||||
group_array=(*/)
|
||||
group=$(printf '%s\n' "${group_array[@]%/}" | _rofi -dmenu -p "Choose Group > ")
|
||||
if [[ $group == "" ]]; then
|
||||
exit
|
||||
else
|
||||
new_name="$(listgpg | _rofi -dmenu -format 'f' -mesg "Copying to same Group. Please enter a name for the new entry" -p "> ")"
|
||||
fi
|
||||
PASSWORD_STORE_DIR="${root}" pass cp "$selected_password" "${group}/${new_name}"
|
||||
mainMenu
|
||||
elif [[ "$1" == "delete" ]]; then
|
||||
HELP="<span color='$help_color'>Selected entry: ${selected_password}</span>"
|
||||
ask_content=("Yes"
|
||||
"No"
|
||||
)
|
||||
ask=$(printf '%s\n' "${ask_content[@]}" | _rofi -mesg "${HELP}" -dmenu -p "Are You Sure? > ")
|
||||
if [[ "$ask" == "Yes" ]]; then
|
||||
PASSWORD_STORE_DIR="${root}" pass rm --force "${selected_password}"
|
||||
elif [[ "$ask" == "No" ]]; then
|
||||
mainMenu
|
||||
elif [[ -z "$ask" ]]; then
|
||||
exit
|
||||
fi
|
||||
else
|
||||
mainMenu
|
||||
fi
|
||||
}
|
||||
|
||||
edit_pass() {
|
||||
if [[ $edit_new_pass == "true" ]]; then
|
||||
PASSWORD_STORE_DIR="${root}" pass edit "${1}"
|
||||
fi
|
||||
}
|
||||
|
||||
insertPass () {
|
||||
url=$(_clip_out_clipboard)
|
||||
|
||||
if [[ "${url:0:4}" == "http" ]]; then
|
||||
domain_name="$(printf '%s\n' "${url}" | awk -F / '{l=split($3,a,"."); print (a[l-1]=="com"?a[l-2] OFS:X) a[l-1] OFS a[l]}' OFS=".")"
|
||||
help_content="Domain: ${domain_name}
|
||||
Type name, make sure it is unique"
|
||||
else
|
||||
help_content="Hint: Copy URL to clipboard before calling this menu.
|
||||
Type name, make sure it is unique"
|
||||
fi
|
||||
|
||||
cd "${root}" || exit
|
||||
group_array=(*/)
|
||||
grouplist=$(printf '%s\n' "${group_array[@]%/}")
|
||||
name="$(listgpg | _rofi -dmenu -format 'f' -filter "${domain_name}" -mesg "${help_content}" -p "> ")"
|
||||
val=$?
|
||||
|
||||
if [[ $val -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
user_content=("${default_user2}"
|
||||
"${USER}"
|
||||
"${default_user}"
|
||||
)
|
||||
|
||||
user=$(printf '%s\n' "${user_content[@]}" | _rofi -dmenu -mesg "Chose Username or type" -p "> ")
|
||||
val=$?
|
||||
|
||||
if [[ $val -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
group_content=("No Group"
|
||||
"---"
|
||||
"${grouplist}"
|
||||
)
|
||||
|
||||
group=$(printf '%s\n' "${group_content[@]}" | _rofi -dmenu -p "Choose Group > ")
|
||||
val=$?
|
||||
|
||||
if [[ $val -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
pw=$(printf '%s' "Generate" | _rofi -dmenu -password -p "Password > " -mesg "Type Password or hit Enter to generate one")
|
||||
|
||||
if [[ $pw == "Generate" ]]; then
|
||||
pw=$(_pwgen "${password_length}")
|
||||
fi
|
||||
|
||||
clear
|
||||
|
||||
if [[ "$group" == "No Group" ]]; then
|
||||
if [[ $url == http* ]]; then
|
||||
pass_content=("${pw}"
|
||||
"---"
|
||||
"${USERNAME_field}: ${user}"
|
||||
"${URL_field}: ${url}"
|
||||
)
|
||||
printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${name}" > /dev/null && edit_pass "${name}"
|
||||
else
|
||||
pass_content=("${pw}"
|
||||
"---"
|
||||
"${USERNAME_field}: ${user}"
|
||||
)
|
||||
printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${name}" > /dev/null && edit_pass "${name}"
|
||||
fi
|
||||
else
|
||||
if [[ $url == http* ]]; then
|
||||
pass_content=("${pw}"
|
||||
"---"
|
||||
"${USERNAME_field}: ${user}"
|
||||
"${URL_field}: ${url}"
|
||||
)
|
||||
printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${group}/${name}" > /dev/null && edit_pass "${group}/${name}"
|
||||
else
|
||||
pass_content=("${pw}"
|
||||
"---"
|
||||
"${USERNAME_field}: ${user}"
|
||||
)
|
||||
printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${group}/${name}" > /dev/null && edit_pass "${group}/${name}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
help_msg () {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
rofi-pass [command]
|
||||
|
||||
Commands:
|
||||
--insert insert new entry to password store
|
||||
--root set custom root directories (colon separated)
|
||||
--last-used highlight last used item
|
||||
--show-last show details of last used Entry
|
||||
--bmarks start in bookmarks mode
|
||||
|
||||
rofi-pass version 1.5.3
|
||||
EOF
|
||||
}
|
||||
|
||||
get_config_file () {
|
||||
configs=("$ROFI_PASS_CONFIG"
|
||||
"$config_dir/rofi-pass/config"
|
||||
"/etc/rofi-pass.conf")
|
||||
|
||||
# return the first config file with a valid path
|
||||
for config in "${configs[@]}"; do
|
||||
# '-n' is needed in case ROFI_PASS_CONFIG is not set
|
||||
if [[ -n "${config}" && -f "${config}" ]]; then
|
||||
printf "%s" "$config"
|
||||
return
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
main () {
|
||||
# load config file
|
||||
config_file="$(get_config_file)"
|
||||
[[ -n "$config_file" ]] && source "$config_file"
|
||||
|
||||
# create tmp dir
|
||||
if [[ ! -d "$cache_dir/rofi-pass" ]]; then
|
||||
mkdir -p "$cache_dir/rofi-pass"
|
||||
fi
|
||||
|
||||
# fix keyboard layout if enabled in config
|
||||
if [[ $fix_layout == "true" ]]; then
|
||||
layout_cmd
|
||||
fi
|
||||
|
||||
# set help color
|
||||
if [[ $help_color == "" ]]; then
|
||||
help_color=$(rofi -dump-xresources | grep 'rofi.color.normal' | gawk -F ',' '/,/{gsub(/ /, "", $2); print $2}')
|
||||
fi
|
||||
|
||||
# check for BROWSER variable, use xdg-open as fallback
|
||||
if [[ -z $BROWSER ]]; then
|
||||
export BROWSER=xdg-open
|
||||
fi
|
||||
|
||||
# check if alternative root directory was given on commandline
|
||||
if [[ -r "$cache_dir/rofi-pass/last_used" ]] && [[ $1 == "--last-used" || $1 == "--show-last" ]]; then
|
||||
roots=("$(awk -F ': ' '{ print $1 }' "$cache_dir/rofi-pass/last_used")")
|
||||
elif [[ -n "$2" && "$1" == "--root" ]]; then
|
||||
custom_root=true; IFS=: read -r -a roots <<< "$2"
|
||||
elif [[ -n $root ]]; then
|
||||
custom_root=true; IFS=: read -r -a roots <<< "${root}"
|
||||
elif [[ -n ${PASSWORD_STORE_DIR} ]]; then
|
||||
roots=("${PASSWORD_STORE_DIR}")
|
||||
else
|
||||
roots=("$HOME/.password-store")
|
||||
fi
|
||||
roots_index=0
|
||||
roots_length=${#roots[@]}
|
||||
export root=${roots[$roots_index]}
|
||||
export PASSWORD_STORE_DIR="${root}"
|
||||
case $1 in
|
||||
--insert)
|
||||
insertPass
|
||||
;;
|
||||
--root)
|
||||
mainMenu
|
||||
;;
|
||||
--help)
|
||||
help_msg
|
||||
;;
|
||||
--last-used)
|
||||
if [[ -r "$cache_dir/rofi-pass/last_used" ]]; then
|
||||
entry="$(awk -F ': ' '{ print $2 }' "$cache_dir/rofi-pass/last_used")"
|
||||
fi
|
||||
mainMenu
|
||||
;;
|
||||
--show-last)
|
||||
if [[ -r "$cache_dir/rofi-pass/last_used" ]]; then
|
||||
selected_password="$(awk -F ': ' '{ print $2 }' "$cache_dir/rofi-pass/last_used")" viewEntry
|
||||
else
|
||||
mainMenu
|
||||
fi
|
||||
;;
|
||||
--bmarks)
|
||||
mainMenu --bmarks;
|
||||
;;
|
||||
*)
|
||||
mainMenu
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
184
home/.local/usr/bin/rofi-screenshot
Executable file
184
home/.local/usr/bin/rofi-screenshot
Executable file
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
## rofi-screenshot
|
||||
## Author: ceuk @ github
|
||||
## Licence: WTFPL
|
||||
## Usage:
|
||||
## show the menu with rofi-screenshot
|
||||
## stop recording with rofi-screenshot -s
|
||||
|
||||
# Screenshot directory
|
||||
screenshot_directory="/home/raelon/Pictures/Screenshots"
|
||||
|
||||
# set ffmpeg defaults
|
||||
ffmpeg() {
|
||||
command ffmpeg -hide_banner -loglevel error -nostdin "$@"
|
||||
}
|
||||
|
||||
video_to_gif() {
|
||||
ffmpeg -i "$1" -vf palettegen -f image2 -c:v png - |
|
||||
ffmpeg -i "$1" -i - -filter_complex paletteuse "$2"
|
||||
}
|
||||
|
||||
countdown() {
|
||||
notify-send "Screenshot" "Recording in 3 seconds" -t 1000
|
||||
sleep 1
|
||||
notify-send "Screenshot" "Recording in 2 seconds" -t 1000
|
||||
sleep 1
|
||||
notify-send "Screenshot" "Recording in 1 seconds" -t 1000
|
||||
sleep 1
|
||||
}
|
||||
|
||||
crtc() {
|
||||
notify-send "Screenshot" "Select a region to capture"
|
||||
ffcast -q $(slop -n -f '%g ') png /tmp/screenshot_clip.png
|
||||
xclip -selection clipboard -t image/png /tmp/screenshot_clip.png
|
||||
rm /tmp/screenshot_clip.png
|
||||
notify-send "Screenshot" "Region copied to Clipboard"
|
||||
}
|
||||
|
||||
crtf() {
|
||||
notify-send "Screenshot" "Select a region to capture"
|
||||
dt=$(date '+%d-%m-%Y %H:%M:%S')
|
||||
ffcast -q $(slop -n -f '%g ') png "$screenshot_directory/$dt.png"
|
||||
notify-send "Screenshot" "Region saved to $screenshot_directory"
|
||||
}
|
||||
|
||||
cstc() {
|
||||
ffcast -q png /tmp/screenshot_clip.png
|
||||
xclip -selection clipboard -t image/png /tmp/screenshot_clip.png
|
||||
rm /tmp/screenshot_clip.png
|
||||
notify-send "Screenshot" "Screenshot copied to Clipboard"
|
||||
}
|
||||
|
||||
cstf() {
|
||||
dt=$(date '+%d-%m-%Y %H:%M:%S')
|
||||
ffcast -q png "$screenshot_directory/$dt.png"
|
||||
notify-send "Screenshot" "Screenshot saved to $screenshot_directory"
|
||||
}
|
||||
|
||||
rgrtf() {
|
||||
notify-send "Screenshot" "Select a region to record"
|
||||
dt=$(date '+%d-%m-%Y %H:%M:%S')
|
||||
ffcast -q $(slop -n -f '%g ' && countdown) rec /tmp/screenshot_gif.mp4
|
||||
notify-send "Screenshot" "Converting to gif... (this can take a while)"
|
||||
video_to_gif /tmp/screenshot_gif.mp4 "$screenshot_directory/$dt.gif"
|
||||
rm /tmp/screenshot_gif.mp4
|
||||
notify-send "Screenshot" "Recording saved to $screenshot_directory"
|
||||
}
|
||||
|
||||
rgstf() {
|
||||
countdown
|
||||
dt=$(date '+%d-%m-%Y %H:%M:%S')
|
||||
ffcast -q rec /tmp/screenshot_gif.mp4
|
||||
notify-send "Screenshot" "Converting to gif... (this can take a while)"
|
||||
video_to_gif /tmp/screenshot_gif.mp4 "$screenshot_directory/$dt.gif"
|
||||
rm /tmp/screenshot_gif.mp4
|
||||
notify-send "Screenshot" "Recording saved to $screenshot_directory"
|
||||
}
|
||||
|
||||
rvrtf() {
|
||||
notify-send "Screenshot" "Select a region to record"
|
||||
dt=$(date '+%d-%m-%Y %H:%M:%S')
|
||||
ffcast -q $(slop -n -f '%g ' && countdown) rec "$screenshot_directory/$dt.mp4"
|
||||
notify-send "Screenshot" "Recording saved to $screenshot_directory"
|
||||
}
|
||||
|
||||
rvstf() {
|
||||
countdown
|
||||
dt=$(date '+%d-%m-%Y %H:%M:%S')
|
||||
ffcast -q rec "$screenshot_directory/$dt.mp4"
|
||||
notify-send "Screenshot" "Recording saved to $screenshot_directory"
|
||||
}
|
||||
|
||||
get_options() {
|
||||
echo " Capture Region Clip"
|
||||
echo " Capture Region File"
|
||||
echo " Capture Screen Clip"
|
||||
echo " Capture Screen File"
|
||||
echo " Record Region File (GIF)"
|
||||
echo " Record Screen File (GIF)"
|
||||
echo " Record Region File (MP4)"
|
||||
echo " Record Screen File (MP4)"
|
||||
}
|
||||
|
||||
check_deps() {
|
||||
if ! hash $1 2>/dev/null; then
|
||||
echo "Error: This script requires $1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
# check dependencies
|
||||
check_deps slop
|
||||
check_deps ffcast
|
||||
check_deps ffmpeg
|
||||
check_deps xclip
|
||||
check_deps rofi
|
||||
|
||||
if [[ $1 == '--help' ]] || [[ $1 = '-h' ]]
|
||||
then
|
||||
echo ### rofi-screenshot
|
||||
echo USAGE: rofi-screenshot [OPTION]
|
||||
echo \(no option\)
|
||||
echo " show the screenshot menu"
|
||||
echo -s, --stop
|
||||
echo " stop recording"
|
||||
echo -h, --help
|
||||
echo " this screen"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $1 = '--stop' ]] || [[ $1 = '-s' ]]
|
||||
then
|
||||
pkill -fxn '(/\S+)*ffmpeg\s.*\sx11grab\s.*'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get choice from rofi
|
||||
choice=$( (get_options) | rofi -dmenu -i -fuzzy -p "Screenshot" )
|
||||
|
||||
# If user has not picked anything, exit
|
||||
if [[ -z "${choice// }" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# run the selected command
|
||||
case $choice in
|
||||
' Capture Region Clip')
|
||||
crtc
|
||||
;;
|
||||
' Capture Region File')
|
||||
crtf
|
||||
;;
|
||||
' Capture Screen Clip')
|
||||
cstc
|
||||
;;
|
||||
' Capture Screen File')
|
||||
cstf
|
||||
;;
|
||||
' Record Region File (GIF)')
|
||||
rgrtf
|
||||
;;
|
||||
' Record Screen File (GIF)')
|
||||
rgstf
|
||||
;;
|
||||
' Record Region File (MP4)')
|
||||
rvrtf
|
||||
;;
|
||||
' Record Screen File (MP4)')
|
||||
rvstf
|
||||
;;
|
||||
esac
|
||||
|
||||
# done
|
||||
set -e
|
||||
}
|
||||
|
||||
main $1 &
|
||||
|
||||
exit 0
|
||||
|
||||
!/bin/bash
|
||||
|
||||
2
home/.local/usr/bin/screenshot
Executable file
2
home/.local/usr/bin/screenshot
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
scrot ~/Pictures/Screenshots/'%y%m%d-%H:%M'.png -f -s -e 'xclip -selection clipboard -t image/png -i $f'
|
||||
47
home/.local/usr/bin/screenshot.sh
Executable file
47
home/.local/usr/bin/screenshot.sh
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
#changelog
|
||||
#v0.3
|
||||
#added 1. Notifications 2.unique names for each type (for quick launch) 3.better photo editor (pinta) 4.dmenu title
|
||||
#v0.4
|
||||
#1.Added variable for notification timeouts. 2. Show link in notification
|
||||
|
||||
|
||||
IMG_PATH=$HOME/Pictures/Screenshots
|
||||
UL=fb
|
||||
EDIT=gimp
|
||||
TIME=3000 #Miliseconds notification should remain visible
|
||||
|
||||
|
||||
prog="
|
||||
---Local screenshots (saved at IMG_PATH)---
|
||||
1.quick_fullscreen
|
||||
2.delayed_fullscreen
|
||||
3.section
|
||||
4.edit_fullscreen
|
||||
---Upload to remote service (images will be deleted)---
|
||||
a.upload_fullscreen
|
||||
u.upload_delayed_fullscreen
|
||||
e.edit_upload_fullscreen
|
||||
s.upload_section
|
||||
p.edit_upload_section
|
||||
"
|
||||
|
||||
cmd=$(dmenu -l 20 -nf '#999' -nb '#292d3e' -sf '#eee' -sb '#0077bb' -p 'Choose Screenshot Type' <<< "$prog")
|
||||
|
||||
cd $IMG_PATH
|
||||
case ${cmd%% *} in
|
||||
|
||||
1.quick_fullscreen) scrot -d 1 '%Y-%m-%d-@%H-%M-%S-scrot.png' && notify-send -u low -t $TIME 'Scrot' 'Fullscreen taken and saved' ;;
|
||||
2.delayed_fullscreen) scrot -d 4 '%Y-%m-%d-@%H-%M-%S-scrot.png' && notify-send -u low -t $TIME 'Scrot' 'Fullscreen Screenshot saved' ;;
|
||||
3.section) scrot -s '%Y-%m-%d-@%H-%M-%S-scrot.png' && notify-send -u low -t $TIME 'Scrot' 'Screenshot of section saved' ;;
|
||||
4.edit_fullscreen) scrot -d 1 '%Y-%m-%d-@%H-%M-%S-scrot.png' -e "$EDIT \$f" && notify-send -u low -t $TIME 'Scrot' 'Screenshot edited and saved' ;;
|
||||
|
||||
a.upload_fullscreen) scrot -d 1 '%Y-%m-%d-@%H-%M-%S-scrot.png' -e "$UL \$f" && (xclip -o;echo) | xclip -selection clipboard && notify-send -u low -t $TIME "Scrot" "Screenshot Uploaded (powered by fb) - $(xclip -o;echo)" ;;
|
||||
u.upload_delayed_fullscreen) scrot -d 4 '%Y-%m-%d-@%H-%M-%S-scrot.png' -e "$UL \$f" && (xclip -o;echo) | xclip -selection clipboard && notify-send -u low -t $TIME "Scrot" "Screenshot Uploaded (powered by fb) - $(xclip -o)" ;;
|
||||
e.edit_upload_fullscreen) scrot -d 4 '%Y-%m-%d-@%H-%M-%S-scrot.png' -e "$EDIT \$f && $UL \$f && rm -f \$f" && notify-send -u low -t $TIME "Scrot" "Screenshot Uploaded (powered by fb) - $(xclip -o)" ;;
|
||||
s.upload_section) scrot -s '%Y-%m-%d-@%H-%M-%S-scrot.png' -e "$UL \$f" && (xclip -o;echo) | xclip -selection clipboard && notify-send -u low -t $TIME "Scrot" "Screenshot Uploaded (powered by fb - $(xclip -o)";;
|
||||
p.edit_upload_section) scrot -s '%Y-%m-%d-@%H-%M-%S-scrot.png' -e "$EDIT \$f && $UL \$f && rm -f \$f" && (xclip -o;echo) | xclip -selection clipboard && notify-send -u low -t $TIME "Scrot" "Screenshot Uploaded (powered by FB) - $(xclip -o)" ;;
|
||||
|
||||
|
||||
*) exec "'${cmd}'" ;;
|
||||
esac
|
||||
33
home/.local/usr/bin/surf-open.sh
Executable file
33
home/.local/usr/bin/surf-open.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# See the LICENSE file for copyright and license details.
|
||||
#
|
||||
|
||||
# xidfile="$HOME/tmp/tabbed-surf.xid"
|
||||
xidfile="$HOME/.local/state/tabbed-surf.xid"
|
||||
uri="https://duckduckgo.com/lite"
|
||||
|
||||
if [ "$#" -gt 0 ];
|
||||
then
|
||||
uri="$1"
|
||||
fi
|
||||
|
||||
runtabbed() {
|
||||
tabbed -dn tabbed-surf -r 2 surf -e '' "$uri" >"$xidfile" \
|
||||
2>/dev/null &
|
||||
}
|
||||
|
||||
if [ ! -r "$xidfile" ];
|
||||
then
|
||||
runtabbed
|
||||
else
|
||||
xid=$(cat "$xidfile")
|
||||
xprop -id "$xid" >/dev/null 2>&1
|
||||
if [ $? -gt 0 ];
|
||||
then
|
||||
runtabbed
|
||||
else
|
||||
surf -e "$xid" "$uri" >/dev/null 2>&1 &
|
||||
fi
|
||||
fi
|
||||
|
||||
4
home/.local/usr/bin/swapesc.sh
Executable file
4
home/.local/usr/bin/swapesc.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Swap ESC and Caps Lock
|
||||
eval "setxkbmap -option caps:swapescape"
|
||||
34
home/.local/usr/bin/taskadd
Executable file
34
home/.local/usr/bin/taskadd
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Behavior:
|
||||
# Userscript for qutebrowser which adds a task to taskwarrior.
|
||||
# If run as a command (:spawn --userscript taskadd), it creates a new task
|
||||
# with the description equal to the current page title and annotates it with
|
||||
# the current page url. Additional arguments are passed along so you can add
|
||||
# mods to the task (e.g. priority, due date, tags).
|
||||
#
|
||||
# Example:
|
||||
# :spawn --userscript taskadd due:eod pri:H
|
||||
#
|
||||
# To enable passing along extra args, I suggest using a mapping like:
|
||||
# :bind <somekey> cmd-set-text -s :spawn --userscript taskadd
|
||||
#
|
||||
# If run from hint mode, it uses the selected hint text as the description
|
||||
# and the selected hint url as the annotation.
|
||||
#
|
||||
# Ryan Roden-Corrent (rcorre), 2016
|
||||
# Any feedback is welcome!
|
||||
#
|
||||
# For more info on Taskwarrior, see https://taskwarrior.org/
|
||||
|
||||
# use either the current page title or the hint text as the task description
|
||||
[[ $QUTE_MODE == 'hints' ]] && title=$QUTE_SELECTED_TEXT || title=$QUTE_TITLE
|
||||
|
||||
# try to add the task and grab the output
|
||||
if msg="$(task add "$title" "$*" 2>&1)"; then
|
||||
# annotate the new task with the url, send the output back to the browser
|
||||
task +LATEST annotate "$QUTE_URL"
|
||||
echo "message-info '$(echo "$msg" | head -n 1)'" >> "$QUTE_FIFO"
|
||||
else
|
||||
echo "message-error '$(echo "$msg" | head -n 1)'" >> "$QUTE_FIFO"
|
||||
fi
|
||||
24
home/.local/usr/bin/tmuxsessions.sh
Executable file
24
home/.local/usr/bin/tmuxsessions.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Description: A script to list and start tmuxinator projects using fzf.
|
||||
|
||||
# Set the directory where your tmuxinator configuration files are located
|
||||
TMUXINATOR_CONFIG_DIR="${HOME}/.config/tmuxinator/"
|
||||
|
||||
# Find all tmuxinator `.yml` files in the specified directory, remove path and extensions
|
||||
# project=$(find "$TMUXINATOR_CONFIG_DIR" -type f -name "*.yml" | sed 's|.*/||;s|\.yml$||' | \
|
||||
# fzf --prompt="Session: " --preview-label="pyTui Tmuxinator Picker" --preview-label-pos=bottom \
|
||||
# --preview="bat --style=full --color=always" --preview-window=up \
|
||||
# )
|
||||
|
||||
# project=$(find "$TMUXINATOR_CONFIG_DIR" -type f -name "*.yml" | sed 's|.*/||;s|\.yml$||' | fzf --prompt="Session: " --tmux bottom,5%)
|
||||
project=$(find "$TMUXINATOR_CONFIG_DIR" -type f -name "*.yml" | sed 's|.*/||;s|\.yml$||' | fzf --prompt="Session " --tmux left,25 --reverse)
|
||||
|
||||
# Check if a project was selected
|
||||
if [[ -n "$project" ]]; then
|
||||
# Start the selected tmuxinator project
|
||||
tmuxinator start "$project"
|
||||
# else
|
||||
# echo "No project selected. Exiting..."
|
||||
# exit 1
|
||||
fi
|
||||
6
home/.local/usr/bin/tmuxstartup.sh
Executable file
6
home/.local/usr/bin/tmuxstartup.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
fastfetch --logo small --structure "title:os:kernel:cpu:memory:disk:uptime"
|
||||
misfortune|cowsay|lolcat
|
||||
|
||||
exec zsh
|
||||
6
home/.local/usr/bin/touchpad
Executable file
6
home/.local/usr/bin/touchpad
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
idd=$(xinput --list | grep "DELL07E6:00 06CB:76AF Touchpad" | awk '{print $6}' | cut -d'=' -f2)
|
||||
sudo xinput set-prop $idd 318 1
|
||||
sudo xinput set-prop $idd 300 1
|
||||
sudo xinput set-prop $idd 307 1
|
||||
sudo xinput set-prop $idd 309 .5
|
||||
120
home/.local/usr/bin/url_handler.sh
Executable file
120
home/.local/usr/bin/url_handler.sh
Executable file
@@ -0,0 +1,120 @@
|
||||
#! /bin/bash
|
||||
|
||||
# Copyright (c) 1998 Martin Schulze <joey@debian.org>
|
||||
# Slightly modified by Luis Francisco Gonzalez <luisgh@debian.org>
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
###########################################################################
|
||||
# Configurable section
|
||||
###########################################################################
|
||||
#
|
||||
# Any entry in the lists of programs that urlview handler will try out will
|
||||
# be made of /path/to/program + ':' + TAG where TAG is one of
|
||||
# XW: XWindows program
|
||||
# XT: Launch with an xterm if possible or as VT if not
|
||||
# VT: Launch in the same terminal
|
||||
|
||||
# The lists of programs to be executed are
|
||||
https_prgs="/usr/bin/qutebrowser:XW /usr/bin/w3m:XT"
|
||||
http_prgs="/usr/bin/qutebrowser:XW /usr/bin/w3m:XT"
|
||||
mailto_prgs="/usr/bin/neomutt:VT /usr/bin/elm:VT /usr/bin/pine:VT /usr/bin/mail:VT"
|
||||
gopher_prgs="/usr/bin/lynx:XT /usr/bin/gopher:XT"
|
||||
ftp_prgs="/usr/bin/ranger:XT /usr/bin/ncftp:XT"
|
||||
|
||||
# Program used as an xterm (if it doesn't support -T you'll need to change
|
||||
# the command line in getprg)
|
||||
XTERM=/usr/bin/kitty
|
||||
|
||||
|
||||
###########################################################################
|
||||
# Change bellow this at your own risk
|
||||
###########################################################################
|
||||
function getprg()
|
||||
{
|
||||
local ele tag prog
|
||||
|
||||
for ele in $*
|
||||
do
|
||||
tag=${ele##*:}
|
||||
prog=${ele%%:*}
|
||||
if [ -x $prog ]; then
|
||||
case $tag in
|
||||
XW)
|
||||
[ -n "$DISPLAY" ] && echo "X:$prog" && return 0
|
||||
;;
|
||||
XT)
|
||||
[ -n "$DISPLAY" ] && [ -x "$XTERM" ] && \
|
||||
echo "X:$XTERM -e $prog" && return 0
|
||||
echo "$prog" && return 0
|
||||
;;
|
||||
VT)
|
||||
echo "$prog" && return 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
url="$1"; shift
|
||||
|
||||
type="${url%%:*}"
|
||||
|
||||
if [ "$url" = "$type" ]; then
|
||||
type="${url%%.*}"
|
||||
case "$type" in
|
||||
www|web)
|
||||
type=http
|
||||
;;
|
||||
esac
|
||||
url="$type://$url"
|
||||
fi
|
||||
|
||||
case $type in
|
||||
https)
|
||||
prg=`getprg $https_prgs`
|
||||
;;
|
||||
http)
|
||||
prg=`getprg $http_prgs`
|
||||
;;
|
||||
ftp)
|
||||
prg=`getprg $ftp_prgs`
|
||||
;;
|
||||
mailto)
|
||||
prg=`getprg $mailto_prgs`
|
||||
url="${url#mailto:}"
|
||||
;;
|
||||
gopher)
|
||||
prg=`getprg $gopher_prgs`
|
||||
;;
|
||||
*)
|
||||
echo "Unknown URL type. Please report URL and viewer to:"
|
||||
echo "joey@debian.org."
|
||||
echo -n "Press enter to continue."; read x
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -n "$prg" ]; then
|
||||
if [ "${prg%:*}" = "X" ]; then
|
||||
${prg#*:} "$url" 2>/dev/null &
|
||||
else
|
||||
$prg "$url"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
28
home/.local/usr/bin/win98
Executable file
28
home/.local/usr/bin/win98
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Enable basic sound output via pulseaudio
|
||||
# Run "pacmd list-sinks | grep -e 'name:' -e 'index'" to find your QEMU_PA_SINK
|
||||
export QEMU_AUDIO_DRV=pa
|
||||
export QEMU_PA_SINK=alsa_output.pci-0000_00_1f.3.analog-stereo
|
||||
export QEMU_PA_SOURCE=input
|
||||
|
||||
# Start QEMU
|
||||
qemu-system-x86_64 \
|
||||
-enable-kvm \
|
||||
-m 3G \
|
||||
-smp cores=2,threads=2,sockets=1,maxcpus=4 \
|
||||
-cpu host,hv_relaxed,hv_spinlocks=0x1fff,hv_vapic,hv_time \
|
||||
-machine type=pc,accel=kvm,kernel_irqchip=on \
|
||||
-global PIIX4_PM.disable_s3=1 \
|
||||
-global PIIX4_PM.disable_s4=1 \
|
||||
-name windows-98-guest \
|
||||
-cdrom '/home/raelon/isos/win98se.iso' \
|
||||
-drive file='/home/raelon/usd/win98',format=qcow2,l2-cache-size=8M \
|
||||
-boot order=d \
|
||||
-soundhw hda \
|
||||
-usb \
|
||||
-device usb-tablet \
|
||||
# -nic none \
|
||||
-vga qxl \
|
||||
-display gtk,gl=on \
|
||||
-device vfio-pci,sysfsdev=/sys/devices/pci0000:00/0000:00:02.0/87c17a7c-972b-407a-b14a-74779f799b8d,x-igd-opregion=on,display=on \
|
||||
41
home/.local/usr/lib/blightmud/empiremud.lua
Normal file
41
home/.local/usr/lib/blightmud/empiremud.lua
Normal file
@@ -0,0 +1,41 @@
|
||||
local mapfile = "/home/th3r00t/.local/share/blightmud/empiremud.map"
|
||||
Map = Mapper.create("empiremud")
|
||||
|
||||
local function file_exists(file)
|
||||
local f = io.open(file, "r")
|
||||
if f then
|
||||
f:close()
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function load_map()
|
||||
if file_exists(mapfile) then
|
||||
blight.status_line(1, "Loading map...")
|
||||
Map:load(mapfile)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function empiremud_connect()
|
||||
blight.status_height(1)
|
||||
blight.status_line(0, "Connecting to Enpire Mud...")
|
||||
blight.status_line(1, "Logging in...")
|
||||
mud.send("Raelon")
|
||||
mud.send("b2edxfrr1")
|
||||
blight.status_line(1, "Connected To Enpire Mud.")
|
||||
blight.status_line(0, "Enpire Mud")
|
||||
load_map()
|
||||
Map:print()
|
||||
end
|
||||
|
||||
mud.on_disconnect(function()
|
||||
blight.status_line(0, "Disconnected.")
|
||||
if Map then
|
||||
Map:save(mapfile)
|
||||
end
|
||||
end)
|
||||
|
||||
empiremud_connect()
|
||||
40
home/.local/usr/lib/blightmud/sindome.lua
Normal file
40
home/.local/usr/lib/blightmud/sindome.lua
Normal file
@@ -0,0 +1,40 @@
|
||||
local mapfile = "/home/th3r00t/.local/share/blightmud/sindome.map"
|
||||
Map = Mapper.create("sindome")
|
||||
|
||||
local function file_exists(file)
|
||||
local f = io.open(file, "r")
|
||||
if f then
|
||||
f:close()
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function load_map()
|
||||
if file_exists(mapfile) then
|
||||
blight.status_line(1, "Loading map...")
|
||||
Map:load(mapfile)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function sindome_connect()
|
||||
blight.status_height(1)
|
||||
blight.status_line(0, "Connecting to Sindome...")
|
||||
blight.status_line(1, "Logging in...")
|
||||
mud.send("connect ryn XeGEb")
|
||||
blight.status_line(1, "Connected To Sindome.")
|
||||
blight.status_line(0, "Sindome")
|
||||
load_map()
|
||||
Map:print()
|
||||
end
|
||||
|
||||
mud.on_disconnect(function()
|
||||
blight.status_line(0, "Disconnected.")
|
||||
if Map then
|
||||
Map:save(mapfile)
|
||||
end
|
||||
end)
|
||||
|
||||
sindome_connect()
|
||||
40
home/.local/usr/lib/blightmud/untold-dawn.lua
Normal file
40
home/.local/usr/lib/blightmud/untold-dawn.lua
Normal file
@@ -0,0 +1,40 @@
|
||||
local mapfile = "/home/th3r00t/.local/share/blightmud/sindome.map"
|
||||
Map = Mapper.create("untolddawn")
|
||||
|
||||
local function file_exists(file)
|
||||
local f = io.open(file, "r")
|
||||
if f then
|
||||
f:close()
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function load_map()
|
||||
if file_exists(mapfile) then
|
||||
blight.status_line(1, "Loading map...")
|
||||
Map:load(mapfile)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function untolddawn_connect()
|
||||
blight.status_height(1)
|
||||
blight.status_line(0, "Connecting to Untold Dawn...")
|
||||
blight.status_line(1, "Logging in...")
|
||||
mud.send("login th3r00t b2edxfrr1")
|
||||
blight.status_line(1, "Connected To Untold Dawn.")
|
||||
blight.status_line(0, "Untold Dawn")
|
||||
load_map()
|
||||
Map:print()
|
||||
end
|
||||
|
||||
mud.on_disconnect(function()
|
||||
blight.status_line(0, "Disconnected.")
|
||||
if Map then
|
||||
Map:save(mapfile)
|
||||
end
|
||||
end)
|
||||
|
||||
untolddawn_connect()
|
||||
49
home/.taskrc
Normal file
49
home/.taskrc
Normal file
@@ -0,0 +1,49 @@
|
||||
# [Created by task 2.6.2 7/28/2022 12:49:42]
|
||||
# Taskwarrior program configuration file.
|
||||
# For more documentation, see https://taskwarrior.org or try 'man task', 'man task-color',
|
||||
# 'man task-sync' or 'man taskrc'
|
||||
|
||||
# Here is an example of entries that use the default, override and blank values
|
||||
# variable=foo -- By specifying a value, this overrides the default
|
||||
# variable= -- By specifying no value, this means no default
|
||||
# #variable=foo -- By commenting out the line, or deleting it, this uses the default
|
||||
|
||||
# You can also refence environment variables:
|
||||
# variable=$HOME/task
|
||||
# variable=$VALUE
|
||||
|
||||
# Use the command 'task show' to see all defaults and overrides
|
||||
|
||||
# Files
|
||||
data.location=/home/th3r00t/.task
|
||||
|
||||
# To use the default location of the XDG directories,
|
||||
# move this configuration file from ~/.taskrc to ~/.config/task/taskrc and uncomment below
|
||||
|
||||
#data.location=~/.local/share/task
|
||||
#hooks.location=~/.config/task/hooks
|
||||
|
||||
# Color theme (uncomment one to use)
|
||||
#include light-16.theme
|
||||
#include light-256.theme
|
||||
#include dark-16.theme
|
||||
#include dark-256.theme
|
||||
#include dark-red-256.theme
|
||||
#include dark-green-256.theme
|
||||
include dark-blue-256.theme
|
||||
#include dark-violets-256.theme
|
||||
#include dark-yellow-green.theme
|
||||
#include dark-gray-256.theme
|
||||
#include dark-gray-blue-256.theme
|
||||
#include solarized-dark-256.theme
|
||||
#include solarized-light-256.theme
|
||||
#include no-color.theme
|
||||
#taskd.trust=allow all
|
||||
taskd.server=mylt.dev:53589
|
||||
taskd.credentials=own\/th3r00t\/cc06caef-20ea-48e6-8d61-23ac7d12941a
|
||||
taskd.certificate=/home/th3r00t/.task/th3r00t.cert.pem
|
||||
taskd.key=/home/th3r00t/.task/th3r00t.key.pem
|
||||
taskd.ca=/home/th3r00t/.task/ca.cert.pem
|
||||
|
||||
#include ~/.local/builds/falcon/taskwarrior/falcon.theme
|
||||
news.version=3.1.0
|
||||
1350
home/config/dosbox-x/dosbox-x-2025.05.03.conf
Normal file
1350
home/config/dosbox-x/dosbox-x-2025.05.03.conf
Normal file
File diff suppressed because it is too large
Load Diff
138
home/config/nvim/init.lua
Normal file
138
home/config/nvim/init.lua
Normal file
@@ -0,0 +1,138 @@
|
||||
local vim = vim
|
||||
require("options") -- lua/options.lua
|
||||
require("plugins") -- lua/plugins.lua
|
||||
require("utils.t3_functions") -- lua/utils/t3_functions.lua
|
||||
require("utils.t3_overrides") -- lua/utils/t3_overrides.lua
|
||||
require("utils.reload") -- lua/utils/reload.lua
|
||||
require("vimwiki") -- lua/vimwiki.lua
|
||||
require("keymaps") -- lua/keymaps.lua
|
||||
require("lsp") -- lua/lsp.lua
|
||||
require("completion") -- lua/completion.lua
|
||||
require("treesitter") -- lua/treesitter.lua
|
||||
require("autocmds") -- lua/autocmds.lua
|
||||
require("diagnostics") -- lua/diagnostics.lua
|
||||
|
||||
require('tokyonight').setup({
|
||||
style = "moon", -- "storm", "moon", "day", "night"
|
||||
transparent = true, -- Enable transparent background
|
||||
terminal_colors = true, -- Enable terminal colors
|
||||
styles = {
|
||||
comments = { italic = true }, -- Italic comments
|
||||
keywords = { italic = true }, -- Italic keywords
|
||||
functions = { bold = true }, -- Bold functions
|
||||
variables = {}, -- No special style for variables
|
||||
sidebars = "dark", -- Dark sidebars
|
||||
floats = "dark", -- Dark floating windows
|
||||
},
|
||||
})
|
||||
|
||||
local function is_linux_console()
|
||||
return vim.env.TERM == "linux"
|
||||
end
|
||||
|
||||
local function want_truecolor()
|
||||
if is_linux_console() then return false end
|
||||
return vim.fn.has("termguicolors") == 1
|
||||
or ((vim.env.COLORTERM or ""):lower():find("truecolor") ~= nil)
|
||||
end
|
||||
|
||||
local function set_colorscheme()
|
||||
if want_truecolor() then
|
||||
vim.o.termguicolors = true
|
||||
if not pcall(vim.cmd.colorscheme, "tokyonight") then
|
||||
pcall(vim.cmd.colorscheme, "habamax")
|
||||
end
|
||||
else
|
||||
vim.o.termguicolors = false
|
||||
if not pcall(vim.cmd.colorscheme, "industry") then
|
||||
pcall(vim.cmd.colorscheme, "default")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
vim.api.nvim_create_autocmd("VimEnter", {
|
||||
callback = function()
|
||||
set_colorscheme()
|
||||
|
||||
local tty = is_linux_console()
|
||||
|
||||
-- LUALINE: no icons, simple separators, TTY theme
|
||||
pcall(function()
|
||||
local ok, lualine = pcall(require, "lualine")
|
||||
if not ok then return end
|
||||
if tty then
|
||||
lualine.setup({
|
||||
options = {
|
||||
theme = "16color", -- built-in, safe for TTY
|
||||
icons_enabled = false,
|
||||
component_separators = "",
|
||||
section_separators = "",
|
||||
globalstatus = true,
|
||||
},
|
||||
sections = {
|
||||
lualine_a = { "mode" },
|
||||
lualine_b = { "branch" },
|
||||
lualine_c = { { "filename", file_status = true, path = 1 } },
|
||||
lualine_x = { "encoding", "fileformat", "filetype" },
|
||||
lualine_y = { "progress" },
|
||||
lualine_z = { "location" },
|
||||
},
|
||||
})
|
||||
else
|
||||
lualine.setup({
|
||||
options = {
|
||||
theme = "tokyonight",
|
||||
icons_enabled = true,
|
||||
globalstatus = true,
|
||||
},
|
||||
})
|
||||
end
|
||||
end)
|
||||
|
||||
-- BARBAR: kill icons in TTY, simplify separators
|
||||
pcall(function()
|
||||
vim.g.barbar_auto_setup = false
|
||||
local ok, barbar = pcall(require, "barbar")
|
||||
if not ok then return end
|
||||
if tty then
|
||||
barbar.setup({
|
||||
animation = false,
|
||||
auto_hide = false,
|
||||
sidebar_filetypes = { NvimTree = true, undotree = { text = "Undotree" } },
|
||||
icons = {
|
||||
-- aggressively disable anything icon-like
|
||||
buffer_index = false,
|
||||
buffer_number = false,
|
||||
button = "", -- close button
|
||||
diagnostics = {
|
||||
[vim.diagnostic.severity.ERROR] = { enabled = false },
|
||||
[vim.diagnostic.severity.WARN] = { enabled = false },
|
||||
[vim.diagnostic.severity.INFO] = { enabled = false },
|
||||
[vim.diagnostic.severity.HINT] = { enabled = false },
|
||||
},
|
||||
gitsigns = { added = {enabled=false}, changed = {enabled=false}, deleted = {enabled=false} },
|
||||
filetype = { enabled = false },
|
||||
pinned = { button = "", filename = true },
|
||||
modified = { button = "*" }, -- simple ASCII marker
|
||||
separator = { left = "|", right = "|" },
|
||||
inactive = { separator = { left = "", right = "" } },
|
||||
},
|
||||
})
|
||||
else
|
||||
barbar.setup({}) -- your normal config, or keep defaults
|
||||
end
|
||||
end)
|
||||
|
||||
-- If you use web-devicons, disable it in TTY to avoid glyphs
|
||||
if is_linux_console() then
|
||||
-- If using lazy.nvim, better to conditionally load the plugin (see spec below).
|
||||
if package.loaded["nvim-web-devicons"] then
|
||||
local ok, devicons = pcall(require, "nvim-web-devicons")
|
||||
if ok and devicons.has_loaded() then
|
||||
-- there's no runtime "disable", but not using it in barbar/lualine is enough.
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
3
home/config/nvim/lazy-lock.json
Normal file
3
home/config/nvim/lazy-lock.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
9
home/config/nvim/lua/autocmds.lua
Normal file
9
home/config/nvim/lua/autocmds.lua
Normal file
@@ -0,0 +1,9 @@
|
||||
local vim = vim
|
||||
|
||||
vim.api.nvim_create_autocmd({ "BufEnter", "BufWritePost" }, {
|
||||
group = vim.api.nvim_create_augroup("TWTask", { clear = true }),
|
||||
pattern = "*.wiki", -- Pattern to match Markdown files
|
||||
callback = function()
|
||||
vim.cmd('TWSyncTasks')
|
||||
end,
|
||||
})
|
||||
112
home/config/nvim/lua/completion.lua
Normal file
112
home/config/nvim/lua/completion.lua
Normal file
@@ -0,0 +1,112 @@
|
||||
local cmp = require("cmp")
|
||||
|
||||
cmp.setup({
|
||||
snippet = {
|
||||
expand = function(args)
|
||||
require('luasnip').lsp_expand(args.body) -- For `luasnip` users.
|
||||
end,
|
||||
},
|
||||
window = {
|
||||
completion = cmp.config.window.bordered(),
|
||||
documentation = cmp.config.window.bordered(),
|
||||
},
|
||||
mapping = cmp.mapping.preset.insert({
|
||||
["<C-b>"] = cmp.mapping.scroll_docs(-4),
|
||||
["<C-f>"] = cmp.mapping.scroll_docs(4),
|
||||
["<C-Space>"] = cmp.mapping.complete(),
|
||||
["<C-e>"] = cmp.mapping.abort(),
|
||||
["<CR>"] = cmp.mapping.confirm({ select = false }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
|
||||
["<C-Tab>"] = cmp.mapping(function(fallback)
|
||||
if cmp.visible() then
|
||||
cmp.select_next_item()
|
||||
else
|
||||
fallback()
|
||||
end
|
||||
end, { "i", "s" }),
|
||||
|
||||
["<S-Tab>"] = cmp.mapping(function(fallback)
|
||||
if cmp.visible() then
|
||||
cmp.select_prev_item()
|
||||
else
|
||||
fallback()
|
||||
end
|
||||
end, { "i", "s" }),
|
||||
}),
|
||||
sources = cmp.config.sources({
|
||||
{ name = "nvim_lua" },
|
||||
{ name = "copilot", group_index = 3 },
|
||||
{ name = "nvim_lsp", group_index = 1 },
|
||||
{ name = "path", group_index = 3 },
|
||||
{ name = "luasnip", group_index = 2 },
|
||||
{ name = "buffer" },
|
||||
{ name = "calc" },
|
||||
{ name = 'orgmode' },
|
||||
-- { name = 'vsnip' }, -- For vsnip users.
|
||||
-- { name = 'luasnip' }, -- For luasnip users.
|
||||
-- { name = 'ultisnips' }, -- For ultisnips users.
|
||||
-- { name = 'snippy' }, -- For snippy users.
|
||||
{ name = "crates" },
|
||||
-- { name = 'cmdline' },
|
||||
-- { name = 'neorg' },
|
||||
}),
|
||||
})
|
||||
|
||||
-- Set configuration for specific filetype.
|
||||
cmp.setup.filetype("gitcommit", {
|
||||
sources = cmp.config.sources({
|
||||
{ name = "cmp_git" }, -- You can specify the `cmp_git` source if you were installed it.
|
||||
}, {
|
||||
{ name = "buffer" },
|
||||
}),
|
||||
})
|
||||
|
||||
-- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore).
|
||||
cmp.setup.cmdline({ "/", "?" }, {
|
||||
mapping = cmp.mapping.preset.cmdline(),
|
||||
sources = {
|
||||
{ name = "buffer" },
|
||||
{ name = "cmdline" },
|
||||
},
|
||||
})
|
||||
|
||||
-- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore).
|
||||
cmp.setup.cmdline(":", {
|
||||
mapping = cmp.mapping.preset.cmdline(),
|
||||
sources = cmp.config.sources({
|
||||
{ name = "path" },
|
||||
}, {
|
||||
{ name = "cmdline" },
|
||||
}),
|
||||
})
|
||||
|
||||
-- Set up lspconfig.
|
||||
-- require("cmp_nvim_lsp").default_capabilities()
|
||||
local capabilities = require("cmp_nvim_lsp").default_capabilities()
|
||||
-- Replace <YOUR_LSP_SERVER> with each lsp server you've enabled.
|
||||
-- require('lspconfig')['<YOUR_LSP_SERVER>'].setup {
|
||||
-- capabilities = capabilities
|
||||
-- }
|
||||
require("lspconfig").clangd.setup({
|
||||
capabilities = capabilities,
|
||||
})
|
||||
require("lspconfig").taplo.setup({
|
||||
capabilities = capabilities,
|
||||
})
|
||||
require("lspconfig").marksman.setup({
|
||||
capabilities = capabilities,
|
||||
})
|
||||
require("lspconfig").lua_ls.setup({
|
||||
capabilities = capabilities,
|
||||
})
|
||||
require("lspconfig").rust_analyzer.setup({
|
||||
capabilities = capabilities,
|
||||
})
|
||||
require("lspconfig").zls.setup({
|
||||
capabilities = capabilities,
|
||||
})
|
||||
require("lspconfig").pyright.setup({
|
||||
capabilities = capabilities,
|
||||
})
|
||||
-- require'lspconfig'.jedi_language_server.setup {
|
||||
-- capabilities = capabilities,
|
||||
-- }
|
||||
60
home/config/nvim/lua/diagnostics.lua
Normal file
60
home/config/nvim/lua/diagnostics.lua
Normal file
@@ -0,0 +1,60 @@
|
||||
require("tiny-inline-diagnostic").setup({
|
||||
-- Style preset for diagnostic messages
|
||||
-- Available options:
|
||||
-- "modern", "classic", "minimal", "powerline",
|
||||
-- "ghost", "simple", "nonerdfont", "amongus"
|
||||
preset = "modern",
|
||||
transparent_bg = false, -- Set the background of the diagnostic to transparent
|
||||
transparent_cursorline = false, -- Set the background of the cursorline to transparent (only one the first diagnostic)
|
||||
hi = {
|
||||
error = "DiagnosticError", -- Highlight group for error messages
|
||||
warn = "DiagnosticWarn", -- Highlight group for warning messages
|
||||
info = "DiagnosticInfo", -- Highlight group for informational messages
|
||||
hint = "DiagnosticHint", -- Highlight group for hint or suggestion messages
|
||||
arrow = "NonText", -- Highlight group for diagnostic arrows
|
||||
background = "CursorLine",
|
||||
mixing_color = "None",
|
||||
},
|
||||
|
||||
options = {
|
||||
show_source = {
|
||||
enabled = false,
|
||||
if_many = false,
|
||||
},
|
||||
use_icons_from_diagnostic = false,
|
||||
set_arrow_to_diag_color = false,
|
||||
add_messages = true,
|
||||
throttle = 20,
|
||||
softwrap = 30,
|
||||
multilines = {
|
||||
enabled = false,
|
||||
always_show = false,
|
||||
trim_whitespaces = false,
|
||||
tabstop = 4,
|
||||
},
|
||||
show_all_diags_on_cursorline = false,
|
||||
enable_on_insert = false,
|
||||
enable_on_select = false,
|
||||
|
||||
overflow = {
|
||||
mode = "wrap",
|
||||
padding = 0,
|
||||
},
|
||||
break_line = {
|
||||
enabled = false,
|
||||
after = 30,
|
||||
},
|
||||
format = nil,
|
||||
virt_texts = {
|
||||
priority = 2048,
|
||||
},
|
||||
severity = {
|
||||
vim.diagnostic.severity.ERROR,
|
||||
vim.diagnostic.severity.WARN,
|
||||
vim.diagnostic.severity.INFO,
|
||||
vim.diagnostic.severity.HINT,
|
||||
},
|
||||
overwrite_events = nil,
|
||||
},
|
||||
disabled_ft = {} -- List of filetypes to disable the plugin
|
||||
})
|
||||
166
home/config/nvim/lua/functions.lua
Normal file
166
home/config/nvim/lua/functions.lua
Normal file
@@ -0,0 +1,166 @@
|
||||
local vim = vim
|
||||
local fzflua = require("fzf-lua")
|
||||
local Job = require'plenary.job'
|
||||
|
||||
function t3_find_file()
|
||||
-- local file_name = vim.fn.input("Find File: ", "", "file")
|
||||
fzflua.files()
|
||||
end
|
||||
|
||||
function t3_recent_files()
|
||||
fzflua.oldfiles()
|
||||
end
|
||||
|
||||
function t3_org_files()
|
||||
fzflua.files({ cwd = '~/org/'})
|
||||
end
|
||||
|
||||
function t3_project_files()
|
||||
fzflua.files({ cwd = '~/Projects/'})
|
||||
end
|
||||
|
||||
function t3_dot_files()
|
||||
fzflua.files({ cwd = '~/.dotfiles/'})
|
||||
end
|
||||
|
||||
function t3_config_files()
|
||||
fzflua.files({ cwd = '~/.dotfiles/'})
|
||||
end
|
||||
|
||||
function t3_snip_capture(name)
|
||||
if type(name) ~= "string" or name == "" then
|
||||
print("Error: Invalid snippet name")
|
||||
return
|
||||
end
|
||||
-- local timestamp = os.date("%Y%m%d%H%M%S")
|
||||
local snippet_path = "~/.config/nvim/snippets/"
|
||||
local filename = snippet_path .. name:gsub("%s+", "_") .. ".lua"
|
||||
local file = io.open(vim.fn.expand(filename), "w")
|
||||
if file == nil then
|
||||
print("Error: Could not open file for editing.")
|
||||
return
|
||||
end
|
||||
local previous_buffer = vim.api.nvim_get_current_buf()
|
||||
file:write("local ls = require('luasnip')\n\nls.add_snippets(\"{}\", {\n\tls.parser.parse_snippet(\n\t\t'{}',\n\t\t'{}'),\n})")
|
||||
file:close()
|
||||
vim.cmd("e " .. filename)
|
||||
vim.bo.filetype = 'lua'
|
||||
-- vim.cmd("Neorg inject-metadata")
|
||||
-- Set an autocmd to return to the previous buffer when the note buffer is closed
|
||||
vim.api.nvim_create_autocmd("BufLeave", {
|
||||
buffer = 0, -- Current buffer (the note buffer)
|
||||
callback = function()
|
||||
load_snippets_from_directory(snippet_path)
|
||||
vim.cmd("buffer " .. previous_buffer)
|
||||
end,
|
||||
})
|
||||
print("Captured snippet: " .. filename)
|
||||
end
|
||||
|
||||
function t3_org_capture(name)
|
||||
if type(name) ~= "string" or name == "" then
|
||||
print("Error: Invalid note name")
|
||||
return
|
||||
end
|
||||
local timestamp = os.date("%Y%m%d%H%M%S")
|
||||
local org_path = "~/org/.org-roam/"
|
||||
local filename = org_path .. timestamp .. "-" .. name:gsub("%s+", "_") .. ".norg"
|
||||
local file = io.open(vim.fn.expand(filename), "w")
|
||||
if file == nil then
|
||||
print("Error: Could not open file for editing.")
|
||||
return
|
||||
end
|
||||
local previous_buffer = vim.api.nvim_get_current_buf()
|
||||
file:write("* " .. name .. "\n\n")
|
||||
file:close()
|
||||
vim.cmd("e " .. filename)
|
||||
vim.bo.filetype = 'norg'
|
||||
vim.cmd("Neorg inject-metadata")
|
||||
-- Set an autocmd to return to the previous buffer when the note buffer is closed
|
||||
vim.api.nvim_create_autocmd("BufLeave", {
|
||||
buffer = 0, -- Current buffer (the note buffer)
|
||||
callback = function()
|
||||
vim.cmd("buffer " .. previous_buffer)
|
||||
end,
|
||||
})
|
||||
print("Captured note: " .. filename)
|
||||
end
|
||||
|
||||
vim.api.nvim_create_user_command(
|
||||
'NeorgCapture',
|
||||
function()
|
||||
-- local title = vim.fn.input("Title: ")
|
||||
local current_workspace = vim.g.neorg_workspace_name
|
||||
if not current_workspace then
|
||||
vim.cmd("Neorg workspace default")
|
||||
end
|
||||
vim.ui.input({ prompt = "Enter note name: "}, function(note_name)
|
||||
if not note_name or note_name == "" then
|
||||
print("Error: Note name required!")
|
||||
return
|
||||
end
|
||||
t3_org_capture(note_name)
|
||||
end
|
||||
)
|
||||
end,
|
||||
{ nargs = 0, desc = "Capture a Neorg note" }
|
||||
)
|
||||
|
||||
vim.api.nvim_create_user_command(
|
||||
'CaptureSnip',
|
||||
function()
|
||||
-- local title = vim.fn.input("Title: ")
|
||||
-- local current_workspace = vim.g.neorg_workspace_name
|
||||
-- if not current_workspace then
|
||||
-- vim.cmd("Neorg workspace default")
|
||||
-- end
|
||||
vim.ui.input({ prompt = "Enter snippet name: "}, function(snip_name)
|
||||
if not snip_name or snip_name == "" then
|
||||
print("Error: Snippet name required!")
|
||||
return
|
||||
end
|
||||
t3_snip_capture(snip_name)
|
||||
end
|
||||
)
|
||||
end,
|
||||
{ nargs = 0, desc = "Capture a Neorg note" }
|
||||
)
|
||||
function t3_buffers()
|
||||
fzflua.buffers()
|
||||
end
|
||||
|
||||
function t3_tabs()
|
||||
fzflua.tabs()
|
||||
end
|
||||
|
||||
function t3_live_grep(state)
|
||||
state = state or 0
|
||||
if state == 0 then
|
||||
fzflua.live_grep()
|
||||
else
|
||||
fzflua.live_grep_resume()
|
||||
end
|
||||
end
|
||||
|
||||
function t3_grep(state)
|
||||
state = state or 0
|
||||
if state == 0 then
|
||||
fzflua.grep_project()
|
||||
else
|
||||
fzflua.grep()
|
||||
end
|
||||
end
|
||||
function t3_make_ctags()
|
||||
Job:new({
|
||||
command = 'ctags',
|
||||
args = { '-R .' },
|
||||
})
|
||||
end
|
||||
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
pattern = { "markdown", "norg", "md", "wiki" }, -- Set for markdown file type
|
||||
callback = function()
|
||||
vim.api.nvim_buf_set_keymap(0, "n", "<C-i>", "o* [ ] ", { noremap = true, silent = true })
|
||||
vim.api.nvim_buf_set_keymap(0, "i", "<C-i>", "<Esc>0wi* [ ] ", { noremap = true, silent = true })
|
||||
end,
|
||||
})
|
||||
85
home/config/nvim/lua/keymaps.lua
Normal file
85
home/config/nvim/lua/keymaps.lua
Normal file
@@ -0,0 +1,85 @@
|
||||
local vim = vim
|
||||
|
||||
vim.keymap.set("n", "<C-w>s", function()
|
||||
vim.cmd("split")
|
||||
vim.cmd("wincmd j")
|
||||
end, { noremap = true })
|
||||
|
||||
vim.keymap.set("n", "<C-w>v", function()
|
||||
vim.cmd("vsplit")
|
||||
vim.cmd("wincmd l")
|
||||
end, { noremap = true })
|
||||
|
||||
-- Leader Maps
|
||||
vim.keymap.set("n", "<leader>f", "", { desc = "Files"})
|
||||
vim.keymap.set("n", "<leader>ff", ":FzfLua files<CR>", { desc = "File Finder"})
|
||||
-- vim.keymap.set("n", "<leader>fe", ":Pick files<CR>", { desc = "File Picker"})
|
||||
vim.keymap.set("n", "<leader>ft", t3_toggle_netrw, { desc = "File Tree"})
|
||||
|
||||
vim.keymap.set("n", "<leader>b", "", { desc = "Buffers"})
|
||||
vim.keymap.set("n", "<leader>bb", ":Pick buffers<CR>", { desc = "Buffer Picker"})
|
||||
vim.keymap.set("n", "<leader>bp", ":bp<CR>", { desc = "Previous"})
|
||||
vim.keymap.set("n", "<leader>bn", ":bn<CR>", { desc = "Next"})
|
||||
vim.keymap.set("n", "<leader>bd", ":bd<CR>", { desc = "Delete"})
|
||||
|
||||
vim.keymap.set("n", "<leader>G", "", { desc = "Grep"})
|
||||
vim.keymap.set("n", "<leader>Gg", ":FzfLua grep<CR>", { desc = "Grep"})
|
||||
vim.keymap.set("n", "<leader>Gr", ":FzfLua grep resume=true<CR>", { desc = "Resume Grep"})
|
||||
|
||||
vim.keymap.set("n", "<leader>g", "", { desc = "Git"})
|
||||
vim.keymap.set("n", "<leader>gg", ":LazyGit<CR>", { desc = "LazyGit"})
|
||||
vim.keymap.set("n", "<leader>gC", ":LazyGitConfig<CR>", { desc = "LazyGit Config"})
|
||||
vim.keymap.set("n", "<leader>gc", ":LazyGitFilter<CR>", { desc = "Commits"})
|
||||
vim.keymap.set("n", "<leader>gl", ":LazyGitLog<CR>", { desc = "Log"})
|
||||
|
||||
vim.keymap.set("n", "<leader><Tab>", "", { desc = "Tabs"})
|
||||
vim.keymap.set("n", "<leader><Tab><Tab>", ":tabnew<CR>", { desc = "New Tab"})
|
||||
vim.keymap.set("n", "<leader><Tab>p", ":tabprevious<CR>", { desc = "Previous Tab"})
|
||||
vim.keymap.set("n", "<leader><Tab>n", ":tabnext<CR>", { desc = "Next Tab"})
|
||||
vim.keymap.set("n", "<leader><Tab>d", ":tabclose<CR>", { desc = "Delete Tab"})
|
||||
vim.keymap.set("n", "<leader><Tab>l", ":tablast<CR>", { desc = "Last Tab"})
|
||||
vim.keymap.set("n", "<leader><Tab>f", ":tabfirst<CR>", { desc = "First Tab"})
|
||||
vim.keymap.set("n", "<leader><Tab>m", ":tabmove<CR>", { desc = "Move Tab"})
|
||||
vim.keymap.set("n", "<leader><Tab>r", ":tabrenumber<CR>", { desc = "Renumber Tabs"})
|
||||
vim.keymap.set("n", "<leader><Tab>c", ":tabclose!<CR>", { desc = "Force Close Tab"})
|
||||
|
||||
vim.keymap.set("n", "gR", "<CMD>Glance references<CR>", { desc = "Glance References" })
|
||||
vim.keymap.set("n", "gD", "<CMD>Glance definitions<CR>", { desc = "Glance Definitions" })
|
||||
vim.keymap.set("n", "gY", "<CMD>Glance type_definitions<CR>", { desc = "Glance Type Definitions" })
|
||||
vim.keymap.set("n", "gM", "<CMD>Glance implementations<CR>", { desc = "Glance Implementations" })
|
||||
|
||||
vim.keymap.set("n", "<A-Tab>", ":b#<CR>", { desc = "Switch to Last Buffer" })
|
||||
vim.keymap.set("n", "<A-Left>", ":bprevious<CR>", { desc = "Previous Buffer" })
|
||||
vim.keymap.set("n", "<A-Right>", ":bnext<CR>", { desc = "Next Buffer" })
|
||||
vim.keymap.set("n", "<A-Up>", ":tabprevious<CR>", { desc = "Previous Tab" })
|
||||
vim.keymap.set("n", "<A-Down>", ":tabnext<CR>", { desc = "Next Tab" })
|
||||
vim.keymap.set("n", "<A-1>", "<Cmd>BufferGoto 1<CR>", { desc = "Go to Buffer 1" })
|
||||
vim.keymap.set("n", "<A-2>", "<Cmd>BufferGoto 2<CR>", { desc = "Go to Buffer 2" })
|
||||
vim.keymap.set("n", "<A-3>", "<Cmd>BufferGoto 3<CR>", { desc = "Go to Buffer 3" })
|
||||
vim.keymap.set("n", "<A-4>", "<Cmd>BufferGoto 4<CR>", { desc = "Go to Buffer 4" })
|
||||
vim.keymap.set("n", "<A-5>", "<Cmd>BufferGoto 5<CR>", { desc = "Go to Buffer 5" })
|
||||
vim.keymap.set("n", "<A-6>", "<Cmd>BufferGoto 6<CR>", { desc = "Go to Buffer 6" })
|
||||
vim.keymap.set("n", "<A-7>", "<Cmd>BufferGoto 7<CR>", { desc = "Go to Buffer 7" })
|
||||
vim.keymap.set("n", "<A-8>", "<Cmd>BufferGoto 8<CR>", { desc = "Go to Buffer 8" })
|
||||
vim.keymap.set("n", "<A-9>", "<Cmd>BufferGoto 9<CR>", { desc = "Go to Buffer 9" })
|
||||
vim.keymap.set("n", "<A-0>", "<Cmd>BufferLast<CR>", { desc = "Go to Last Buffer" })
|
||||
|
||||
|
||||
-- CTRL X Maps
|
||||
vim.keymap.set("n", "<C-x><C-b>", ":Pick buffers<CR>", { desc = "Buffer Picker"})
|
||||
vim.keymap.set("n", "<C-x><C-f>", ":Pick files<CR>", { desc = "File Picker"})
|
||||
vim.keymap.set("n", "<C-x><C-h>", ":Pick help<CR>", { desc = "Help Picker"})
|
||||
vim.keymap.set("n", "<C-x><C-g>", "", { desc = "Grep"})
|
||||
vim.keymap.set("n", "<C-x><C-g>g", ":Pick grep<CR>", { desc = "Grep"})
|
||||
vim.keymap.set("n", "<C-x><C-g>l", ":Pick grep_live<CR>", { desc = "Live Grep"})
|
||||
vim.keymap.set("v", "<C-x><C-c>", ":'<,'>SnipRun<CR>", { silent = true, desc = "Run Selection" })
|
||||
vim.keymap.set("n", "<C-x><C-c>", ":<Plug>SnipRun<CR>", { desc = "Run Current Line" })
|
||||
vim.keymap.set("n", "<C-x><C-b>", ":%SnipRun<CR>", { desc = "Run Buffer" })
|
||||
vim.keymap.set("n", "<C-x><C-k>", "<Plug>SnipReset<CR>", { desc = "Run Buffer" })
|
||||
vim.keymap.set("n", "<C-x><C-n>", "", { desc = "Notes"})
|
||||
vim.keymap.set("n", "<C-x><C-n>e", "<cmd>TWEditTask<cr>", { desc = "TaskWarrior Edit", noremap = true, silent = true })
|
||||
vim.keymap.set("n", "<C-x><C-n>v", "<cmd>TWView<cr>", { desc = "View Tasks", noremap = true, silent = true })
|
||||
vim.keymap.set("n", "<C-x><C-n>u", "<cmd>TWUpdateCurrent<cr>", { desc="Update Tasks", noremap = true, silent = true })
|
||||
vim.keymap.set("n", "<C-x><C-n>s", "<cmd>TWSyncTasks<cr>", { desc = "Sync Tasks", noremap = true, silent = true })
|
||||
vim.keymap.set("n", "<C-x><C-n><c-space>", "<cmd>TWToggle<cr>", { desc = "Toggle Taskwarrior", silent = true })
|
||||
|
||||
57
home/config/nvim/lua/lsp.lua
Normal file
57
home/config/nvim/lua/lsp.lua
Normal file
@@ -0,0 +1,57 @@
|
||||
local vim = vim
|
||||
-- vim.cmd [[
|
||||
-- augroup LspCompletion
|
||||
-- autocmd!
|
||||
-- autocmd InsertEnter * setlocal omnifunc=v:lua.vim.lsp.omnifunc
|
||||
-- autocmd TextChangedI * if pumvisible() == 0 | silent! lua vim.fn.complete(vim.fn.col('.'), vim.fn["vim.lsp.omnifunc"]()) | endif
|
||||
-- augroup END
|
||||
-- ]]
|
||||
vim.lsp.enable('lua_ls')
|
||||
vim.lsp.enable('gopls', {
|
||||
settings = {
|
||||
gopls = {
|
||||
analyses = {
|
||||
unusedparams = true,
|
||||
unusedwrite = true,
|
||||
shadow = true,
|
||||
},
|
||||
staticcheck = true,
|
||||
usePlaceholders = true,
|
||||
hints = {
|
||||
assignVariableTypes = true,
|
||||
compositeLiteralFields = true,
|
||||
compositeLiteralTypes = true,
|
||||
functionTypeParameters = true,
|
||||
parameterNames = true,
|
||||
rangeVariableTypes = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
require("lsp_signature").setup({
|
||||
debug = false,
|
||||
bind = true, -- registers signature handler
|
||||
doc_lines = 10,
|
||||
max_height = 12,
|
||||
max_width = function() return math.floor(vim.api.nvim_win_get_width(0) * 0.8) end,
|
||||
wrap = true,
|
||||
floating_window = true, -- show the popup
|
||||
floating_window_above_cur_line = true,
|
||||
floating_window_off_x = 1,
|
||||
floating_window_off_y = 0,
|
||||
|
||||
-- IMPORTANT: don’t inline (you can change later if you want)
|
||||
hint_enable = true,
|
||||
hint_inline = function() return false end,
|
||||
|
||||
hint_prefix = "🐼 ",
|
||||
hint_scheme = "String",
|
||||
hi_parameter = "LspSignatureActiveParameter",
|
||||
handler_opts = { border = "rounded" },
|
||||
|
||||
always_trigger = false,
|
||||
extra_trigger_chars = { "(", "," }, -- good default
|
||||
zindex = 200,
|
||||
padding = "",
|
||||
timer_interval = 200,
|
||||
})
|
||||
55
home/config/nvim/lua/options.lua
Normal file
55
home/config/nvim/lua/options.lua
Normal file
@@ -0,0 +1,55 @@
|
||||
local vim = vim
|
||||
|
||||
vim.o.number = true
|
||||
vim.o.relativenumber = true
|
||||
vim.o.tabstop = 2
|
||||
vim.o.shiftwidth = 2
|
||||
vim.o.wrap = false
|
||||
vim.o.scrolloff = 5
|
||||
vim.o.colorcolumn = "80"
|
||||
vim.o.wildmenu = true
|
||||
vim.o.wildmode = "longest:full,full"
|
||||
vim.o.wildoptions = "pum"
|
||||
vim.g.mapleader = " "
|
||||
vim.o.termguicolors = true
|
||||
vim.o.winborder = "double"
|
||||
vim.o.clipboard = "unnamedplus"
|
||||
vim.o.completeopt = "menuone"
|
||||
-- vim.o.completeopt = "menuone,noinsert,noselect"
|
||||
vim.o.cursorline = true
|
||||
|
||||
vim.g.netrw_keepdir = 1
|
||||
vim.g.netrw_winsize = 15
|
||||
vim.g.netrw_banner = 0
|
||||
vim.g.netrw_localcopydircmd = 'cp -avr'
|
||||
vim.g.netrw_liststyle = 3
|
||||
vim.g.netrw_browse_split = 4
|
||||
|
||||
vim.o.foldmethod = "expr"
|
||||
vim.o.foldexpr = "nvim_treesitter#foldexpr()"
|
||||
vim.o.foldlevel = 1
|
||||
vim.o.foldenable = true
|
||||
|
||||
vim.o.undofile = true
|
||||
vim.o.undodir = vim.fn.stdpath("data") .. "/undo"
|
||||
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
pattern = "help",
|
||||
callback = function()
|
||||
vim.opt_local.wrap = true
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
pattern = "markdown",
|
||||
callback = function()
|
||||
vim.opt_local.wrap = true
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd("BufWritePost", {
|
||||
pattern = ".wiki",
|
||||
callback = function()
|
||||
vim.cmd("VimwikiGenerateLinks")
|
||||
end,
|
||||
})
|
||||
114
home/config/nvim/lua/plugins.lua
Normal file
114
home/config/nvim/lua/plugins.lua
Normal file
@@ -0,0 +1,114 @@
|
||||
local vim = vim
|
||||
vim.pack.add({
|
||||
{ src = "https://github.com/folke/tokyonight.nvim" },
|
||||
{ src = "https://github.com/nvim-tree/nvim-web-devicons" },
|
||||
{ src = "https://github.com/ibhagwan/fzf-lua" },
|
||||
{ src = "https://github.com/echasnovski/mini.pick" },
|
||||
{ src = "https://github.com/echasnovski/mini.icons" },
|
||||
{ src = "https://github.com/echasnovski/mini.files" },
|
||||
{ src = "https://github.com/echasnovski/mini.pairs" },
|
||||
{ src = "https://github.com/echasnovski/mini.notify" },
|
||||
{ src = "https://github.com/echasnovski/mini.surround" },
|
||||
{ src = "https://github.com/echasnovski/mini.indentscope" },
|
||||
{ src = "https://github.com/echasnovski/mini.fuzzy" },
|
||||
{ src = "https://github.com/echasnovski/mini.tabline" },
|
||||
{ src = "https://github.com/nvim-lualine/lualine.nvim" },
|
||||
{ src = "https://github.com/folke/which-key.nvim" },
|
||||
{ src = "https://github.com/L3MON4D3/LuaSnip" },
|
||||
{ src = "https://github.com/neovim/nvim-lspconfig" },
|
||||
{ src = "https://github.com/hrsh7th/nvim-cmp" },
|
||||
{ src = "https://github.com/hrsh7th/cmp-nvim-lsp" },
|
||||
{ src = "https://github.com/hrsh7th/cmp-buffer" },
|
||||
{ src = "https://github.com/hrsh7th/cmp-path" },
|
||||
{ src = "https://github.com/hrsh7th/cmp-cmdline" },
|
||||
{ src = "https://github.com/hrsh7th/cmp-nvim-lua" },
|
||||
{ src = "https://github.com/saadparwaiz1/cmp_luasnip" },
|
||||
{ src = "https://github.com/github/copilot.vim" },
|
||||
{ src = "https://github.com/pysan3/pathlib.nvim" },
|
||||
-- { src = "https://github.com/nvim-orgmode/orgmode" },
|
||||
-- { src = "https://github.com/chipsenkbeil/org-roam.nvim" },
|
||||
-- { src = "https://github.com/danilshvalov/org-modern.nvim" },
|
||||
{ src = "https://github.com/nvim-orgmode/org-bullets.nvim" },
|
||||
{ src = "https://github.com/lukas-reineke/headlines.nvim" },
|
||||
{ src = "https://github.com/michaelb/sniprun", run = "bash install.sh 1" },
|
||||
{ src = "https://github.com/akinsho/toggleterm.nvim" },
|
||||
{ src = "https://github.com/kdheepak/lazygit.nvim" },
|
||||
{ src = "https://github.com/saecki/crates.nvim" },
|
||||
{ src = "https://github.com/nvim-treesitter/nvim-treesitter" },
|
||||
{ src = "https://github.com/folke/trouble.nvim" },
|
||||
{ src = "https://github.com/folke/todo-comments.nvim" },
|
||||
{ src = "https://github.com/MunifTanjim/nui.nvim" },
|
||||
{ src = "https://github.com/huantrinh1802/m_taskwarrior_d.nvim" },
|
||||
{ src = "https://github.com/rmagatti/auto-session" },
|
||||
{ src = "https://github.com/romgrk/barbar.nvim" },
|
||||
{ src = "https://github.com/christoomey/vim-tmux-navigator" },
|
||||
{ src = "https://github.com/rachartier/tiny-inline-diagnostic.nvim" },
|
||||
{ src = "https://github.com/zeioth/garbage-day.nvim" },
|
||||
{ src = "https://github.com/ray-x/lsp_signature.nvim" },
|
||||
{ src = "https://github.com/DNLHC/glance.nvim" },
|
||||
{ src = "https://github.com/rmagatti/logger.nvim" },
|
||||
{ src = "https://github.com/rmagatti/goto-preview" },
|
||||
})
|
||||
|
||||
require('mini.icons').setup({})
|
||||
require('mini.pick').setup({})
|
||||
require('mini.pairs').setup({})
|
||||
require('mini.notify').setup({})
|
||||
require('mini.surround').setup({})
|
||||
require('mini.indentscope').setup({})
|
||||
require('mini.tabline').setup({})
|
||||
require('mini.fuzzy').setup({})
|
||||
require('lualine').setup({ options = { theme = 'tokyonight' } })
|
||||
require('which-key').setup({})
|
||||
require('fzf-lua').setup({})
|
||||
require('crates').setup({})
|
||||
require('todo-comments').setup({
|
||||
options = {
|
||||
keywords = {
|
||||
FIX = {
|
||||
icon = " ", -- icon used for the sign, and in search results
|
||||
color = "error", -- can be a hex color, or a named color (see below)
|
||||
alt = { "FIXME", "BUG", "FIXIT", "ISSUE" }, -- a set of other keywords that all map to this FIX keywords
|
||||
-- signs = false, -- configure signs for some keywords individually
|
||||
},
|
||||
TODO = { icon = " ", color = "info" },
|
||||
HACK = { icon = " ", color = "warning" },
|
||||
WARN = { icon = " ", color = "warning", alt = { "WARNING", "XXX" } },
|
||||
PERF = { icon = " ", alt = { "OPTIM", "PERFORMANCE", "OPTIMIZE" } },
|
||||
NOTE = { icon = " ", color = "hint", alt = { "INFO" } },
|
||||
TEST = { icon = "⏲ ", color = "test", alt = { "TESTING", "PASSED", "FAILED" } },
|
||||
},
|
||||
}
|
||||
})
|
||||
require('trouble').setup({})
|
||||
-- require('orgmode').setup({
|
||||
-- org_agenda_files = { '~/org/*' },
|
||||
-- org_default_notes_file = '~/org/notes.org',
|
||||
-- })
|
||||
-- require('org-roam').setup({ directory = '~/org/roam' })
|
||||
-- require("orgmode").setup({})
|
||||
require('org-bullets').setup({})
|
||||
require('headlines').setup({})
|
||||
require('sniprun').setup({
|
||||
binary_path = '/home/th3r00t/.local/share/nvim/site/pack/core/opt/sniprun/\
|
||||
target/release/sniprun'
|
||||
})
|
||||
require('toggleterm').setup({
|
||||
size = 20,
|
||||
open_mapping = [[<c-\>]],
|
||||
hide_numbers = true,
|
||||
shade_filetypes = {},
|
||||
shading_factor = 2,
|
||||
start_in_insert = true,
|
||||
insert_mappings = true,
|
||||
persist_size = true,
|
||||
direction = 'horizontal',
|
||||
close_on_exit = true,
|
||||
shell = vim.o.shell,
|
||||
})
|
||||
require('m_taskwarrior_d').setup({})
|
||||
require("auto-session").setup({
|
||||
suppressed_dirs = { "~/Downloads", "~/Documents", "~/Projects", "~/" },
|
||||
})
|
||||
require('barbar').setup({})
|
||||
require('goto-preview').setup({ default_mappings = true })
|
||||
11
home/config/nvim/lua/terminal.lua
Normal file
11
home/config/nvim/lua/terminal.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
function _G.set_terminal_keymaps()
|
||||
local opts = { buffer = 0 }
|
||||
vim.keymap.set('t', '<esc>', [[<C-\><C-n>]], opts)
|
||||
vim.keymap.set('t', 'jk', [[<C-\><C-n>]], opts)
|
||||
vim.keymap.set('t', '<C-h>', [[<Cmd>wincmd h<CR>]], opts)
|
||||
vim.keymap.set('t', '<C-j>', [[<Cmd>wincmd j<CR>]], opts)
|
||||
vim.keymap.set('t', '<C-k>', [[<Cmd>wincmd k<CR>]], opts)
|
||||
vim.keymap.set('t', '<C-l>', [[<Cmd>wincmd l<CR>]], opts)
|
||||
end
|
||||
|
||||
vim.cmd('autocmd! TermOpen term://* lua set_terminal_keymaps()')
|
||||
11
home/config/nvim/lua/treesitter.lua
Normal file
11
home/config/nvim/lua/treesitter.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
local configs = require('nvim-treesitter.configs')
|
||||
configs.setup({
|
||||
ensure_installed = {
|
||||
"ini", "bash", "c", "lua", "vim", "vimdoc", "query", "python",
|
||||
"rust", "zig", "typescript", "svelte", "css", "html", "nix"
|
||||
},
|
||||
sync_install = false,
|
||||
highlight = { enable = true },
|
||||
indent = { enable = true, disable = { "norg" }, },
|
||||
incremental_selection = { enable = true },
|
||||
})
|
||||
11
home/config/nvim/lua/utils/reload.lua
Normal file
11
home/config/nvim/lua/utils/reload.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
for name,_ in pairs(package.loaded) do
|
||||
if name:match("^t3")
|
||||
or name:match("^options")
|
||||
or name:match("^overrides")
|
||||
or name:match("^plugins")
|
||||
or name:match("keymaps")
|
||||
or name:match("^reload")
|
||||
then
|
||||
package.loaded[name] = nil
|
||||
end
|
||||
end
|
||||
187
home/config/nvim/lua/utils/t3_functions.lua
Normal file
187
home/config/nvim/lua/utils/t3_functions.lua
Normal file
@@ -0,0 +1,187 @@
|
||||
local vim = vim
|
||||
local fzflua = require("fzf-lua")
|
||||
|
||||
function t3_find_file()
|
||||
-- local file_name = vim.fn.input("Find File: ", "", "file")
|
||||
fzflua.files()
|
||||
end
|
||||
|
||||
function t3_recent_files()
|
||||
fzflua.oldfiles()
|
||||
end
|
||||
|
||||
function t3_org_files()
|
||||
fzflua.files({ cwd = '~/org/'})
|
||||
end
|
||||
|
||||
function t3_project_files()
|
||||
fzflua.files({ cwd = '~/Projects/'})
|
||||
end
|
||||
|
||||
function t3_dot_files()
|
||||
fzflua.files({ cwd = '~/.dotfiles/'})
|
||||
end
|
||||
|
||||
function t3_config_files()
|
||||
fzflua.files({ cwd = '~/.dotfiles/'})
|
||||
end
|
||||
|
||||
function t3_snip_capture(name)
|
||||
if type(name) ~= "string" or name == "" then
|
||||
print("Error: Invalid snippet name")
|
||||
return
|
||||
end
|
||||
-- local timestamp = os.date("%Y%m%d%H%M%S")
|
||||
local snippet_path = "~/.config/nvim/snippets/"
|
||||
local filename = snippet_path .. name:gsub("%s+", "_") .. ".lua"
|
||||
local file = io.open(vim.fn.expand(filename), "w")
|
||||
if file == nil then
|
||||
print("Error: Could not open file for editing.")
|
||||
return
|
||||
end
|
||||
local previous_buffer = vim.api.nvim_get_current_buf()
|
||||
file:write("local ls = require('luasnip')\n\nls.add_snippets(\"{}\", {\n\tls.parser.parse_snippet(\n\t\t'{}',\n\t\t'{}'),\n})")
|
||||
file:close()
|
||||
vim.cmd("e " .. filename)
|
||||
vim.bo.filetype = 'lua'
|
||||
-- vim.cmd("Neorg inject-metadata")
|
||||
-- Set an autocmd to return to the previous buffer when the note buffer is closed
|
||||
vim.api.nvim_create_autocmd("BufLeave", {
|
||||
buffer = 0, -- Current buffer (the note buffer)
|
||||
callback = function()
|
||||
load_snippets_from_directory(snippet_path)
|
||||
vim.cmd("buffer " .. previous_buffer)
|
||||
end,
|
||||
})
|
||||
print("Captured snippet: " .. filename)
|
||||
end
|
||||
|
||||
function t3_org_capture(name)
|
||||
if type(name) ~= "string" or name == "" then
|
||||
print("Error: Invalid note name")
|
||||
return
|
||||
end
|
||||
local timestamp = os.date("%Y%m%d%H%M%S")
|
||||
local org_path = "~/org/.org-roam/"
|
||||
local filename = org_path .. timestamp .. "-" .. name:gsub("%s+", "_") .. ".norg"
|
||||
local file = io.open(vim.fn.expand(filename), "w")
|
||||
if file == nil then
|
||||
print("Error: Could not open file for editing.")
|
||||
return
|
||||
end
|
||||
local previous_buffer = vim.api.nvim_get_current_buf()
|
||||
file:write("* " .. name .. "\n\n")
|
||||
file:close()
|
||||
vim.cmd("e " .. filename)
|
||||
vim.bo.filetype = 'norg'
|
||||
vim.cmd("Neorg inject-metadata")
|
||||
-- Set an autocmd to return to the previous buffer when the note buffer is closed
|
||||
vim.api.nvim_create_autocmd("BufLeave", {
|
||||
buffer = 0, -- Current buffer (the note buffer)
|
||||
callback = function()
|
||||
vim.cmd("buffer " .. previous_buffer)
|
||||
end,
|
||||
})
|
||||
print("Captured note: " .. filename)
|
||||
end
|
||||
|
||||
vim.api.nvim_create_user_command(
|
||||
'NeorgCapture',
|
||||
function()
|
||||
-- local title = vim.fn.input("Title: ")
|
||||
local current_workspace = vim.g.neorg_workspace_name
|
||||
if not current_workspace then
|
||||
vim.cmd("Neorg workspace default")
|
||||
end
|
||||
vim.ui.input({ prompt = "Enter note name: "}, function(note_name)
|
||||
if not note_name or note_name == "" then
|
||||
print("Error: Note name required!")
|
||||
return
|
||||
end
|
||||
t3_org_capture(note_name)
|
||||
end
|
||||
)
|
||||
end,
|
||||
{ nargs = 0, desc = "Capture a Neorg note" }
|
||||
)
|
||||
|
||||
vim.api.nvim_create_user_command(
|
||||
'CaptureSnip',
|
||||
function()
|
||||
-- local title = vim.fn.input("Title: ")
|
||||
-- local current_workspace = vim.g.neorg_workspace_name
|
||||
-- if not current_workspace then
|
||||
-- vim.cmd("Neorg workspace default")
|
||||
-- end
|
||||
vim.ui.input({ prompt = "Enter snippet name: "}, function(snip_name)
|
||||
if not snip_name or snip_name == "" then
|
||||
print("Error: Snippet name required!")
|
||||
return
|
||||
end
|
||||
t3_snip_capture(snip_name)
|
||||
end
|
||||
)
|
||||
end,
|
||||
{ nargs = 0, desc = "Capture a Neorg note" }
|
||||
)
|
||||
function t3_buffers()
|
||||
fzflua.buffers()
|
||||
end
|
||||
|
||||
function t3_tabs()
|
||||
fzflua.tabs()
|
||||
end
|
||||
|
||||
function t3_live_grep(state)
|
||||
state = state or 0
|
||||
if state == 0 then
|
||||
fzflua.live_grep()
|
||||
else
|
||||
fzflua.live_grep_resume()
|
||||
end
|
||||
end
|
||||
|
||||
function t3_grep(state)
|
||||
state = state or 0
|
||||
if state == 0 then
|
||||
fzflua.grep_project()
|
||||
else
|
||||
fzflua.grep()
|
||||
end
|
||||
end
|
||||
|
||||
local function is_netrw_open()
|
||||
for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
|
||||
local buf = vim.api.nvim_win_get_buf(win)
|
||||
if vim.bo[buf].filetype == "netrw" then
|
||||
return true, win
|
||||
end
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
function t3_toggle_netrw()
|
||||
local is_open, win = is_netrw_open()
|
||||
if is_open then
|
||||
vim.api.nvim_win_close(win, true)
|
||||
else
|
||||
vim.cmd("Lexplore")
|
||||
end
|
||||
end
|
||||
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
pattern = { "markdown", "norg", "md", "wiki" }, -- Set for markdown file type
|
||||
callback = function()
|
||||
vim.api.nvim_buf_set_keymap(0, "n", "<C-i>", "o* [ ] ", { noremap = true, silent = true })
|
||||
vim.api.nvim_buf_set_keymap(0, "i", "<C-i>", "<Esc>0wi* [ ] ", { noremap = true, silent = true })
|
||||
end,
|
||||
})
|
||||
vim.api.nvim_create_user_command("Split", function()
|
||||
vim.cmd("split")
|
||||
vim.cmd("wincmd j")
|
||||
end, {})
|
||||
|
||||
vim.api.nvim_create_user_command("Vsplit", function()
|
||||
vim.cmd("vsplit")
|
||||
vim.cmd("wincmd l")
|
||||
end, {})
|
||||
5
home/config/nvim/lua/utils/t3_overrides.lua
Normal file
5
home/config/nvim/lua/utils/t3_overrides.lua
Normal file
@@ -0,0 +1,5 @@
|
||||
-- vim.api.nvim_create_autocmd("winNew", {
|
||||
-- callback = function()
|
||||
-- vim.cmd("wincmd w")
|
||||
-- end,
|
||||
-- })
|
||||
109
home/config/nvim/lua/vimwiki.lua
Normal file
109
home/config/nvim/lua/vimwiki.lua
Normal file
@@ -0,0 +1,109 @@
|
||||
local vim = vim
|
||||
local opt = vim.opt
|
||||
|
||||
-- opt.wildmenu = true
|
||||
-- vim.g.netrw_keepdir = 0
|
||||
-- vim.treesitter.language.register("markdown", "vimwiki")
|
||||
-- vim.g.vimwiki_folding = 'expr'
|
||||
-- vim.g.vimwiki_header_type = "="
|
||||
|
||||
-- vim.api.nvim_create_autocmd({ "BufWritePost" }, {
|
||||
-- pattern = "*.wiki", -- Adjust this pattern if your Vimwiki files have a different extension
|
||||
-- callback = function()
|
||||
-- vim.cmd("TWSyncTasks")
|
||||
-- end,
|
||||
-- })
|
||||
|
||||
-- Autocommand to trigger LuaSnip snippet expansion for new diary files
|
||||
vim.api.nvim_create_autocmd("BufNewFile", {
|
||||
pattern = "diary/*.wiki", -- Adjust this path to match your diary directory
|
||||
callback = function()
|
||||
-- Expand the 'diary_template' snippet automatically
|
||||
ls.snip_expand(ls.snippets.diary_template[1])
|
||||
end,
|
||||
})
|
||||
vim.g.vimwiki_automatic_nested_syntaxes = 1
|
||||
vim.g.vimwiki_list = {
|
||||
{
|
||||
name = "Personal Wiki",
|
||||
path = '/home/th3r00t/wiki/',
|
||||
path_html = '/home/th3r00t/wiki/html/',
|
||||
syntax = 'default',
|
||||
ext = '.wiki',
|
||||
diary_rel_path = 'diary/',
|
||||
diary_index = "diary_index",
|
||||
auto_tags = 1,
|
||||
auto_toc = 1,
|
||||
auto_export = 1,
|
||||
template_path = "/home/th3r00t/wiki/templates/",
|
||||
template_default = "def_template",
|
||||
template_ext = "html",
|
||||
css_name = "main.css",
|
||||
maxhi = 1, -- BUG: Can be a source of lag.
|
||||
diary_caption_level = 1,
|
||||
bullet_types = { "-", "*", "#", "→" },
|
||||
cycle_bullets = 1,
|
||||
generated_links_caption = 1,
|
||||
listsyms = '✗○◐●✓',
|
||||
-- listsym_rejected = '✗',
|
||||
auto_diary_index = 1,
|
||||
auto_generate_links = 1,
|
||||
auto_generate_tags = 1,
|
||||
exclude_files = { "**/README.md" },
|
||||
rss_name = "feed.rss",
|
||||
base_url = "https://th3r00t.net",
|
||||
}
|
||||
}
|
||||
vim.g.vimwiki_syntax_plugins = {
|
||||
codeblock = {
|
||||
["```lua"] = { parser = "lua" },
|
||||
["```python"] = { parser = "python" },
|
||||
["```javascript"] = { parser = "javascript" },
|
||||
["```bash"] = { parser = "bash" },
|
||||
["```html"] = { parser = "html" },
|
||||
["```css"] = { parser = "css" },
|
||||
["```c"] = { parser = "c" },
|
||||
["```zig"] = { parser = "zig" },
|
||||
},
|
||||
}
|
||||
vim.g.vimwiki_toc_header = "Navigation"
|
||||
vim.g.vimwiki_toc_header_level = 2
|
||||
vim.g.vimwiki_hl_cb_checked = 1
|
||||
vim.g.vimwiki_global_ext = 1
|
||||
vim.g.vimwiki_auto_chdir = 1
|
||||
vim.g.wimwiki_markdown_link_ext = 1
|
||||
-- vim.g.vimwiki_folding = 'list'
|
||||
vim.g.vimwiki_folding = 'expr'
|
||||
vim.g.vimwiki_use_calendar = 1
|
||||
vim.api.nvim_set_keymap('n', '<Leader>ww', '<Cmd>VimwikiIndex<CR>', { noremap = true, silent = true })
|
||||
vim.api.nvim_set_keymap('n', '<Leader>wt', '<Cmd>VimwikiTabIndex<CR>', { noremap = true, silent = true })
|
||||
vim.api.nvim_set_keymap('n', '<Leader>ws', '<Cmd>VimwikiUISelect<CR>', { noremap = true, silent = true })
|
||||
local function setup_vimwiki_highlights()
|
||||
-- Define color scheme mappings
|
||||
local colors = {
|
||||
header1 = "#81a1c1", -- Tokyo Night blue
|
||||
header2 = "#88c0d0", -- Tokyo Night light blue
|
||||
header3 = "#8fbcbb", -- Tokyo Night greenish blue
|
||||
bold = "#eceff4", -- Tokyo Night bright white
|
||||
italic = "#5e81ac", -- Tokyo Night dark blue
|
||||
link = "#b48ead", -- Tokyo Night purple
|
||||
list = "#d08770", -- Tokyo Night orange
|
||||
}
|
||||
|
||||
-- Apply highlights for vimwiki syntax elements
|
||||
vim.api.nvim_set_hl(0, "VimwikiHeader1", { fg = colors.header1, bold = true })
|
||||
vim.api.nvim_set_hl(0, "VimwikiHeader2", { fg = colors.header2, bold = true })
|
||||
vim.api.nvim_set_hl(0, "VimwikiHeader3", { fg = colors.header3, bold = true })
|
||||
vim.api.nvim_set_hl(0, "VimwikiBold", { fg = colors.bold, bold = true })
|
||||
vim.api.nvim_set_hl(0, "VimwikiItalic", { fg = colors.italic, italic = true })
|
||||
vim.api.nvim_set_hl(0, "VimwikiLink", { fg = colors.link, underline = true })
|
||||
vim.api.nvim_set_hl(0, "VimwikiList", { fg = colors.list })
|
||||
end
|
||||
setup_vimwiki_highlights()
|
||||
-- Define the Lua function for generating the diary template
|
||||
--
|
||||
vim.pack.add({
|
||||
{ src = "https://github.com/vimwiki/vimwiki", opt = true },
|
||||
})
|
||||
|
||||
vim.cmd.packadd("vimwiki")
|
||||
Reference in New Issue
Block a user