minor updates

This commit is contained in:
Arthur Khachaturov 2024-09-19 04:25:07 +03:00
parent e3790a4f3f
commit 628baf3eea
No known key found for this signature in database
GPG key ID: CAC2B7EB6DF45D55
32 changed files with 655 additions and 123 deletions

View file

@ -1,8 +1,18 @@
systemctl --user import-environment DISPLAY systemctl --user import-environment DISPLAY
export TERMINAL=/usr/bin/alacritty set -a
export TERM=/usr/bin/alacritty
export _JAVA_AWT_WM_NONREPARENTING=1 TERMINAL=/usr/bin/alacritty
export AWT_TOOLKIT=MToolkit TERM=/usr/bin/alacritty
_JAVA_AWT_WM_NONREPARENTING=1
AWT_TOOLKIT=MToolkit
MOZ_USE_XINPUT2=1
XDG_CURRENT_DESKTOP="gtk"
XDG_SESSION_DESKTOP="$XDG_CURRENT_DESKTOP"
WINDOW_MANAGER="dwm"
set +a
# vim: ft=bash # vim: ft=bash

View file

@ -1,15 +1,29 @@
-- Remap leader key to <Space> -- Remap leader key to <Space>
vim.g.mapleader = ' '
vim.g.maplocalleader = ' '
vim.keymap.set({ 'n', 'v' }, '<Space>', '<Nop>', { silent = true })
-- Load modules -- Load basic configuration
require("config") require("config")
require("utils.lazy").lazy_init()
-- Init lazy.nvim plugin manager
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
if not vim.loop.fs_stat(lazypath) then
vim.fn.system {
'git',
'clone',
'--filter=blob:none',
'https://github.com/folke/lazy.nvim.git',
'--branch=stable',
lazypath,
}
end
vim.opt.rtp:prepend(lazypath)
-- Load plugins
require("lazy").setup("plugins", { require("lazy").setup("plugins", {
change_detection = { change_detection = {
enabled = false, enabled = false,
notify = false, notify = false,
}, },
}) })
-- Load lsp configuration
require("lsp") require("lsp")

View file

@ -1,5 +1,14 @@
-- Set proper tabstop for go -- Set proper tabstop for go
vim.api.nvim_create_autocmd('FileType', { vim.api.nvim_create_autocmd('FileType', {
pattern = "go", pattern = "go",
command = "setlocal tabstop=4", command = "setlocal tabstop=4 noexpandtab",
})
-- Remove trailing whitespaces on save
vim.api.nvim_create_autocmd('BufWritePre', {
callback = function ()
local view = vim.fn.winsaveview()
vim.cmd('%s/\\s\\+$//e')
vim.fn.winrestview(view)
end
}) })

View file

@ -1,5 +1,10 @@
local map = vim.keymap.set local map = vim.keymap.set
-- Remap leader to <Space>
vim.g.mapleader = ' '
vim.g.maplocalleader = ' '
map({ 'n', 'v' }, '<Space>', '<Nop>', { silent = true })
-- Unbind keys -- Unbind keys
map('n', '<C-q>', '<NOP>') map('n', '<C-q>', '<NOP>')
map({ 'n', 'v' }, 'H', '<NOP>') map({ 'n', 'v' }, 'H', '<NOP>')
@ -28,6 +33,10 @@ map({ 'n', 'v' }, '<leader>m', '<C-w>10>')
map({ 'n', 'v' }, '<leader>N', '<C-w>6-') map({ 'n', 'v' }, '<leader>N', '<C-w>6-')
map({ 'n', 'v' }, '<leader>M', '<C-w>6+') map({ 'n', 'v' }, '<leader>M', '<C-w>6+')
-- quickfix buffer
map('n', '<M-n>', ':cn<CR>', { silent = true })
map('n', '<M-p>', ':cp<CR>', { silent = true })
-- Remap <M-BS> to remove last word -- Remap <M-BS> to remove last word
map('i', '<M-BS>', '<C-w>') map('i', '<M-BS>', '<C-w>')

View file

@ -16,7 +16,7 @@ vim.o.autoindent = true
vim.o.smartindent = true vim.o.smartindent = true
vim.o.smarttab = true vim.o.smarttab = true
vim.o.breakindent = true vim.o.breakindent = true
vim.o.softtabstop = -1 vim.o.softtabstop = 4
-- Save undo history -- Save undo history
vim.o.undofile = true vim.o.undofile = true

View file

@ -6,6 +6,8 @@ local servers = {
rust_analyzer = {}, rust_analyzer = {},
bashls = {}, bashls = {},
hls = {}, hls = {},
eslint = {},
ts_ls = {},
} }
vim.lsp.set_log_level("debug") vim.lsp.set_log_level("debug")
@ -43,7 +45,15 @@ for server_name, config in pairs(servers) do
lspconfig[server_name].setup({ lspconfig[server_name].setup({
capabilities = capabilities, capabilities = capabilities,
on_attach = on_attach, on_attach = on_attach,
settings = { [server_name] = config }, settings = {
[server_name] = config ~= {} and {
settings = {
[server_name] = {
config
}
}
} or {}
},
}) })
end end

View file

@ -1,10 +1,11 @@
return { return {
settings = {
['lua_ls'] = {
Lua = { Lua = {
workspace = { checkThirdParty = false }, workspace = {
checkThirdParty = true,
library = {
vim.env.VIMRUNTIME
}
},
telemetry = { enable = false }, telemetry = { enable = false },
}, },
} }
}
}

View file

@ -1,6 +1,8 @@
return { return {
'rcarriga/nvim-notify', 'rcarriga/nvim-notify',
'psliwka/vim-smoothie',
'stefandtw/quickfix-reflector.vim', 'stefandtw/quickfix-reflector.vim',
'tpope/vim-sleuth',
{ 'akinsho/bufferline.nvim', opts = {}, dependencies = { 'navarasu/onedark.nvim' } }, { 'akinsho/bufferline.nvim', opts = {}, dependencies = { 'navarasu/onedark.nvim' } },
{ 'ethanholz/nvim-lastplace', opts = {} }, { 'ethanholz/nvim-lastplace', opts = {} },
{ 'kylechui/nvim-surround', version = '*', event = 'VeryLazy', opts = {} }, { 'kylechui/nvim-surround', version = '*', event = 'VeryLazy', opts = {} },

View file

@ -36,6 +36,6 @@ return {
vim.keymap.set('n', '<leader>of', require('telescope.builtin').oldfiles) vim.keymap.set('n', '<leader>of', require('telescope.builtin').oldfiles)
vim.keymap.set('n', '<leader>af', require('telescope.builtin').git_files) vim.keymap.set('n', '<leader>af', require('telescope.builtin').git_files)
vim.keymap.set('n', '<leader>sf', require('telescope.builtin').find_files) vim.keymap.set('n', '<leader>sf', require('telescope.builtin').find_files)
vim.keymap.set('n', '<leader>sw', require('telescope.builtin').grep_string) vim.keymap.set('n', '<leader>fw', require('telescope.builtin').grep_string)
end end
} }

View file

@ -3,11 +3,9 @@ return {
opts = {}, opts = {},
cmd = "Trouble", cmd = "Trouble",
keys = { keys = {
{ "<leader>xx", "<cmd>Trouble diagnostics toggle<cr>" }, -- ?? { "<leader>ew", "<cmd>Trouble diagnostics toggle<cr>" },
{ "<leader>xX", "<cmd>Trouble diagnostics toggle filter.buf=0<cr>" }, -- useless? { "<leader>ef", "<cmd>Trouble diagnostics toggle filter.buf=0<cr>" },
{ "<leader>cs", "<cmd>Trouble symbols toggle focus=false<cr>" }, -- nice as well { "<leader>cs", "<cmd>Trouble symbols toggle focus=false<cr>" },
{ "<leader>cl", "<cmd>Trouble lsp toggle focus=false win.position=right<cr>" }, -- nicee { "<leader>cl", "<cmd>Trouble lsp toggle focus=false win.position=right<cr>" },
{ "<leader>xL", "<cmd>Trouble loclist toggle<cr>" }, -- ??
{ "<leader>xQ", "<cmd>Trouble qflist toggle<cr>" }, -- ??
}, },
} }

View file

@ -1,15 +0,0 @@
local M = { }
function M.close_buffer(force)
if #vim.fn.filter(vim.fn.range(1, vim.fn.bufnr '$'), 'buflisted(v:val)') <= 1 then
vim.api.nvim_command("qa" .. (force and "!" or ""))
else
local tree = require("nvim-tree.api").tree
tree.toggle({ focus = false })
vim.api.nvim_command("bd" .. (force and "!" or ""))
tree.toggle({ focus = false })
end
end
return M

View file

@ -1,18 +0,0 @@
local M = { }
function M.lazy_init()
local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim'
if not vim.loop.fs_stat(lazypath) then
vim.fn.system {
'git',
'clone',
'--filter=blob:none',
'https://github.com/folke/lazy.nvim.git',
'--branch=stable',
lazypath,
}
end
vim.opt.rtp:prepend(lazypath)
end
return M

View file

@ -21,8 +21,8 @@ bind ';' "command-prompt"
bind C-r "source-file ~/.config/tmux/tmux.conf" bind C-r "source-file ~/.config/tmux/tmux.conf"
# Session binds # Session binds
bind C-n "new-session -c '#{pane_current_path}' -s '#{b:pane_current_path}'" # bind C-n "new-session -c '#{pane_current_path}' -s '#{b:pane_current_path}'"
bind C-x "set-option -g detach-on-destroy on; kill-session" # bind C-x "set-option -g detach-on-destroy on; kill-session"
bind X "set-option -g detach-on-destroy off; kill-session; set-option -g detach-on-destroy on" bind X "set-option -g detach-on-destroy off; kill-session; set-option -g detach-on-destroy on"
# Select mode # Select mode

View file

@ -9,8 +9,8 @@ set -g @batt_icon_charge_tier6 ' '
set -g @batt_icon_charge_tier5 ' ' set -g @batt_icon_charge_tier5 ' '
set -g @batt_icon_charge_tier4 ' ' set -g @batt_icon_charge_tier4 ' '
set -g @batt_icon_charge_tier3 ' ' set -g @batt_icon_charge_tier3 ' '
set -g @batt_icon_charge_tier2 '' set -g @batt_icon_charge_tier2 ''
set -g @batt_icon_charge_tier1 '! !' set -g @batt_icon_charge_tier1 ''
# better-mouse-mode # better-mouse-mode
set -g @emulate-scroll-for-no-mouse-alternate-buffer "on" set -g @emulate-scroll-for-no-mouse-alternate-buffer "on"

View file

@ -13,10 +13,11 @@ set -g status-justify "left"
# status # status
set -g status-left-length 0 set -g status-left-length 0
set -g status-left "#[bg=#{@theme-active-bg},fg=#{@theme-active-fg}]#{?client_prefix,[#{session_name}],#[bg=#{@theme-bg},fg=#{@theme-fg}][#{session_name}]}#[bg=#{@theme-bg},fg=#{@theme-fg}] " set -g status-left "#[bg=#{@theme-active-bg},fg=#{@theme-active-fg}]#{?client_prefix,[#{session_name}],#[bg=#{@theme-bg},fg=#{@theme-fg}][#{session_name}]}#[bg=#{@theme-bg},fg=#{@theme-fg}] "
set -g status-right "#{battery_icon_charge} #{battery_percentage} | %a %m/%d %I:%M %P" set -g status-right "#(sb-battery -s) | %a %m/%d %I:%M %P"
set -g window-status-format " #I:#W " set -g window-status-format " #I:#W "
set -g window-status-current-format "#[bg=#{@theme-active-bg},fg=#{@theme-active-fg}, bold]#{?window_zoomed_flag, #I:#W 󰊓 , #I:#W }" set -g window-status-current-format "#[bg=#{@theme-active-bg},fg=#{@theme-active-fg}, bold]#{?window_zoomed_flag, #I:#W 󰊓 , #I:#W }"
set -g window-status-style "bg=#{@theme-bg},fg=#{@theme-fg}" set -g window-status-style "bg=#{@theme-bg},fg=#{@theme-fg}"
set -g status-interval "5"
# pane styles # pane styles
set -g pane-border-style "fg=#{@theme-active-bg}" set -g pane-border-style "fg=#{@theme-active-bg}"

View file

@ -28,6 +28,9 @@ setw -g pane-base-index 1
set -g visual-activity off set -g visual-activity off
set -g monitor-activity off set -g monitor-activity off
# number windows with respect for base-index
set -g renumber-windows on
# Resize all windows to max size? # Resize all windows to max size?
setw -g aggressive-resize on setw -g aggressive-resize on

View file

@ -1,4 +1,5 @@
# if [ -z "$SSH_AUTH_SOCK" ]; then # if [ -z "$SSH_AUTH_SOCK" ]; then
# eval "$(ssh-agent -s)" # eval "$(ssh-agent -s)"
# fi # fi
systemctl --user import-environment XDG_CURRENT_DESKTOP systemctl --user import-environment XDG_CURRENT_DESKTOP

View file

@ -1,7 +1,7 @@
set -a set -a
PATH="$HOME/.local/share/go/bin:$PATH" PATH="$HOME/.local/share/go/bin:$PATH"
PATH="${$(find -L ~/.local/bin -type d -printf %p:)%%:}:$PATH" PATH="${$(find -L ~/.local/bin ! -name '.*' -type d -printf %p:)%%:}:$PATH"
# lc vars # lc vars
LANGUAGE="en_US.UTF-8" LANGUAGE="en_US.UTF-8"
@ -26,11 +26,6 @@ GPG_TTY="$(tty)"
MANPAGER="sh -c 'col -bx | batcat -l man -p'" MANPAGER="sh -c 'col -bx | batcat -l man -p'"
MANROFFOPT="-c" MANROFFOPT="-c"
MTR_OPTIONS="-t" MTR_OPTIONS="-t"
MOZ_USE_XINPUT2=1
XDG_CURRENT_DESKTOP="gtk"
XDG_SESSION_DESKTOP="$XDG_CURRENT_DESKTOP"
WINDOW_MANAGER="dwm"
SUDO_ASKPASS="${HOME}/.local/bin/scripts/dmenu_askpass" SUDO_ASKPASS="${HOME}/.local/bin/scripts/dmenu_askpass"
SSH_ASKPASS="${HOME}/.local/bin/scripts/ssh-askpass" SSH_ASKPASS="${HOME}/.local/bin/scripts/ssh-askpass"

View file

@ -1,8 +1,7 @@
[[ $- != *i* ]] && return # [[ $- != *i* ]] && return # idk why would it be tho...
[ "$TERM" = "linux" ] && export TERM=fbterm
. ~/.cargo/env . ~/.cargo/env
. ~/.config/zsh/modes.sh
# ls colors # ls colors
eval "$(dircolors -b)" eval "$(dircolors -b)"
@ -86,6 +85,7 @@ alias 7z="7zz" # for whatever reason 7z provides 7zz binary in debian
alias wt="watch -d -cn 0.1 " alias wt="watch -d -cn 0.1 "
alias cal="ncal -b" alias cal="ncal -b"
alias .e="source .env" alias .e="source .env"
alias tp="taskell ${HOME}/.projects.md"
# function aliases # function aliases
bl() { brightnessctl set "$1"% &> /dev/null; } bl() { brightnessctl set "$1"% &> /dev/null; }
@ -126,4 +126,4 @@ alias ta="tmux a -t"
stty -ixon stty -ixon
# print tasks on startup # print tasks on startup
cat ~/.taskell.md cat ~/.taskell.md | grep -v '>.*'

62
.config/zsh/modes.sh Normal file
View file

@ -0,0 +1,62 @@
mode::enable() {
local mode_path="${HOME}/.config/zsh/modes/$1.sh"
[ ! -f "$mode_path" ] && echo "Mode not found!" && return 1
export MODE__ACTIVE_MODE="$1"
export MODE__OLD_PS1="$PS1"
export PS1="($1) $PS1"
# shellcheck disable=SC1090
source "$mode_path"
}
mode::disable() {
export PS1="${MODE__OLD_PS1}"
local mode_path="${HOME}/.config/zsh/modes/$MODE__ACTIVE_MODE.sh"
unset -v "MODE__OLD_PS1"
unset -v "MODE__ACTIVE_MODE"
for mode_variable in $(perl -ne '/^(?>declare\s+(?>--?\w+\s*)+\s*)?\s*([\x21-\x3c\x3e-\x7e]+)=.*$/ && print "$1\n"' < "$mode_path"); do
unset "$mode_variable"
done
for mode_function in $(perl -ne '/^(?>function\s+)?([\x21-\x7e]+)\s*\(\)/ && print "$1\n"' < "$mode_path"); do
unset -f "$mode_function"
done
for mode_alias in $(perl -ne '/^alias ([\x21-\x3c\x3e-\x7e]+)=/ && print "$1\n"'< "$mode_path"); do
unalias "$mode_alias"
done
}
mode::help() {
echo "USAGE"
echo " mode [-h]"
echo " mode <MODENAME>"
echo " mode"
echo
echo "OPTIONS"
echo " -h for help lol"
echo
echo "AVAILABLE MODES"
for mode in ~/.config/zsh/modes/*; do
printf " %s\n" "$(basename "${mode%.sh}")"
done
}
m() {
[ -n "$MODE__ACTIVE_MODE" ] && mode::disable && return
local cmd="${1:?}"
case "$cmd" in
"-h"|"--help")
mode::help
;;
*)
mode::enable "$cmd" || mode::help >&2
;;
esac
}

18
.config/zsh/modes/cpp.sh Normal file
View file

@ -0,0 +1,18 @@
# shellcheck disable=SC2139
CPP_MODE__BUILD_DIR="./cmake-build"
alias cb="cmake --build ${CPP_MODE__BUILD_DIR}"
alias cg="cmake -B ${CPP_MODE__BUILD_DIR} -DCMAKE_EXPORT_COMPILE_COMMANDS=1 && ln -sf ${CPP_MODE__BUILD_DIR}/compile_commands.json ."
cpp_mode::find_exec() {
find "${CPP_MODE__BUILD_DIR}/$1" -maxdepth 1 -type f -executable
}
ct() {
eval "$(cpp_mode::find_exec "tests")"
}
cr() {
eval "$(cpp_mode::find_exec)"
}

View file

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
API_ENDPOINT='http://ip-api.com/json/?fields=7876383' API_ENDPOINT="http://ip-api.com/json/$1"'?fields=7876383'
printf "%s" "$(curl "${API_ENDPOINT}" 2>/dev/null)" | jq -r '[ "IP: \(.query)", "Country: \(.country)", "City: \(.city)", "ISP: \(.isp)", "ASN: \(.as)" ][] | "\(.)"' printf "%s" "$(curl "${API_ENDPOINT}" 2>/dev/null)" | jq -r '[ "IP: \(.query)", "Country: \(.country)", "City: \(.city)", "ISP: \(.isp)", "ASN: \(.as)" ][] | "\(.)"'
# vim: ft=bash # vim: ft=bash

View file

@ -35,6 +35,7 @@ main() {
"--variable=published_time=$(date -Iseconds -d"$(stat "$1" | grep 'Birth:' | sed 's/.*Birth:\s//')")" "--variable=published_time=$(date -Iseconds -d"$(stat "$1" | grep 'Birth:' | sed 's/.*Birth:\s//')")"
) )
pandoc "${pandoc_options[@]}" <(shift_header "$1") > "$FILENAME" 2>/dev/null && pandoc "${pandoc_options[@]}" <(shift_header "$1") > "$FILENAME" 2>/dev/null &&
echo "$FILENAME" &&
firefox "$FILENAME" 2>/dev/null & disown firefox "$FILENAME" 2>/dev/null & disown
sleep 5 sleep 5

320
.local/bin/scripts/my.itmo Executable file
View file

@ -0,0 +1,320 @@
#!/bin/sh
# shellcheck disable=all
"exec" "${HOME}/.local/share/venv/statusbar/bin/python3" "-u" "$0" "$@"
import datetime
import json
import os
import signal
import sys
import time
import traceback
from collections.abc import Callable
from dataclasses import dataclass
from typing import Literal, Any, TypeVar
from urllib.parse import urlparse
import requests
from bs4 import BeautifulSoup, Tag
EMOJI_BY_STATUS = {
0: '🟡',
1: '🟢',
2: '🔴',
}
TIMEOUT = 30
CONFIG_FILE = f"{os.environ['HOME']}/.my.itmo"
CACHE_FILE = f"{os.environ['HOME']}/.cache/my_itmo.cache"
SECRET_FILE = f"{os.environ['HOME']}/.secrets/my_itmo.secret"
PIPE_FILE = f"{os.environ['XDG_RUNTIME_DIR']}/my.itmo.pipe"
T = TypeVar('T')
def run_forever(fn: Callable, *args, **kwargs):
while True:
try:
fn(*args, **kwargs)
except Exception:
print(traceback.format_exc())
def run_until_successful(fn: Callable[..., T], *args, **kwargs) -> T:
while True:
try:
return fn(*args, **kwargs)
except Exception:
pass
else:
break # no it's not >( # pyright: ignore
def send_message(chat_id: int, text: str, token: str):
requests.post(f"https://api.telegram.org/bot{token}/sendMessage", data={
'chat_id': chat_id,
'parse_mode': 'HTML',
'text': text
})
@dataclass
class StatusObject:
id: int
name: str
notice: str
status: Literal[0, 1, 2]
status_name: str
updated_at: datetime.datetime
created_at: datetime.datetime
@staticmethod
def from_dict(data: dict[str, Any]):
data['updated_at'] = datetime.datetime.strptime(data['updated_at'].replace("+03:00", ''), '%Y-%m-%dT%H:%M:%S')
data['created_at'] = datetime.datetime.strptime(data['created_at'].replace("+03:00", ''), '%Y-%m-%dT%H:%M:%S')
return StatusObject(**data)
class ApiException(Exception):
status_code: int
body: str
def __init__(self, status_code: int, body: str):
super().__init__(status_code, body)
self.status_code = status_code
self.body = body
def __str__(self):
return f'Status code: {self.status_code}\nBody: {self.body}'
class Api:
_session: requests.Session
_username: str
_password: str
_access_token: str
_refresh_token: str
_expires_in: int
_refresh_expires_in: int
def __init__(self, username: str, password: str, *, access_token: str | None = None,
refresh_token: str | None = None, expires_in: int | None = None,
refresh_expires_in: int | None = None, cookies: Any | None = None):
self._session = requests.Session()
self._username = username
self._password = password
self._refresh_token = refresh_token if refresh_token else ''
self._expires_in = expires_in if expires_in else 0
self._refresh_expires_in = refresh_expires_in if refresh_expires_in else 0
if cookies: self._session.cookies.update(cookies)
self._access_token = access_token if access_token else ''
if access_token: self._session.headers.update({'Authorization': f'Bearer {access_token}'})
self._ensure_authorized()
def _first_auth(self):
self._session.headers.clear()
self._session.cookies.clear()
code_request = run_until_successful(self._session.get, 'https://id.itmo.ru/auth/realms/itmo/protocol/openid-connect/auth', params={
'protocol': 'oauth2',
'response_type': 'code',
'client_id': 'student-personal-cabinet',
'redirect_uri': 'https://my.itmo.ru/login/callback',
'scope': 'openid profile',
}, timeout=2)
soup = BeautifulSoup(code_request.text, features='html.parser')
form = soup.find('form')
if not isinstance(form, Tag):
raise ApiException(code_request.status_code, code_request.text)
url = form.get_attribute_list('action')[0]
auth_request = run_until_successful(self._session.post, url, data={'username': self._username, 'password': self._password})
if auth_request.status_code != 200:
raise ApiException(auth_request.status_code, auth_request.text)
parsed_url_params = {a.split('=')[0]: a.split('=')[1] for a in urlparse(auth_request.url).query.split('&')}
self._get_and_save_tokens({
'code' : parsed_url_params['code'],
'client_id': 'student-personal-cabinet',
'redirect_uri': 'https://my.itmo.ru/login/callback',
'audience': '',
'response_type': 'code',
'grant_type': 'authorization_code',
'code_verifier': ''
})
def _renew(self):
self._session.headers.clear()
self._session.cookies.clear()
self._get_and_save_tokens({
'refresh_token': self._refresh_token,
'scopes': 'openid profile',
'client_id': 'student-personal-cabinet',
'grant_type': 'refresh_token'
})
def _get_and_save_tokens(self, data: Any):
tokens_request = run_until_successful(self._session.post, 'https://id.itmo.ru/auth/realms/itmo/protocol/openid-connect/token', data=data, timeout=2)
if tokens_request.status_code != 200:
raise ApiException(tokens_request.status_code, tokens_request.text)
tokens = tokens_request.json()
self._access_token = tokens['access_token']
self._expires_in = int(time.time()) + tokens['expires_in'] - 10
self._refresh_expires_in = int(time.time()) + tokens['refresh_expires_in'] - 10
self._refresh_token = tokens['refresh_token']
self._session.headers.update({"Authorization": f"Bearer {tokens_request.json()['access_token']}"})
def _ensure_authorized(self):
current_time = int(time.time())
if self._access_token and self._expires_in > current_time:
return
elif self._refresh_token and self._refresh_expires_in > current_time:
self._renew()
else:
self._first_auth()
def get_status_list(self):
self._ensure_authorized()
r = run_until_successful(self._session.get, 'https://my.itmo.ru/api/requests/my', timeout=2)
if r.status_code != 200 or r.json()['error_code'] != 0:
raise ApiException(r.status_code, r.text)
return [StatusObject.from_dict(obj) for obj in r.json()['result']]
def to_dict(self) -> Any:
return {
'username': self._username,
'password': self._password,
'access_token': self._access_token,
'refresh_token': self._refresh_token,
'expires_in': self._expires_in,
'refresh_expires_in': self._refresh_expires_in,
'cookies': self._session.cookies.get_dict()
}
@staticmethod
def from_dict(data: Any):
return Api(
data['username'],
data['password'],
access_token = data['access_token'],
refresh_token = data['refresh_token'],
expires_in = data['expires_in'],
refresh_expires_in = data['refresh_expires_in'],
cookies = data['cookies'],
)
def listen_for_messages(api: Api, timeout=TIMEOUT, filter_func: Callable[[StatusObject], bool] | None = None):
prev_msg = None
while True:
msg = list(filter(filter_func, api.get_status_list()))
if not msg or msg == prev_msg:
time.sleep(timeout)
continue
prev_msg = msg
yield msg
time.sleep(timeout)
format_status = lambda status: f"{EMOJI_BY_STATUS[status.status]} {status.notice.split('.')[0].strip()}"
format_message = lambda status: f"{EMOJI_BY_STATUS[status.status]} <b>{status.name}</b>\n\n{status.notice}"
class IDsFilter:
_ids: list[str]
_update_time: float
def __init__(self):
self._ids = []
self._update_dict()
def __call__(self, status: StatusObject) -> bool:
if self._update_time + TIMEOUT < time.time():
self._update_dict()
return str(status.id) in self._ids
def _update_dict(self):
self._update_time = time.time()
try:
with open(CONFIG_FILE) as file:
self._ids = file.read().strip().replace(' ', '').split(',')
except Exception:
self._ids = []
class LastUpdateFilter:
_update_time: datetime.datetime
def __init__(self, ignore_now = False) -> None:
self._update_time = datetime.datetime.fromtimestamp(0) if not ignore_now else datetime.datetime.now()
def __call__(self, status: StatusObject):
return status.updated_at >= self._update_time
def update(self):
self._update_time = datetime.datetime.now()
def main():
api = None
if os.path.isfile(CACHE_FILE):
with open(CACHE_FILE) as file:
api = Api.from_dict(json.load(file))
if os.path.isfile(SECRET_FILE):
with open(SECRET_FILE) as secret_file:
data = json.load(secret_file)
owner_id = data['owner_id']
bot_token = data['bot_token']
if not api:
api = Api(data['username'], data['password'])
else:
print("Missing secret file!", file=sys.stderr)
exit(1)
def die(*_):
with open(CACHE_FILE, 'w') as file:
json.dump(api.to_dict(), file)
if os.path.isfile(PIPE_FILE):
os.remove(PIPE_FILE)
exit(0)
signal.signal(signal.SIGTERM, die)
signal.signal(signal.SIGINT, die)
for message in listen_for_messages(api, filter_func=IDsFilter()):
with open(PIPE_FILE, 'w') as file:
print('\n'.join(map(format_status, message)))
file.write(' '.join(map(format_status, message)))
# update_filter = LastUpdateFilter(ignore_now=True)
# for message in listen_for_messages(api, filter_func=update_filter):
# formatted_messages = list(map(format_message, message))
# print('\n---\n'.join(formatted_messages))
# for message in formatted_messages:
# send_message(owner_id, message, bot_token)
# update_filter.update()
if __name__ == "__main__":
run_forever(main)
# vim: ft=python

90
.local/bin/scripts/tg Executable file
View file

@ -0,0 +1,90 @@
#!/bin/bash
{ read -r _TELEGRAM__BOT_TOKEN; read -r _TELEGRAM__USER_ID; } < "${HOME}/.secrets/telegram.secret"
declare -A _TELEGRAM__PARSE_MODES=(
[md]=MarkdownV2
[html]=HTML
)
declare -A tg__params=()
tg__code=0
tg::send_message() {
declare -a curl_params=()
for name in "${!tg__params[@]}"; do
curl_params+=("--data-urlencode" "$name=${tg__params[$name]}")
done
while IFS= read -d '' -n 4096 -r chunk; do
[ ${tg__code} -eq 1 ] &&
txt=(--data-urlencode "text=<pre>${chunk}</pre>") ||
txt=(--data-urlencode "text=${chunk}")
curl -X POST "https://api.telegram.org/bot${_TELEGRAM__BOT_TOKEN}/sendMessage" \
--data-urlencode "chat_id=$_TELEGRAM__USER_ID" \
"${curl_params[@]}" \
"${txt[@]}"
done
[ -n "$chunk" ] && {
[ ${tg__code} -eq 1 ] &&
txt=(--data-urlencode "text=<pre>${chunk}</pre>") ||
txt=(--data-urlencode "text=${chunk}")
curl -X POST "https://api.telegram.org/bot${_TELEGRAM__BOT_TOKEN}/sendMessage" \
--data-urlencode "chat_id=$_TELEGRAM__USER_ID" \
"${curl_params[@]}" \
"${txt[@]}"
}
}
(return 0 2>/dev/null) && return
help() {
echo "ABSTRACT"
echo " Read data from fd0 and send it to Telegram."
echo
echo "USAGE"
echo " tg [PARAMS]"
echo
echo "PARAMS"
echo " -c, --code Wrap text with <pre> tags"
echo " -h, --help Print this message"
echo " -p, --parse-mode Telegram parse mode (html, md)"
echo " -r, --print-response Don't silence Telegram response"
echo " --tg<NAME> <VALUE> Set POST parameter with NAME to VALUE"
}
die() {
echo "[ERROR] $1" >&2
echo
help
exit 1
}
main() {
while [ $# -gt 0 ]; do
case "$1" in
'-h'|'--help') help; exit 0 ;;
'-p'|'--parse-mode') shift; tg__params[parse_mode]="${_TELEGRAM__PARSE_MODES[$1]}" ;;
'-c'|'--code') tg__code=1; tg__params[parse_mode]='HTML' ;;
'-r'|'--print-response') print_response=1 ;;
'--tg'*) tg__params["${1#--tg}"]="$2"; shift ;;
esac
shift
done
[ -t 0 ] && die "Can't run on stdin!"
resp="$(tg::send_message "$@" 2>/dev/null)"
[ -n "${print_response:+_}" ] && echo "$resp"
[ "$(jq .ok <<<"$resp")" = "true" ] || jq <<< "$resp" >&2
}
main "$@"

View file

@ -41,9 +41,9 @@ while [ "$#" -gt 0 ]; do
'-c'|'--create') OPERATION=c;; '-c'|'--create') OPERATION=c;;
'-d'|'--deactivate') OPERATION=d; return;; '-d'|'--deactivate') OPERATION=d; return;;
'-r'|'--remove') OPERATION=r;; '-r'|'--remove') OPERATION=r;;
'-f'|'--folder') shift; VENV_FOLDER_NAME="$1";; '-f'|'--folder') shift; VENV_FOLDER_PATH="$1";;
-*) help; return;; -*) help; return;;
*) shift; VENV_FOLDER_PATH="$1";; *) VENV_FOLDER_NAME="$1";;
esac esac
shift shift
done done

View file

@ -4,22 +4,37 @@ shopt -s extglob
declare -a batteries declare -a batteries
status_by_charge() {
capacity="$1"
if [ "$capacity" -ge 95 ]; then
echo ' '
elif [ "$capacity" -ge 65 ]; then
echo ' '
elif [ "$capacity" -ge 50 ]; then
echo ' '
elif [ "$capacity" -gt 20 ]; then
echo ' '
fi
}
for battery_path in /sys/class/power_supply/!(AC*); do for battery_path in /sys/class/power_supply/!(AC*); do
status="$(cat "${battery_path}/status")" status="$(cat "${battery_path}/status")"
capacity="$(cat "${battery_path}/capacity")"
sep=$([ "$1" == "-s" ] && echo " ")
case "${status}" in case "${status}" in
"Full") status_string="⚡" ;; "Full") status_symbol=" " ;;
"Discharging") status_string="🔋" ;; "Discharging") status_symbol="$(status_by_charge "${capacity}")" ;;
"Charging") status_string="🔌" ;; "Charging") status_symbol="󱐥 " ;;
"Not charging") status_string="🛑" ;; "Not charging") status_symbol="󱐤 " ;;
"Unknown") status_string="♻️" ;; "Unknown") status_symbol="󰒲 " ;;
*) status_string="??" ;; *) status_symbol="?? " ;;
esac esac
capacity="$(cat "${battery_path}/capacity")" [ "$capacity" -eq 100 ] && status_symbol=" "
[ "$status" = "Discharging" ] && [ "$capacity" -le 25 ] && status_string="❗" [ "$status" = "Discharging" ] && [ "$capacity" -le 20 ] && { status_symbol="❗"; [ -n "$sep" ] && sep="" || sep=" "; }
batteries+=("${status_symbol}${sep}${capacity}%")
batteries+=("${status_string} ${capacity}%")
done done
echo "${batteries[@]}" echo "${batteries[@]}"

5
.local/bin/statusbar/sb-status Executable file
View file

@ -0,0 +1,5 @@
#!/bin/bash
FILEPATH="${XDG_RUNTIME_DIR}/my.itmo.pipe"
[ -f "${FILEPATH}" ] && cat "${FILEPATH}"

View file

@ -3,5 +3,5 @@
IFNAME="$(ip link show | grep 'wg_' | cut -d ' ' -f 2 | sed 's/://' | sed 's/wg_//' | tr '[:lower:]' '[:upper:]' | sed 's/_D/ (dpi)/')" IFNAME="$(ip link show | grep 'wg_' | cut -d ' ' -f 2 | sed 's/://' | sed 's/wg_//' | tr '[:lower:]' '[:upper:]' | sed 's/_D/ (dpi)/')"
if [ -n "${IFNAME}" ]; then if [ -n "${IFNAME}" ]; then
echo "🛡️ ${IFNAME}" echo "󰦝 ${IFNAME}"
fi fi

View file

@ -10,7 +10,8 @@ export XDG_CURRENT_DESKTOP="gtk"
export XDG_SESSION_DESKTOP="$XDG_CURRENT_DESKTOP" export XDG_SESSION_DESKTOP="$XDG_CURRENT_DESKTOP"
export WINDOW_MANAGER="dwm" export WINDOW_MANAGER="dwm"
exec ssh-agent "${HOME}"/.local/src/dwm/dwm eval "$(ssh-agent)"
# exec ssh-agent /usr/bin/dwm
exec "${HOME}"/.local/src/dwm/dwm
# vim: ft=sh # vim: ft=sh