Compare commits

...

9 Commits

Author SHA1 Message Date
e46d6b0dd3 [bin] Improve weather command 2025-12-13 13:59:56 +00:00
2c404cf540 [bin] Add more validation and checks to Stowage 2025-12-13 13:57:12 +00:00
1bb76e4b24 [bin] Improve Stowage
Switch to using logging, and modernized Python usage.
2025-12-13 13:51:36 +00:00
088491234b [irssi] Remove 2025-12-13 13:31:29 +00:00
b2b326544c [raycast] Remove 2025-12-13 13:28:23 +00:00
04206a5471 [shell-common] Support fzf on awslogin 2025-12-12 22:27:11 +00:00
Andrew Williams
4115692e51 [macos] Add Homebrew installs 2025-11-14 09:25:08 +00:00
Andrew Williams
d27de08a5c [shell-common] Rename check function 2025-11-14 09:21:44 +00:00
Andrew Williams
7b493cbfde [shell-common] Add AWS credentials check 2025-11-14 09:20:41 +00:00
16 changed files with 255 additions and 1720 deletions

View File

@@ -27,144 +27,180 @@ SOFTWARE.
import argparse import argparse
import fnmatch import fnmatch
import logging
import os import os
from os import path
import re import re
import shutil import shutil
import sys import sys
from pathlib import Path
from typing import Callable, List
logger = logging.getLogger(__name__)
def add(args): def add(args: argparse.Namespace) -> None:
target = path.realpath(args.target) """Add a file to a package by moving it and creating a symlink."""
file_path = path.realpath(args.file) target = Path(args.target).resolve()
package = path.realpath(path.join(args.repository, args.packages[0])) file_path = Path(args.file).resolve()
if path.commonprefix([target, file_path]) != target: package = Path(args.repository, args.packages[0]).resolve()
print(f"error: '{args.add}' not under '{args.target}'", file=sys.stderr)
if not file_path.is_relative_to(target):
logger.error("'%s' not under '%s'", args.file, args.target)
sys.exit(1) sys.exit(1)
rest = file_path[len(target) + 1 :]
dest_path = path.join(package, rest) rest = file_path.relative_to(target)
dest = path.dirname(dest_path) dest_path = package / rest
if not path.exists(dest): dest_dir = dest_path.parent
if args.verbose:
print("DIR", dest) if dest_path.exists():
os.makedirs(dest, mode=0o755) logger.error("file already exists in package: %s", dest_path)
if args.verbose: sys.exit(1)
print("SWAP", dest_path, file_path)
if not dest_dir.exists():
logger.info("DIR %s", dest_dir)
if not args.dry_run: if not args.dry_run:
shutil.move(file_path, dest) dest_dir.mkdir(parents=True, mode=0o755, exist_ok=True)
# TODO Should really check if the symlink fails here.
os.symlink(dest_path, file_path) logger.info("SWAP %s %s", dest_path, file_path)
if not args.dry_run:
shutil.move(str(file_path), str(dest_path))
try:
file_path.symlink_to(dest_path)
except OSError as e:
logger.error("failed to create symlink: %s", e)
# Attempt to restore the file
try:
shutil.move(str(dest_path), str(file_path))
except Exception as restore_error:
logger.error("failed to restore file: %s", restore_error)
sys.exit(1)
def install(args, is_excluded): def install(args: argparse.Namespace, is_excluded: Callable[[str], bool]) -> None:
"""Install packages by creating symlinks from repository to target."""
for package in args.packages: for package in args.packages:
package_dir = path.join(args.repository, package) package_dir = Path(args.repository, package)
if not path.isdir(package_dir): if not package_dir.is_dir():
print(f"no such package: {package}; skipping", file=sys.stderr) logger.warning("no such package: %s; skipping", package)
continue continue
# Walk the package # Walk the package
for root, _, files in os.walk(package_dir, followlinks=True): for root, _, files in os.walk(package_dir, followlinks=True):
root_path = Path(root)
files = [filename for filename in files if not is_excluded(filename)] files = [filename for filename in files if not is_excluded(filename)]
if len(files) == 0: if not files:
continue continue
rest = root[len(package_dir) + 1 :]
dest = path.join(args.target, rest) rest = root_path.relative_to(package_dir)
dest = Path(args.target) / rest
# Create the directory path # Create the directory path
if rest != "": if rest != Path("."):
# If a non-directory exists with the same name and clobber is enabled, get rid of it. # If a non-directory exists with the same name and clobber is enabled, get rid of it.
if path.exists(dest) and not path.isdir(dest) and args.clobber: if dest.exists() and not dest.is_dir() and args.clobber:
if args.verbose: logger.info("UNLINK %s", dest)
print("UNLINK", dest)
if not args.dry_run: if not args.dry_run:
os.unlink(dest) dest.unlink()
# Make directory # Make directory
if args.verbose: if not dest.exists():
print("DIR", dest) logger.info("DIR %s", dest)
if not args.dry_run and not path.exists(dest): if not args.dry_run:
os.makedirs(dest, mode=0o755) dest.mkdir(parents=True, mode=0o755, exist_ok=True)
# Process files # Process files
for filename in files: for filename in files:
src_path = path.realpath(path.join(root, filename)) src_path = (root_path / filename).resolve()
dest_path = path.join(dest, filename) dest_path = dest / filename
# Skip if the file exists and we're not clobbering # Skip if the file exists and we're not clobbering
if path.exists(dest_path) and not args.clobber: if dest_path.exists() and not args.clobber:
if args.verbose: logger.info("SKIP %s", dest_path)
print("SKIP", dest_path)
continue continue
# Does the file already exist? # Does the file already exist?
if path.isfile(dest_path): if dest_path.is_file() or dest_path.is_symlink():
if args.verbose: logger.info("UNLINK %s", dest_path)
print("UNLINK", dest_path)
if not args.dry_run: if not args.dry_run:
os.unlink(dest_path) dest_path.unlink()
# Link the file # Link the file
if args.verbose: logger.info("LINK %s %s", src_path, dest_path)
print("LINK", src_path, dest_path)
if not args.dry_run: if not args.dry_run:
os.symlink(src_path, dest_path) try:
dest_path.symlink_to(src_path)
except OSError as e:
logger.error("failed to create symlink %s: %s", dest_path, e)
def uninstall(args, is_excluded): def uninstall(args: argparse.Namespace, is_excluded: Callable[[str], bool]) -> None:
dirs = [] """Uninstall packages by removing symlinks."""
dirs: List[Path] = []
for package in args.packages: for package in args.packages:
package_dir = path.join(args.repository, package) package_dir = Path(args.repository, package)
if not path.isdir(package_dir): if not package_dir.is_dir():
print(f"no such package: {package}; skipping", file=sys.stderr) logger.warning("no such package: %s; skipping", package)
continue continue
for root, _, files in os.walk(package_dir, followlinks=True): for root, _, files in os.walk(package_dir, followlinks=True):
root_path = Path(root)
files = [filename for filename in files if not is_excluded(filename)] files = [filename for filename in files if not is_excluded(filename)]
if len(files) == 0: if not files:
continue continue
rest = root[len(package_dir) + 1 :]
dest = path.join(args.target, rest) rest = root_path.relative_to(package_dir)
if rest != "": dest = Path(args.target) / rest
if rest != Path("."):
dirs.append(dest) dirs.append(dest)
for filename in files: for filename in files:
dest_path = path.join(dest, filename) dest_path = dest / filename
if path.islink(dest_path): if not dest_path.exists():
src_path = path.realpath(path.join(root, filename)) logger.debug("does not exist: %s", dest_path)
if path.realpath(dest_path) == src_path: continue
if args.verbose:
print("UNLINK", dest_path) if dest_path.is_symlink():
src_path = (root_path / filename).resolve()
try:
if dest_path.resolve() == src_path:
logger.info("UNLINK %s", dest_path)
if not args.dry_run: if not args.dry_run:
os.unlink(dest_path) dest_path.unlink()
elif args.verbose: else:
print("SKIP", dest_path) logger.info("SKIP %s (points elsewhere)", dest_path)
elif args.verbose: except (OSError, RuntimeError) as e:
print("SKIP", dest_path) logger.warning("error checking symlink %s: %s", dest_path, e)
else:
logger.info("SKIP %s (not a symlink)", dest_path)
# Delete the directories if empty. # Delete the directories if empty.
for dir_path in sorted(dirs, key=len, reverse=True): for dir_path in sorted(dirs, key=lambda p: len(str(p)), reverse=True):
if not dir_path.exists():
continue
try: try:
if args.verbose: logger.info("RMDIR %s", dir_path)
print("RMDIR", dir_path)
if not args.dry_run: if not args.dry_run:
os.rmdir(dir_path) dir_path.rmdir()
except OSError: except OSError:
pass logger.debug("directory not empty: %s", dir_path)
def make_argparser(): def make_argparser() -> argparse.ArgumentParser:
"""Create and configure the argument parser."""
parser = argparse.ArgumentParser(description="A dotfile package manager.") parser = argparse.ArgumentParser(description="A dotfile package manager.")
parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output") parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
parser.add_argument("--dry-run", "-n", action="store_true", help="Dry run.") parser.add_argument("--dry-run", "-n", action="store_true", help="Dry run.")
parser.add_argument( parser.add_argument(
"--target", "--target",
"-t", "-t",
default=path.expanduser("~"), default=str(Path.home()),
help="Target directory in which to place symlinks", help="Target directory in which to place symlinks",
) )
parser.add_argument( parser.add_argument(
"--repository", "--repository",
"-r", "-r",
default=path.expanduser("~/.dotfiles"), default=str(Path.home() / ".dotfiles"),
help="The location of the dotfile repository", help="The location of the dotfile repository",
) )
parser.add_argument( parser.add_argument(
@@ -184,7 +220,7 @@ def make_argparser():
subparsers = parser.add_subparsers(dest="command", help="sub-command help") subparsers = parser.add_subparsers(dest="command", help="sub-command help")
# List # List
parser_add = subparsers.add_parser("list", help="List packages in the repository") subparsers.add_parser("list", help="List packages in the repository")
# Add # Add
parser_add = subparsers.add_parser("add", help="Add a file to a package") parser_add = subparsers.add_parser("add", help="Add a file to a package")
@@ -208,31 +244,68 @@ def make_argparser():
return parser return parser
def main(): def main() -> None:
"""Main entry point for the stowage script."""
parser = make_argparser() parser = make_argparser()
args = parser.parse_args() args = parser.parse_args()
if args.dry_run:
args.verbose = True # Configure logging
log_level = logging.INFO if args.verbose or args.dry_run else logging.WARNING
logging.basicConfig(
level=log_level,
format='%(message)s',
stream=sys.stdout
)
# Validate repository exists
repo_path = Path(args.repository)
if not repo_path.exists():
logger.error("repository does not exist: %s", args.repository)
sys.exit(1)
# Validate target exists
target_path = Path(args.target)
if not target_path.exists():
logger.error("target directory does not exist: %s", args.target)
sys.exit(1)
exclude = [re.compile(fnmatch.translate(pattern)) for pattern in args.exclude] exclude = [re.compile(fnmatch.translate(pattern)) for pattern in args.exclude]
def is_excluded(filename): def is_excluded(filename: str) -> bool:
"""Check if a filename matches any exclusion pattern."""
return any(pattern.match(filename) for pattern in exclude) return any(pattern.match(filename) for pattern in exclude)
if args.command == "list": if args.command == "list":
for dir in os.listdir(args.repository): if not repo_path.is_dir():
if path.isdir(path.join(args.repository, dir)) and dir[0] != ".": logger.error("repository is not a directory: %s", args.repository)
print(dir) sys.exit(1)
packages = sorted([
item.name for item in repo_path.iterdir()
if item.is_dir() and not item.name.startswith(".")
])
if packages:
for package in packages:
print(package)
else:
logger.info("no packages found in repository")
elif args.command == "add": elif args.command == "add":
if len(args.packages) > 1: if len(args.packages) > 1:
parser.error("--add only works with a single package") parser.error("add only works with a single package")
args.file = path.normpath(path.join(args.target, args.file)) file_path = Path(args.file)
if not path.isfile(args.file): # Handle both absolute and relative paths
if not file_path.is_absolute():
file_path = Path(args.target) / file_path
if not file_path.is_file():
parser.error(f"no such file: {args.file}") parser.error(f"no such file: {args.file}")
args.file = str(file_path)
add(args) add(args)
elif args.command == "install": elif args.command == "install":
install(args, is_excluded) install(args, is_excluded)
elif args.command == "uninstall": elif args.command == "uninstall":
uninstall(args, is_excluded) uninstall(args, is_excluded)
else:
parser.print_help()
sys.exit(1)
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -1,5 +1,26 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail
show_help() {
cat << EOF
Usage: $(basename "$0") [LOCATION]
Fetch weather information from wttr.in for the specified location.
Arguments:
LOCATION Location to get weather for (default: St Helens)
Options:
-h, --help Show this help message
Examples:
$(basename "$0") # Get weather for St Helens
$(basename "$0") "New York" # Get weather for New York
$(basename "$0") "London,UK" # Get weather for London, UK
EOF
}
urlencode() { urlencode() {
# urlencode <string> # urlencode <string>
old_lc_collate=$LC_COLLATE old_lc_collate=$LC_COLLATE
@@ -9,7 +30,7 @@ urlencode() {
for ((i = 0; i < length; i++)); do for ((i = 0; i < length; i++)); do
local c="${1:i:1}" local c="${1:i:1}"
case $c in case $c in
[a-zA-Z0-9.~_-]) printf "$c" ;; [a-zA-Z0-9.~_-]) printf "%s" "$c" ;;
*) printf '%%%02X' "'$c" ;; *) printf '%%%02X' "'$c" ;;
esac esac
done done
@@ -17,5 +38,15 @@ urlencode() {
LC_COLLATE=$old_lc_collate LC_COLLATE=$old_lc_collate
} }
# Handle help flag
if [[ "${1:-}" == "-h" ]] || [[ "${1:-}" == "--help" ]]; then
show_help
exit 0
fi
location=$(urlencode "${1:-St Helens}") location=$(urlencode "${1:-St Helens}")
curl -s https://wttr.in/$location
if ! curl -sf "https://wttr.in/$location"; then
echo "Error: Failed to fetch weather data. Please check your internet connection or location name." >&2
exit 1
fi

View File

@@ -1 +0,0 @@
away.log

View File

@@ -1,244 +0,0 @@
# For irssi 0.8.4 by marmot
replaces = { };
abstracts = {
##
## generic
##
# text to insert at the beginning of each non-message line
line_start = "<%b*%n> ";
# timestamp styling, nothing by default
# timestamp = "$0";
timestamp = "%K$0-%n";
# any kind of text that needs hilighting, default is to bold
hilight = "$0";
# any kind of error message, default is bright red
error = "%R$0-%n";
# channel name is printed
channel = "%b$0-%n";
# nick is printed
nick = "%_$0-%_";
# nick host is printed
nickhost = "[$0-]";
# server name is printed
server = "$0-";
# some kind of comment is printed
comment = "[$0-]";
# reason for something is printed (part, quit, kick, ..)
reason = "[$0-]";
# mode change is printed ([+o nick])
mode = "%_($0-)%_";
##
## channel specific messages
##
# highlighted nick/host is printed (joins)
channick_hilight = "%b$0-%n";
chanhost_hilight = "{nickhost %b$0-%n}";
# nick/host is printed (parts, quits, etc.)
channick = "%b$0-%n";
chanhost = "{nickhost %b$0-%n}";
# highlighted channel name is printed
channelhilight = "%_$0-%_";
# ban/ban exception/invite list mask is printed
ban = "$0-";
##
## messages
##
# the basic styling of how to print message, $0 = nick mode, $1 = nick
msgnick = "%B<%n%_$0%_%b$1-%B>%n %|";
# message from you is printed. "msgownnick" specifies the styling of the
# nick ($0 part in msgnick) and "ownmsgnick" specifies the styling of the
# whole line.
# Example1: You want the message text to be green:
# ownmsgnick = "{msgnick $0 $1-}%g";
# Example2.1: You want < and > chars to be yellow:
# ownmsgnick = "%Y{msgnick $0 $1-%Y}%n";
# (you'll also have to remove <> from replaces list above)
# Example2.2: But you still want to keep <> grey for other messages:
# pubmsgnick = "%K{msgnick $0 $1-%K}%n";
# pubmsgmenick = "%K{msgnick $0 $1-%K}%n";
# pubmsghinick = "%K{msgnick $1 $0$2-%K}%n";
# ownprivmsgnick = "%K{msgnick $0-%K}%n";
# privmsgnick = "%K{msgnick %R$0-%K}%n";
# $0 = nick mode, $1 = nick
ownmsgnick = "%W<%n%_%_%b$1%n%W>%n%b %|";
ownnick = "$0-";
# public message in channel, $0 = nick mode, $1 = nick
pubmsgnick = "{msgnick $0 $1-}";
pubnick = "$0-";
# public message in channel meant for me, $0 = nick mode, $1 = nick
pubmsgmenick = "%Y<$0$1-> %|";
menick = "$0-";
# public highlighted message in channel
# $0 = highlight color, $1 = nick mode, $2 = nick
pubmsghinick = "%Y<$1$2-> %|";
# channel name is printed with message
msgchannel = "%w|%b$0-";
# private message, $0 = nick, $1 = host
privmsg = "<-%b$0%n[%b$1%n] ";
# private message from you, $0 = "msg", $1 = target nick
ownprivmsg = "->[%b$1-%n] $0";
# own private message in query
ownprivmsgnick = "%B<%n%_$0%_%b$1%B>%n%_ %|";
ownprivnick = "$0-";
# private message in query
privmsgnick = "{msgnick %b$0-%n}";
##
## Actions (/ME stuff)
##
# used internally by this theme
action_core = "%B $0-%b";
# generic one that's used by most actions
action = "{action_core $0-} ";
# own action, both private/public
ownaction = "{action $0-}";
# own action with target, both private/public
ownaction_target = "{action_core $0}{msgchannel $1} ";
# private action sent by others
pvtaction = " %g(*) $0- ";
pvtaction_query = "{action $0-}";
# public action sent by others
pubaction = "{action $0-}";
##
## other IRC events
##
# notices
ownnotice = "-> %gnotice%n[%G$1%n] ";
notice = "<- %Gnotice%n[%g$0%n] ";
pubnotice_channel = "{msgchannel $0}";
pvtnotice_host = "";
servernotice = "{notice $0-}";
# CTCPs
ownctcp = "-> %b$0%n[%B$1-%n] ";
ctcp = "%B$0-";
# wallops
wallop = "%y$0-: %n";
wallop_nick = "%y$0-%n";
wallop_action = "%y * $0-%n ";
# netsplits
netsplit = "%b$0-%n";
netjoin = "%b$0-%n";
# /names list
names_nick = "%b[%_$0%_$1-]%n ";
names_users = "[$0-]";
names_channel = "{channel $0-}";
# DCC
dcc = "$0-";
dccfile = "%_$0-%_";
# DCC chat, own msg/action
dccownmsg = "*%b=$1-%n*> %g";
dccownaction = "{action $0-}";
dccownaction_target = "{ownaction_target $0-}";
# DCC chat, others
dccmsg = "*%b=$1-%n* ";
dccquerynick = "$0-";
dccaction = " (*dcc*) $0- %|";
##
## statusbar
##
# default background for all statusbars. You can also give
# the default foreground color for statusbar items.
sb_background = "%4%k";
# default backround for "default" statusbar group
#sb_default_bg = "%4";
# background for prompt / input line
sb_prompt_bg = "%n";
# background for info statusbar
sb_info_bg = "%4";
# background for topicbar (same default)
sb_topic_bg = "%4%k";
#sb_topic_fg = "%k";
# text at the beginning of statusbars. sb-item already puts
# space there,so we don't use anything by default.
sbstart = "";
# text at the end of statusbars. Use space so that it's never
# used for anything.
sbend = " ";
prompt = "[$*] ";
sb = " %W[%n$*%W]%n";
sbmode = "(%W+%n$*)";
sbaway = " (%GzZzZ%n)";
sbservertag = ":$0 (change with ^X)";
# activity in statusbar
# ',' separator
sb_act_sep = "%k$*";
# normal text
sb_act_text = "%k$*";
# public message
sb_act_msg = "%W$*";
# hilight
sb_act_hilight = "%M$*";
# hilight with specified color, $0 = color, $1 = text
sb_act_hilight_color = "$0$1-%n";
};
formats = {
"fe-common/core" = {
join = "%bJoins%n[{channel $2}] %b->%n{channick_hilight $0} {chanhost_hilight $1}";
part = "%bParts%n[{channel $2}] %B->%n{channick $0} {chanhost $1} {reason $3}";
kick = "{channick $0} was kicked from {channel $1} by {nick $2} {reason $3}";
quit = "%bQuits%n %B->%n{channick $0} {chanhost $1} {reason $2}";
};
"fe-common/irc" = {
chanmode_change = "mode[{channel $0}] {mode $1} by {nick $2}";
whois = "{nick $0} {nickhost $1@$2}%: ircname : $3";
server_chanmode_change = "{netsplit ServerMode}/{channelhilight $0}: {mode $1} by {nick $2}";
};
};

View File

@@ -1,137 +0,0 @@
servers = (
{
address = "irc.tilde.chat";
chatnet = "tildechat";
port = "6697";
use_tls = "yes";
tls_verify = "no";
autoconnect = "yes";
tls_cert = "~/.irssi/certs/tilde.pem";
},
{
address = "irc.libera.chat";
chatnet = "libera.chat";
port = "6697";
use_tls = "yes";
tls_cert = "~/.irssi/certs/libera.pem";
tls_verify = "yes";
autoconnect = "yes";
}
);
chatnets = {
tildechat = { type = "IRC"; sasl_mechanism = "EXTERNAL"; };
"libera.chat" = { type = "IRC"; sasl_mechanism = "EXTERNAL"; };
};
channels = (
{ name = "#dimension"; chatnet = "tilechat"; autojoin = "yes"; },
{ name = "#dimension"; chatnet = "tildechat"; autojoin = "yes"; },
{ name = "#meta"; chatnet = "tildechat"; autojoin = "yes"; },
{
name = "#idlerpg";
chatnet = "tildechat";
autojoin = "yes";
password = "-botmd";
botmasks = "ubergeek@thunix.net";
autosendcmd = "^MSG idlerpg_bot login Matalok br6feoot";
},
{ name = "#livlug"; chatnet = "Freenode"; autojoin = "yes"; },
{ name = "#gemini"; chatnet = "tildechat"; autojoin = "yes"; },
{ name = "#wiki"; chatnet = "tildechat"; autojoin = "yes"; },
{ name = "#tw2002"; chatnet = "tildechat"; autojoin = "yes"; },
{ name = "#tildeverse"; chatnet = "tildechat"; autojoin = "yes"; }
);
settings = {
core = {
real_name = "Unknown";
user_name = "nikdoof";
nick = "nikdoof";
};
"fe-text" = { actlist_sort = "refnum"; colors_ansi_24bit = "yes"; };
"fe-common/core" = {
activity_hide_level = "QUITS JOINS PARTS KICKS MODES TOPIC NICKS";
theme = "IamCyan";
};
};
logs = { };
hilights = ( { text = "matalok"; nick = "yes"; word = "yes"; } );
ignores = ( { level = "JOINS PARTS QUITS"; } );
windows = {
1 = { immortal = "yes"; name = "(status)"; level = "ALL"; };
2 = {
items = (
{
type = "CHANNEL";
chat_type = "IRC";
name = "#dimension";
tag = "tildechat";
}
);
};
3 = {
items = (
{
type = "CHANNEL";
chat_type = "IRC";
name = "#meta";
tag = "tildechat";
}
);
};
4 = {
items = (
{
type = "CHANNEL";
chat_type = "IRC";
name = "#idlerpg";
tag = "tildechat";
}
);
};
5 = { immortal = "yes"; name = "hilight"; sticky = "yes"; };
6 = {
items = (
{
type = "CHANNEL";
chat_type = "IRC";
name = "#gemini";
tag = "tildechat";
}
);
};
7 = {
items = (
{
type = "CHANNEL";
chat_type = "IRC";
name = "#wiki";
tag = "tildechat";
}
);
};
8 = {
items = (
{
type = "CHANNEL";
chat_type = "IRC";
name = "#tildeverse";
tag = "tildechat";
}
);
};
9 = {
items = (
{
type = "CHANNEL";
chat_type = "IRC";
name = "#tw2002";
tag = "tildechat";
}
);
};
};
mainwindows = {
1 = { first_line = "7"; lines = "41"; };
5 = { first_line = "1"; lines = "6"; };
};

View File

@@ -1,294 +0,0 @@
# When testing changes, the easiest way to reload the theme is with /RELOAD.
# This reloads the configuration file too, so if you did any changes remember
# to /SAVE it first. Remember also that /SAVE overwrites the theme file with
# old data so keep backups :)
# TEMPLATES:
# The real text formats that irssi uses are the ones you can find with
# /FORMAT command. Back in the old days all the colors and texts were mixed
# up in those formats, and it was really hard to change the colors since you
# might have had to change them in tens of different places. So, then came
# this templating system.
# Now the /FORMATs don't have any colors in them, and they also have very
# little other styling. Most of the stuff you need to change is in this
# theme file. If you can't change something here, you can always go back
# to change the /FORMATs directly, they're also saved in these .theme files.
# So .. the templates. They're those {blahblah} parts you see all over the
# /FORMATs and here. Their usage is simply {name parameter1 parameter2}.
# When irssi sees this kind of text, it goes to find "name" from abstracts
# block below and sets "parameter1" into $0 and "parameter2" into $1 (you
# can have more parameters of course). Templates can have subtemplates.
# Here's a small example:
# /FORMAT format hello {colorify {underline world}}
# abstracts = { colorify = "%G$0-%n"; underline = "%U$0-%U"; }
# When irssi expands the templates in "format", the final string would be:
# hello %G%Uworld%U%n
# ie. underlined bright green "world" text.
# and why "$0-", why not "$0"? $0 would only mean the first parameter,
# $0- means all the parameters. With {underline hello world} you'd really
# want to underline both of the words, not just the hello (and world would
# actually be removed entirely).
# COLORS:
# You can find definitions for the color format codes in docs/formats.txt.
# There's one difference here though. %n format. Normally it means the
# default color of the terminal (white mostly), but here it means the
# "reset color back to the one it was in higher template". For example
# if there was /FORMAT test %g{foo}bar, and foo = "%Y$0%n", irssi would
# print yellow "foo" (as set with %Y) but "bar" would be green, which was
# set at the beginning before the {foo} template. If there wasn't the %g
# at start, the normal behaviour of %n would occur. If you _really_ want
# to use the terminal's default color, use %N.
#############################################################################
# default foreground color (%N) - -1 is the "default terminal color"
default_color = "-1";
# print timestamp/servertag at the end of line, not at beginning
info_eol = "false";
# these characters are automatically replaced with specified color
# (dark grey by default)
replaces = { "[]=" = "%K$*%n"; };
abstracts = {
##
## generic
##
# text to insert at the beginning of each non-message line
line_start = "%B-%n!%B-%n ";
# timestamp styling, nothing by default
timestamp = "$*";
# any kind of text that needs hilighting, default is to bold
hilight = "%_$*%_";
# any kind of error message, default is bright red
error = "%R$*%n";
# channel name is printed
channel = "%_$*%_";
# nick is printed
nick = "%_$*%_";
# nick host is printed
nickhost = "[$*]";
# server name is printed
server = "%_$*%_";
# some kind of comment is printed
comment = "[$*]";
# reason for something is printed (part, quit, kick, ..)
reason = "{comment $*}";
# mode change is printed ([+o nick])
mode = "{comment $*}";
##
## channel specific messages
##
# highlighted nick/host is printed (joins)
channick_hilight = "%C$*%n";
chanhost_hilight = "{nickhost %c$*%n}";
# nick/host is printed (parts, quits, etc.)
channick = "%c$*%n";
chanhost = "{nickhost $*}";
# highlighted channel name is printed
channelhilight = "%c$*%n";
# ban/ban exception/invite list mask is printed
ban = "%c$*%n";
##
## messages
##
# the basic styling of how to print message, $0 = nick mode, $1 = nick
msgnick = "%K<%n$0$1-%K>%n %|";
# message from you is printed. "ownnick" specifies the styling of the
# nick ($0 part in msgnick) and "ownmsgnick" specifies the styling of the
# whole line.
# Example1: You want the message text to be green:
# ownmsgnick = "{msgnick $0 $1-}%g";
# Example2.1: You want < and > chars to be yellow:
# ownmsgnick = "%Y{msgnick $0 $1-%Y}%n";
# (you'll also have to remove <> from replaces list above)
# Example2.2: But you still want to keep <> grey for other messages:
# pubmsgnick = "%K{msgnick $0 $1-%K}%n";
# pubmsgmenick = "%K{msgnick $0 $1-%K}%n";
# pubmsghinick = "%K{msgnick $1 $0$2-%n%K}%n";
# ownprivmsgnick = "%K{msgnick $*%K}%n";
# privmsgnick = "%K{msgnick %R$*%K}%n";
# $0 = nick mode, $1 = nick
ownmsgnick = "{msgnick $0 $1-}";
ownnick = "%_$*%n";
# public message in channel, $0 = nick mode, $1 = nick
pubmsgnick = "{msgnick $0 $1-}";
pubnick = "%N$*%n";
# public message in channel meant for me, $0 = nick mode, $1 = nick
pubmsgmenick = "{msgnick $0 $1-}";
menick = "%Y$*%n";
# public highlighted message in channel
# $0 = highlight color, $1 = nick mode, $2 = nick
pubmsghinick = "{msgnick $1 $0$2-%n}";
# channel name is printed with message
msgchannel = "%K:%c$*%n";
# private message, $0 = nick, $1 = host
privmsg = "[%R$0%K(%r$1-%K)%n] ";
# private message from you, $0 = "msg", $1 = target nick
ownprivmsg = "[%r$0%K(%R$1-%K)%n] ";
# own private message in query
ownprivmsgnick = "{msgnick $*}";
ownprivnick = "%_$*%n";
# private message in query
privmsgnick = "{msgnick %R$*%n}";
##
## Actions (/ME stuff)
##
# used internally by this theme
action_core = "%_ * $*%n";
# generic one that's used by most actions
action = "{action_core $*} ";
# own action, both private/public
ownaction = "{action $*}";
# own action with target, both private/public
ownaction_target = "{action_core $0}%K:%c$1%n ";
# private action sent by others
pvtaction = "%_ (*) $*%n ";
pvtaction_query = "{action $*}";
# public action sent by others
pubaction = "{action $*}";
##
## other IRC events
##
# whois
whois = "%# $[8]0 : $1-";
# notices
ownnotice = "[%r$0%K(%R$1-%K)]%n ";
notice = "%K-%M$*%K-%n ";
pubnotice_channel = "%K:%m$*";
pvtnotice_host = "%K(%m$*%K)";
servernotice = "%g!$*%n ";
# CTCPs
ownctcp = "[%r$0%K(%R$1-%K)] ";
ctcp = "%g$*%n";
# wallops
wallop = "%_$*%n: ";
wallop_nick = "%n$*";
wallop_action = "%_ * $*%n ";
# netsplits
netsplit = "%R$*%n";
netjoin = "%C$*%n";
# /names list
names_prefix = "";
names_nick = "[%_$0%_$1-] ";
names_nick_op = "{names_nick $*}";
names_nick_halfop = "{names_nick $*}";
names_nick_voice = "{names_nick $*}";
names_users = "[%g$*%n]";
names_channel = "%G$*%n";
# DCC
dcc = "%g$*%n";
dccfile = "%_$*%_";
# DCC chat, own msg/action
dccownmsg = "[%r$0%K($1-%K)%n] ";
dccownnick = "%R$*%n";
dccownquerynick = "%_$*%n";
dccownaction = "{action $*}";
dccownaction_target = "{action_core $0}%K:%c$1%n ";
# DCC chat, others
dccmsg = "[%G$1-%K(%g$0%K)%n] ";
dccquerynick = "%G$*%n";
dccaction = "%_ (*dcc*) $*%n %|";
##
## statusbar
##
# default background for all statusbars. You can also give
# the default foreground color for statusbar items.
sb_background = "%4%k";
# default backround for "default" statusbar group
#sb_default_bg = "%4";
# background for prompt / input line
sb_prompt_bg = "%n";
# background for info statusbar
sb_info_bg = "%8";
# background for topicbar (same default)
#sb_topic_bg = "%4";
# text at the beginning of statusbars. "sb" already puts a space there,
# so we don't use anything by default.
sbstart = "";
# text at the end of statusbars. Use space so that it's never
# used for anything.
sbend = " ";
topicsbstart = "{sbstart $*}";
topicsbend = "{sbend $*}";
prompt = "[$*] ";
sb = " %K[%n$*%K]%n";
sbmode = "(%K+%n$*)";
sbaway = " (%GzZzZ%n)";
sbservertag = ":$0 (change with ^X)";
sbnickmode = "$0";
# activity in statusbar
# ',' separator
sb_act_sep = "%k$*";
# normal text
sb_act_text = "%K$*";
# public message
sb_act_msg = "%W$*";
# hilight
sb_act_hilight = "%y$*";
# hilight with specified color, $0 = color, $1 = text
sb_act_hilight_color = "$0$1-%n";
};

View File

@@ -1,33 +0,0 @@
# Print hilighted messages & private messages to window named "hilight"
# for irssi 0.7.99 by Timo Sirainen
use Irssi;
use vars qw($VERSION %IRSSI);
$VERSION = "0.01";
%IRSSI = (
authors => "Timo \'cras\' Sirainen",
contact => "tss\@iki.fi",
name => "hilightwin",
description => "Print hilighted messages & private messages to window named \"hilight\"",
license => "Public Domain",
url => "http://irssi.org/",
changed => "2002-03-04T22:47+0100"
);
sub sig_printtext {
my ($dest, $text, $stripped) = @_;
if (($dest->{level} & (MSGLEVEL_HILIGHT|MSGLEVEL_MSGS)) &&
($dest->{level} & MSGLEVEL_NOHILIGHT) == 0) {
$window = Irssi::window_find_name('hilight');
if ($dest->{level} & MSGLEVEL_PUBLIC) {
$text = $dest->{target}.": ".$text;
}
$window->print($text, MSGLEVEL_CLIENTCRAP) if ($window);
}
}
$window = Irssi::window_find_name('hilight');
Irssi::print("Create a window named 'hilight'") if (!$window);
Irssi::signal_add('print text', 'sig_printtext');

View File

@@ -1,203 +0,0 @@
use Irssi;
use strict;
use FileHandle;
use vars qw($VERSION %IRSSI);
$VERSION = "2.1"; # e8934ed1ce04461
%IRSSI = (
authors => 'cdidier',
name => 'tmux_away',
description => 'set (un)away if tmux session is attached/detached',
license => 'GPL v2',
url => 'http://cybione.org',
);
# tmux_away irssi module
#
# Written by Colin Didier <cdidier@cybione.org> and heavily based on
# screen_away irssi module version 0.9.7.1 written by Andreas 'ads' Scherbaum
# <ads@ufp.de>.
#
# Updated by John C. Vernaleo <john@netpurgatory.com> to handle tmux with
# named sessions and other code cleanup and forked as version 2.0.
#
# usage:
#
# put this script into your autorun directory and/or load it with
# /SCRIPT LOAD <name>
#
# there are 5 settings available:
#
# /set tmux_away_active ON/OFF/TOGGLE
# /set tmux_away_repeat <integer>
# /set tmux_away_grace <integer>
# /set tmux_away_message <string>
# /set tmux_away_window <string>
# /set tmux_away_nick <string>
#
# active means that you will be only set away/unaway, if this
# flag is set, default is ON
# repeat is the number of seconds, after the script will check the
# tmux session status again, default is 5 seconds
# grace is the number of seconds, to wait additionally, before
# setting you away, default is disabled (0)
# message is the away message sent to the server, default: not here ...
# window is a window number or name, if set, the script will switch
# to this window, if it sets you away, default is '1'
# nick is the new nick, if the script goes away
# will only be used it not empty
# variables
my $timer_name = undef;
my $away_status = 0;
my %old_nicks = ();
my %away = ();
# Register formats
Irssi::theme_register(
[
'tmux_away_crap',
'{line_start}{hilight ' . $IRSSI{'name'} . ':} $0'
]);
# try to find out if we are running in a tmux session
# (see if $ENV{TMUX} is set)
if (!defined($ENV{TMUX})) {
# just return, we will never be called again
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'tmux_away_crap',
"no tmux session!");
return;
}
my @args_env = split(',', $ENV{TMUX});
my $tmux_socket = $args_env[0];
# register config variables
Irssi::settings_add_bool('misc', $IRSSI{'name'} . '_active', 1);
Irssi::settings_add_int('misc', $IRSSI{'name'} . '_repeat', 5);
Irssi::settings_add_int('misc', $IRSSI{'name'} . '_grace', 0);
Irssi::settings_add_str('misc', $IRSSI{'name'} . '_message', "not here...");
Irssi::settings_add_str('misc', $IRSSI{'name'} . '_window', "1");
Irssi::settings_add_str('misc', $IRSSI{'name'} . '_nick', "");
# check, set or reset the away status
sub tmux_away {
my ($immediate) = @_;
my ($status, @res);
# only run, if activated
if (Irssi::settings_get_bool($IRSSI{'name'} . '_active') != 1) {
$away_status = 0;
} else {
if ($away_status == 0) {
# display init message at first time
my $grace = Irssi::settings_get_int($IRSSI{'name'} . '_grace');
$grace = ", $grace seconds grace" if $grace;
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'tmux_away_crap',
"activating $IRSSI{'name'} (interval: " . Irssi::settings_get_int($IRSSI{'name'} . '_repeat') . " seconds$grace)");
$away_status = 2;
}
# get actual tmux session status
chomp(@res = `tmux -S '$tmux_socket' lsc 2>&1`);
chomp(my $tmux_session = `tmux -S '$tmux_socket' display -p '#S' 2>/dev/null`);
if ($res[0] =~ /^server not found/ || $? >> 8) {
die "error getting tmux session status.";
}
$status = 1; # away, assumes the session is detached
foreach (@res) {
my @args_st = split(' ');
if ($args_st[1] eq $tmux_session) {
$status = 2; # unaway
}
}
# unaway -> away
if ($status == 1 and $away_status != 1) {
if (my $grace = Irssi::settings_get_int($IRSSI{'name'} . '_grace')) {
if (!$immediate) {
Irssi::timeout_add_once($grace * 1000, 'tmux_away', '1');
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'tmux_away_crap',
"(in grace for away: $grace seconds)");
return 1;
}
}
if (length(Irssi::settings_get_str($IRSSI{'name'} . '_window')) > 0) {
# if length of window is greater then 0, make this window active
Irssi::command('window goto ' . Irssi::settings_get_str($IRSSI{'name'} . '_window'));
}
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'tmux_away_crap', "Set away");
my $message = Irssi::settings_get_str($IRSSI{'name'} . '_message');
if (length($message) == 0) {
# we have to set a message or we wouldnt go away
$message = "not here ...";
}
foreach (Irssi::servers()) {
if (!$_->{usermode_away}) {
# user isn't yet away
$away{$_->{'tag'}} = 0;
$_->command("^AWAY " . ($_->{chat_type} ne 'SILC' ? "-one " : "") . "$message");
if ($_->{chat_type} ne 'XMPP' and length(Irssi::settings_get_str($IRSSI{'name'} . '_nick')) > 0) {
# only change if actual nick isn't already the away nick
if (Irssi::settings_get_str($IRSSI{'name'} . '_nick') ne $_->{nick}) {
# keep old nick
$old_nicks{$_->{'tag'}} = $_->{nick};
# set new nick
$_->command("NICK " . Irssi::settings_get_str($IRSSI{'name'} . '_nick'));
}
}
} else {
# user is already away, remember this
$away{$_->{'tag'}} = 1;
}
}
$away_status = $status;
# away -> unaway
} elsif ($status == 2 and $away_status != 2) {
if (my $grace = Irssi::settings_get_int($IRSSI{'name'} . '_grace')) {
if (!$immediate) {
Irssi::timeout_add_once($grace * 1000, 'tmux_away', '1');
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'tmux_away_crap',
"(in grace for unaway: $grace seconds)");
return 1;
}
}
# unset away
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'tmux_away_crap', "Reset away");
foreach (Irssi::servers()) {
if ($away{$_->{'tag'}} == 1) {
# user was already away, don't reset away
$away{$_->{'tag'}} = 0;
next;
}
$_->command("^AWAY" . (($_->{chat_type} ne 'SILC') ? " -one" : "")) if ($_->{usermode_away});
if ($_->{chat_type} ne 'XMPP' and defined($old_nicks{$_->{'tag'}}) and length($old_nicks{$_->{'tag'}}) > 0) {
# set old nick
$_->command("NICK " . $old_nicks{$_->{'tag'}});
$old_nicks{$_->{'tag'}} = "";
}
}
$away_status = $status;
} elsif ($immediate) {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'tmux_away_crap',
"in grace aborted");
}
}
# but everytimes install a new timer
register_tmux_away_timer();
return 0;
}
# remove old timer and install a new one
sub register_tmux_away_timer {
# add new timer with new timeout (maybe the timeout has been changed)
Irssi::timeout_add_once(Irssi::settings_get_int($IRSSI{'name'} . '_repeat') * 1000, 'tmux_away', '');
}
# init process
tmux_away();

View File

@@ -1,606 +0,0 @@
## trackbar.pl
#
# This little script will do just one thing: it will draw a line each time you
# switch away from a window. This way, you always know just upto where you've
# been reading that window :) It also removes the previous drawn line, so you
# don't see double lines.
#
# redraw trackbar only works on irssi 0.8.17 or higher.
#
##
## Usage:
#
# The script works right out of the box, but if you want you can change
# the working by /set'ing the following variables:
#
# Setting: trackbar_style
# Description: This setting will be the color of your trackbar line.
# By default the value will be '%K', only Irssi color
# formats are allowed. If you don't know the color formats
# by heart, you can take a look at the formats documentation.
# You will find the proper docs on http://www.irssi.org/docs.
#
# Setting: trackbar_string
# Description: This is the string that your line will display. This can
# be multiple characters or just one. For example: '~-~-'
# The default setting is '-'.
# Here are some unicode characters you can try:
# "───" => U+2500 => a line
# "═══" => U+2550 => a double line
# "━━━" => U+2501 => a wide line
# "▭ " => U+25ad => a white rectangle
#
# Setting: trackbar_use_status_window
# Description: If this setting is set to OFF, Irssi won't print a trackbar
# in the statuswindow
#
# Setting: trackbar_ignore_windows
# Description: A list of windows where no trackbar should be printed
#
# Setting: trackbar_print_timestamp
# Description: If this setting is set to ON, Irssi will print the formatted
# timestamp in front of the trackbar.
#
# Setting: trackbar_require_seen
# Description: Only clear the trackbar if it has been scrolled to.
#
# Setting: trackbar_all_manual
# Description: Never clear the trackbar until you do /mark.
#
# /mark is a command that will redraw the line at the bottom.
#
# Command: /trackbar, /trackbar goto
# Description: Jump to where the trackbar is, to pick up reading
#
# Command: /trackbar keep
# Description: Keep this window's trackbar where it is the next time
# you switch windows (then this flag is cleared again)
#
# Command: /mark, /trackbar mark
# Description: Remove the old trackbar and mark the bottom of this
# window with a new trackbar
#
# Command: /trackbar markvisible
# Description: Like mark for all visible windows
#
# Command: /trackbar markall
# Description: Like mark for all windows
#
# Command: /trackbar remove
# Description: Remove this window's trackbar
#
# Command: /trackbar removeall
# Description: Remove all windows' trackbars
#
# Command: /trackbar redraw
# Description: Force redraw of trackbars
#
##
##
#
# For bugreports and other improvements contact one of the authors.
#
# 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 script; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
##
use strict;
use warnings;
use vars qw($VERSION %IRSSI);
$VERSION = "2.9"; # a4c78e85092a271
%IRSSI = (
authors => "Peter 'kinlo' Leurs, Uwe Dudenhoeffer, " .
"Michiel Holtkamp, Nico R. Wohlgemuth, " .
"Geert Hauwaerts",
contact => 'peter@pfoe.be',
patchers => 'Johan Kiviniemi (UTF-8), Uwe Dudenhoeffer (on-upgrade-remove-line)',
name => 'trackbar',
description => 'Shows a bar where you have last read a window.',
license => 'GNU General Public License',
url => 'http://www.pfoe.be/~peter/trackbar/',
commands => 'trackbar',
);
## Comments and remarks.
#
# This script uses settings.
# Use /SET to change the value or /TOGGLE to switch it on or off.
#
#
# Tip: The command 'trackbar' is very useful if you bind that to a key,
# so you can easily jump to the trackbar. Please see 'help bind' for
# more information about keybindings in Irssi.
#
# Command: /BIND meta2-P key F1
# /BIND F1 command trackbar
#
##
## Bugfixes and new items in this rewrite.
#
# * Remove all the trackbars before upgrading.
# * New setting trackbar_use_status_window to control the statuswindow trackbar.
# * New setting trackbar_print_timestamp to print a timestamp or not.
# * New command 'trackbar' to scroll up to the trackbar.
# * When resizing your terminal, Irssi will update all the trackbars to the new size.
# * When changing trackbar settings, change all the trackbars to the new settings.
# * New command 'trackbar mark' to draw a new trackbar (The old '/mark').
# * New command 'trackbar markall' to draw a new trackbar in each window.
# * New command 'trackbar remove' to remove the trackbar from the current window.
# * New command 'trackbar removeall' to remove all the trackbars.
# * Don't draw a trackbar in empty windows.
# * Added a version check to prevent Irssi redraw errors.
# * Fixed a bookmark NULL versus 0 bug.
# * Fixed a remove-line bug in Uwe Dudenhoeffer his patch.
# * New command 'help trackbar' to display the trackbar commands.
# * Fixed an Irssi startup bug, now processing each auto-created window.
#
##
## Known bugs and the todolist.
#
# Todo: * Instead of drawing a line, invert the line.
#
##
## Authors:
#
# - Main maintainer & author: Peter 'kinlo' Leurs
# - Many thanks to Timo 'cras' Sirainen for placing me on my way
# - on-upgrade-remove-line patch by Uwe Dudenhoeffer
# - trackbar resizing by Michiel Holtkamp (02 Jul 2012)
# - scroll to trackbar, window excludes, and timestamp options by Nico R.
# Wohlgemuth (22 Sep 2012)
#
##
## Version history:
#
# 2.9: - fix crash on /mark in empty window
# 2.8: - fix /^join bug
# 2.7: - add /set trackbar_all_manual option
# 2.5: - merge back on scripts.irssi.org
# - fix /trackbar redraw broken in 2.4
# - fix legacy encodings
# - add workaround for irssi issue #271
# 2.4: - add support for horizontal splits
# 2.3: - add some features for seen tracking using other scripts
# 2.0: - big rewrite based on 1.4
# * removed /tb, you can have it with /alias tb trackbar if you want
# * subcommand and settings changes:
# /trackbar vmark => /trackbar markvisible
# /trackbar scroll => /trackbar goto (or just /trackbar)
# /trackbar help => /help trackbar
# /set trackbar_hide_windows => /set trackbar_ignore_windows
# /set trackbar_timestamp => /set trackbar_print_timestamp
# * magic line strings were removed, just paste the unicode you want!
# * trackbar_timestamp_styled is not currently supported
# 1.9: - add version guard
# 1.8: - sub draw_bar
# 1.7: - Added /tb scroll, trackbar_hide_windows, trackbar_timestamp_timestamp
# and trackbar_timestamp_styled
# 1.6: - Work around Irssi resize bug, please do /upgrade! (see below)
# 1.5: - Resize trackbars in all windows when terminal is resized
# 1.4: - Changed our's by my's so the irssi script header is valid
# - Removed utf-8 support. In theory, the script should work w/o any
# problems for utf-8, just set trackbar_string to a valid utf-8 character
# and everything *should* work. However, this script is being plagued by
# irssi internal bugs. The function Irssi::settings_get_str does NOT handle
# unicode strings properly, hence you will notice problems when setting the bar
# to a unicode char. For changing your bar to utf-8 symbols, read the line sub.
# 1.3: - Upgrade now removes the trackbars.
# - Some code cleanups, other defaults
# - /mark sets the line to the bottom
# 1.2: - Support for utf-8
# - How the bar looks can now be configured with trackbar_string
# and trackbar_style
# 1.1: - Fixed bug when closing window
# 1.0: - Initial release
#
##
use Irssi;
use Irssi::TextUI;
use Encode;
use POSIX qw(strftime);
sub cmd_help {
my ($args) = @_;
if ($args =~ /^trackbar *$/i) {
print CLIENTCRAP <<HELP
%9Syntax:%9
TRACKBAR
TRACKBAR GOTO
TRACKBAR KEEP
TRACKBAR MARK
TRACKBAR MARKVISIBLE
TRACKBAR MARKALL
TRACKBAR REMOVE
TRACKBAR REMOVEALL
TRACKBAR REDRAW
%9Parameters:%9
GOTO: Jump to where the trackbar is, to pick up reading
KEEP: Keep this window's trackbar where it is the next time
you switch windows (then this flag is cleared again)
MARK: Remove the old trackbar and mark the bottom of this
window with a new trackbar
MARKVISIBLE: Like mark for all visible windows
MARKALL: Like mark for all windows
REMOVE: Remove this window's trackbar
REMOVEALL: Remove all windows' trackbars
REDRAW: Force redraw of trackbars
%9Description:%9
Manage a trackbar. Without arguments, it will scroll up to the trackbar.
%9Examples:%9
/TRACKBAR MARK
/TRACKBAR REMOVE
HELP
}
}
Irssi::theme_register([
'trackbar_loaded', '%R>>%n %_Scriptinfo:%_ Loaded $0 version $1 by $2.',
'trackbar_wrong_version', '%R>>%n %_Trackbar:%_ Please upgrade your client to 0.8.17 or above if you would like to use this feature of trackbar.',
'trackbar_all_removed', '%R>>%n %_Trackbar:%_ All the trackbars have been removed.',
'trackbar_not_found', '%R>>%n %_Trackbar:%_ No trackbar found in this window.',
]);
my $old_irssi = Irssi::version < 20140701;
sub check_version {
if ($old_irssi) {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_wrong_version');
return;
} else {
return 1;
}
}
sub is_utf8 {
lc Irssi::settings_get_str('term_charset') eq 'utf-8'
}
my (%config, %keep_trackbar, %unseen_trackbar);
sub remove_one_trackbar {
my $win = shift;
my $view = shift || $win->view;
my $line = $view->get_bookmark('trackbar');
if (defined $line) {
my $bottom = $view->{bottom};
$view->remove_line($line);
$win->command('^scrollback end') if $bottom && !$win->view->{bottom};
$view->redraw;
}
}
sub add_one_trackbar_pt1 {
my $win = shift;
my $view = shift || $win->view;
my $last_cur_line = ($view->{buffer}{cur_line}||+{})->{_irssi};
$win->print(line($win->{width}), MSGLEVEL_NEVER);
my $cur_line = ($win->view->{buffer}{cur_line}||+{})->{_irssi}; # get a fresh buffer
($last_cur_line//'') ne ($cur_line//'') # printing was successful
}
sub add_one_trackbar_pt2 {
my $win = shift;
my $view = $win->view;
$view->set_bookmark_bottom('trackbar');
$unseen_trackbar{ $win->{_irssi} } = 1;
Irssi::signal_emit("window trackbar added", $win);
$view->redraw;
}
sub update_one_trackbar {
my $win = shift;
my $view = shift || $win->view;
my $force = shift;
my $ignored = win_ignored($win, $view);
my $success;
$success = add_one_trackbar_pt1($win, $view) ? 1 : 0
if $force || !$ignored;
remove_one_trackbar($win, $view)
if ( $success || !defined $success ) && ( $force || !defined $force || !$ignored );
add_one_trackbar_pt2($win)
if $success;
}
sub win_ignored {
my $win = shift;
my $view = shift || $win->view;
return 1 unless $view->{buffer}{lines_count};
return 1 if $win->{name} eq '(status)' && !$config{use_status_window};
no warnings 'uninitialized';
return 1 if grep { $win->{name} eq $_ || $win->{refnum} eq $_
|| $win->get_active_name eq $_ } @{ $config{ignore_windows} };
return 0;
}
sub sig_window_changed {
my ($newwindow, $oldwindow) = @_;
return unless $oldwindow;
redraw_one_trackbar($newwindow) unless $old_irssi;
trackbar_update_seen($newwindow);
return if delete $keep_trackbar{ $oldwindow->{_irssi} };
trackbar_update_seen($oldwindow);
return if $config{require_seen} && $unseen_trackbar{ $oldwindow->{_irssi } };
return if $config{all_manual};
update_one_trackbar($oldwindow, undef, 0);
}
sub trackbar_update_seen {
my $win = shift;
return unless $win;
return unless $unseen_trackbar{ $win->{_irssi} };
my $view = $win->view;
my $line = $view->get_bookmark('trackbar');
unless ($line) {
delete $unseen_trackbar{ $win->{_irssi} };
Irssi::signal_emit("window trackbar seen", $win);
return;
}
my $startline = $view->{startline};
return unless $startline;
if ($startline->{info}{time} < $line->{info}{time}
|| $startline->{_irssi} == $line->{_irssi}) {
delete $unseen_trackbar{ $win->{_irssi} };
Irssi::signal_emit("window trackbar seen", $win);
}
}
sub screen_length;
{ local $@;
eval { require Text::CharWidth; };
unless ($@) {
*screen_length = sub { Text::CharWidth::mbswidth($_[0]) };
}
else {
*screen_length = sub {
my $temp = shift;
Encode::_utf8_on($temp) if is_utf8();
length($temp)
};
}
}
{ my %strip_table = (
(map { $_ => '' } (split //, '04261537' . 'kbgcrmyw' . 'KBGCRMYW' . 'U9_8I:|FnN>#[' . 'pP')),
(map { $_ => $_ } (split //, '{}%')),
);
sub c_length {
my $o = Irssi::strip_codes($_[0]);
$o =~ s/(%(%|Z.{6}|z.{6}|X..|x..|.))/exists $strip_table{$2} ? $strip_table{$2} :
$2 =~ m{x(?:0[a-f]|[1-6][0-9a-z]|7[a-x])|z[0-9a-f]{6}}i ? '' : $1/gex;
screen_length($o)
}
}
sub line {
my ($width, $time) = @_;
my $string = $config{string};
$string = ' ' unless length $string;
$time ||= time;
Encode::_utf8_on($string) if is_utf8();
my $length = c_length($string);
my $format = '';
if ($config{print_timestamp}) {
$format = $config{timestamp_str};
$format =~ y/%/\01/;
$format =~ s/\01\01/%/g;
$format = strftime($format, localtime $time);
$format =~ y/\01/%/;
}
my $times = $width / $length;
$times += 1 if $times != int $times;
my $style = "$config{style}";
Encode::_utf8_on($style) if is_utf8();
$format .= $style;
$width -= c_length($format);
$string x= $times;
chop $string while length $string && c_length($string) > $width;
return $format . $string;
}
sub remove_all_trackbars {
for my $window (Irssi::windows) {
next unless ref $window;
remove_one_trackbar($window);
}
}
sub UNLOAD {
remove_all_trackbars();
}
sub redraw_one_trackbar {
my $win = shift;
my $view = $win->view;
my $line = $view->get_bookmark('trackbar');
return unless $line;
my $bottom = $view->{bottom};
$win->print_after($line, MSGLEVEL_NEVER, line($win->{width}, $line->{info}{time}),
$line->{info}{time});
$view->set_bookmark('trackbar', $win->last_line_insert);
$view->remove_line($line);
$win->command('^scrollback end') if $bottom && !$win->view->{bottom};
$view->redraw;
}
sub redraw_trackbars {
return unless check_version();
for my $win (Irssi::windows) {
next unless ref $win;
redraw_one_trackbar($win);
}
}
sub goto_trackbar {
my $win = Irssi::active_win;
my $line = $win->view->get_bookmark('trackbar');
if ($line) {
$win->command("scrollback goto ". strftime("%d %H:%M:%S", localtime($line->{info}{time})));
} else {
$win->printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_not_found');
}
}
sub cmd_mark {
update_one_trackbar(Irssi::active_win, undef, 1);
}
sub cmd_markall {
for my $window (Irssi::windows) {
next unless ref $window;
update_one_trackbar($window);
}
}
sub signal_stop {
Irssi::signal_stop;
}
sub cmd_markvisible {
my @wins = Irssi::windows;
my $awin =
my $bwin = Irssi::active_win;
my $awin_counter = 0;
Irssi::signal_add_priority('window changed' => 'signal_stop', -99);
do {
Irssi::active_win->command('window up');
$awin = Irssi::active_win;
update_one_trackbar($awin);
++$awin_counter;
} until ($awin->{refnum} == $bwin->{refnum} || $awin_counter >= @wins);
Irssi::signal_remove('window changed' => 'signal_stop');
}
sub cmd_trackbar_remove_one {
remove_one_trackbar(Irssi::active_win);
}
sub cmd_remove_all_trackbars {
remove_all_trackbars();
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_all_removed');
}
sub cmd_keep_once {
$keep_trackbar{ Irssi::active_win->{_irssi} } = 1;
}
sub trackbar_runsub {
my ($data, $server, $item) = @_;
$data =~ s/\s+$//g;
if ($data) {
Irssi::command_runsub('trackbar', $data, $server, $item);
} else {
goto_trackbar();
}
}
sub update_config {
my $was_status_window = $config{use_status_window};
$config{style} = Irssi::settings_get_str('trackbar_style');
$config{string} = Irssi::settings_get_str('trackbar_string');
$config{require_seen} = Irssi::settings_get_bool('trackbar_require_seen');
$config{all_manual} = Irssi::settings_get_bool('trackbar_all_manual');
$config{ignore_windows} = [ split /[,\s]+/, Irssi::settings_get_str('trackbar_ignore_windows') ];
$config{use_status_window} = Irssi::settings_get_bool('trackbar_use_status_window');
$config{print_timestamp} = Irssi::settings_get_bool('trackbar_print_timestamp');
if (defined $was_status_window && $was_status_window != $config{use_status_window}) {
if (my $swin = Irssi::window_find_name('(status)')) {
if ($config{use_status_window}) {
update_one_trackbar($swin);
}
else {
remove_one_trackbar($swin);
}
}
}
if ($config{print_timestamp}) {
my $ts_format = Irssi::settings_get_str('timestamp_format');
my $ts_theme = Irssi::current_theme->get_format('fe-common/core', 'timestamp');
my $render_str = Irssi::current_theme->format_expand($ts_theme);
(my $ts_escaped = $ts_format) =~ s/([%\$])/$1$1/g;
$render_str =~ s/(?|\$(.)(?!\w)|\$\{(\w+)\})/$1 eq 'Z' ? $ts_escaped : $1/ge;
$config{timestamp_str} = $render_str;
}
redraw_trackbars() unless $old_irssi;
}
Irssi::settings_add_str('trackbar', 'trackbar_string', is_utf8() ? "\x{2500}" : '-');
Irssi::settings_add_str('trackbar', 'trackbar_style', '%K');
Irssi::settings_add_str('trackbar', 'trackbar_ignore_windows', '');
Irssi::settings_add_bool('trackbar', 'trackbar_use_status_window', 1);
Irssi::settings_add_bool('trackbar', 'trackbar_print_timestamp', 0);
Irssi::settings_add_bool('trackbar', 'trackbar_require_seen', 0);
Irssi::settings_add_bool('trackbar', 'trackbar_all_manual', 0);
update_config();
Irssi::signal_add_last( 'mainwindow resized' => 'redraw_trackbars')
unless $old_irssi;
Irssi::signal_register({'window trackbar added' => [qw/Irssi::UI::Window/]});
Irssi::signal_register({'window trackbar seen' => [qw/Irssi::UI::Window/]});
Irssi::signal_register({'gui page scrolled' => [qw/Irssi::UI::Window/]});
Irssi::signal_add_last('gui page scrolled' => 'trackbar_update_seen');
Irssi::signal_add('setup changed' => 'update_config');
Irssi::signal_add_priority('session save' => 'remove_all_trackbars', Irssi::SIGNAL_PRIORITY_HIGH-1);
Irssi::signal_add('window changed' => 'sig_window_changed');
Irssi::command_bind('trackbar goto' => 'goto_trackbar');
Irssi::command_bind('trackbar keep' => 'cmd_keep_once');
Irssi::command_bind('trackbar mark' => 'cmd_mark');
Irssi::command_bind('trackbar markvisible' => 'cmd_markvisible');
Irssi::command_bind('trackbar markall' => 'cmd_markall');
Irssi::command_bind('trackbar remove' => 'cmd_trackbar_remove_one');
Irssi::command_bind('trackbar removeall' => 'cmd_remove_all_trackbars');
Irssi::command_bind('trackbar redraw' => 'redraw_trackbars');
Irssi::command_bind('trackbar' => 'trackbar_runsub');
Irssi::command_bind('mark' => 'cmd_mark');
Irssi::command_bind_last('help' => 'cmd_help');
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_loaded', $IRSSI{name}, $VERSION, $IRSSI{authors});
# workaround for issue #271
{ package Irssi::Nick }

View File

@@ -20,9 +20,12 @@ brew "poetry"
brew "sass/sass/sass" brew "sass/sass/sass"
brew "smartmontools" brew "smartmontools"
brew "hashicorp/tap/terraform" brew "hashicorp/tap/terraform"
brew "terraform-local"
brew "tz" brew "tz"
brew "uv" brew "uv"
brew "yazi" brew "yazi"
brew "jq"
brew "fzf"
cask "appcleaner" cask "appcleaner"
cask "balenaetcher" cask "balenaetcher"

View File

@@ -1,17 +0,0 @@
#!/bin/bash
# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Flush DNS
# @raycast.mode fullOutput
# @raycast.packageName Browsing
# Optional parameters:
# @raycast.icon 💾
# Documentation:
# @raycast.author Andrew Williams
# @raycast.authorURL https://github.com/nikdoof
# @raycast.description Flushes DNS cache on macOS
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

View File

@@ -1,19 +0,0 @@
#!/usr/bin/osascript
# Required parameters:
# @raycast.author Jax0rz
# @authorURL https://github.com/Jax0rz
# @raycast.schemaVersion 1
# @raycast.title Move Downloads to Trash
# @raycast.mode silent
# @raycast.packageName System
# @raycast.needsConfirmation true
# Optional parameters:
# @raycast.icon images/move-downloads-to-trash.png
tell application "Finder"
set allDownloads to every item of folder (path to downloads folder as text)
move allDownloads to trash
log ""
end tell

View File

@@ -1,22 +0,0 @@
#!/usr/bin/osascript
# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Viscosity: Connect
# @raycast.mode silent
# @raycast.packageName Viscosity
#
# Optional parameters:
# @raycast.icon images/viscosity.png
# @raycast.needsConfirmation false
# @raycast.argument1 { "type": "text", "placeholder": "Configuration" }
#
# Documentation:
# @raycast.description Connect a VPN viscosity configuration.
# @raycast.author Luigi Cardito (credits Achille Lacoin https://github.com/pomdtr)
# @raycast.authorURL https://github.com/lcardito
on run argv
tell application "Viscosity" to connect (item 1 of argv)
return # Discard Output
end run

View File

@@ -1,22 +0,0 @@
#!/usr/bin/osascript
# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Viscosity: Disconnect
# @raycast.mode silent
# @raycast.packageName Viscosity
#
# Optional parameters:
# @raycast.icon images/viscosity.png
# @raycast.needsConfirmation false
# @raycast.argument1 { "type": "text", "placeholder": "Configuration" }
#
# Documentation:
# @raycast.description Disconnect a VPN configuration.
# @raycast.author Luigi Cardito (credits Achille Lacoin https://github.com/pomdtr)
# @raycast.authorURL https://github.com/lcardito
on run argv
tell application "Viscosity" to disconnect (item 1 of argv)
return # Discard Output
end run

View File

@@ -1,27 +0,0 @@
#!/usr/bin/osascript
# @raycast.title Toggle Wi-Fi
# @raycast.author Vincent Dörig
# @raycast.authorURL https://github.com/vincentdoerig
# @raycast.description Toggle your Wi-Fi connection.
# @raycast.icon images/wifi-dark.png
# @raycast.iconDark images/wifi.png
# @raycast.mode silent
# @raycast.packageName System
# @raycast.schemaVersion 1
# Wi-Fi interface, should normally be either `en0` or `en1`
# ⌥ + click the wifi icon in your menu bar to display the Wi-Fi interface name
set Interface to "en0"
set NetworkStatus to (do shell script "networksetup -getairportnetwork " & Interface)
if (NetworkStatus contains "off") then
# turn Wi-Fi on
do shell script "networksetup -setairportpower Interface on"
do shell script "echo Wi-Fi turned on"
else
# turn Wi-Fi off
do shell script "networksetup -setairportpower Interface off"
do shell script "echo Wi-Fi turned off"
end if

View File

@@ -1,4 +1,3 @@
# Get the list of AWS profiles # Get the list of AWS profiles
function awsprofiles() { function awsprofiles() {
profiles=$(aws --no-cli-pager configure list-profiles 2> /dev/null) profiles=$(aws --no-cli-pager configure list-profiles 2> /dev/null)
@@ -28,19 +27,47 @@ function awslogin() {
;; ;;
*) *)
echo "Unknown option: $1" echo "Unknown option: $1"
echo "Usage: awslogin --profile prof [--region region]" echo "Usage: awslogin [--profile prof] [--region region]"
return 1 return 1
;; ;;
esac esac
done done
# Check if profile is provided # Get available profiles
if [[ -z "$profile" ]]; then local available_profiles
echo "Error: --profile parameter is required." available_profiles=$(aws --no-cli-pager configure list-profiles 2> /dev/null)
echo "Usage: awslogin --profile prof [--region region]" if [[ -z "$available_profiles" ]]; then
echo "No AWS profiles found in ~/.aws/config"
return 1 return 1
fi fi
# If no profile provided, use fzf to select one
if [[ -z "$profile" ]]; then
profile=$(echo "$available_profiles" | fzf --header "Select AWS profile" --height 40%)
if [[ -z "$profile" ]]; then
echo "No profile selected."
return 1
fi
else
# Check if provided profile exists
if ! echo "$available_profiles" | grep -qx "$profile"; then
echo "Profile '$profile' not found. Searching for matches..."
local matched_profiles
matched_profiles=$(echo "$available_profiles" | grep -i "$profile")
if [[ -z "$matched_profiles" ]]; then
echo "No matching profiles found."
return 1
fi
profile=$(echo "$matched_profiles" | fzf --header "Select AWS profile" --height 40%)
if [[ -z "$profile" ]]; then
echo "No profile selected."
return 1
fi
fi
fi
# Build AWS CLI options # Build AWS CLI options
local aws_opts=() local aws_opts=()
[[ -n "$profile" ]] && aws_opts+=(--profile "$profile") [[ -n "$profile" ]] && aws_opts+=(--profile "$profile")
@@ -71,10 +98,36 @@ function awslogout() {
unset AWS_ACCESS_KEY_ID unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN unset AWS_SESSION_TOKEN
unset AWS_CREDENTIAL_EXPIRATION
export AWS_PROFILE_DISPLAY="" export AWS_PROFILE_DISPLAY=""
echo "AWS profile and credentials cleared." echo "AWS profile and credentials cleared."
} }
function _aws_creds_expiration_check() {
if [[ -n "$AWS_CREDENTIAL_EXPIRATION" ]]; then
local expiration_epoch
local current_epoch
# Convert expiration time to epoch (handles ISO 8601 format)
if command -v gdate &> /dev/null; then
# macOS with GNU coreutils installed
expiration_epoch=$(gdate -d "$AWS_CREDENTIAL_EXPIRATION" +%s 2>/dev/null)
current_epoch=$(gdate +%s)
else
# macOS with BSD date
expiration_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%S%z" "$AWS_CREDENTIAL_EXPIRATION" +%s 2>/dev/null)
current_epoch=$(date +%s)
fi
if [[ $? -eq 0 && -n "$expiration_epoch" ]]; then
if [[ $current_epoch -ge $expiration_epoch ]]; then
echo "AWS credentials have expired. Logging out..."
awslogout
fi
fi
fi
}
# easy access to SSH # easy access to SSH
function awsssh() { function awsssh() {
local profile="" local profile=""