Merge branch 'dmitmel-master'
This commit is contained in:
commit
34fb04a9d2
|
@ -4,22 +4,22 @@
|
||||||
base16_name = "eighties"
|
base16_name = "eighties"
|
||||||
name = "base16-" + base16_name
|
name = "base16-" + base16_name
|
||||||
base16_colors = [
|
base16_colors = [
|
||||||
"#2d2d2d", # 0
|
"#2d2d2d", # 0
|
||||||
"#393939", # 1
|
"#393939", # 1
|
||||||
"#515151", # 2
|
"#515151", # 2
|
||||||
"#747369", # 3
|
"#747369", # 3
|
||||||
"#a09f93", # 4
|
"#a09f93", # 4
|
||||||
"#d3d0c8", # 5
|
"#d3d0c8", # 5
|
||||||
"#e8e6df", # 6
|
"#e8e6df", # 6
|
||||||
"#f2f0ec", # 7
|
"#f2f0ec", # 7
|
||||||
"#f2777a", # 8
|
"#f2777a", # 8
|
||||||
"#f99157", # 9
|
"#f99157", # 9
|
||||||
"#ffcc66", # a
|
"#ffcc66", # a
|
||||||
"#99cc99", # b
|
"#99cc99", # b
|
||||||
"#66cccc", # c
|
"#66cccc", # c
|
||||||
"#6699cc", # d
|
"#6699cc", # d
|
||||||
"#cc99cc", # e
|
"#cc99cc", # e
|
||||||
"#d27b53", # f
|
"#d27b53", # f
|
||||||
]
|
]
|
||||||
|
|
||||||
bg = base16_colors[0x0]
|
bg = base16_colors[0x0]
|
||||||
|
@ -32,19 +32,18 @@ selection_bg = base16_colors[0x2]
|
||||||
selection_fg = fg
|
selection_fg = fg
|
||||||
|
|
||||||
ansi_colors = [
|
ansi_colors = [
|
||||||
base16_colors[int(i, 16)]
|
base16_colors[int(i, 16)] for i in "0 8 B A D E C 5 3 8 B A D E C 7 9 F 1 2 4 6".split()
|
||||||
for i in "0 8 B A D E C 5 3 8 B A D E C 7 9 F 1 2 4 6".split()
|
|
||||||
]
|
]
|
||||||
|
|
||||||
link_color = ansi_colors[0xC]
|
link_color = ansi_colors[0xC]
|
||||||
|
|
||||||
css_variables_prefix = "dotfiles-colorscheme-"
|
css_variables_prefix = "dotfiles-colorscheme-"
|
||||||
css_variables = {
|
css_variables = {
|
||||||
"bg": bg,
|
"bg": bg,
|
||||||
"fg": fg,
|
"fg": fg,
|
||||||
"selection-bg": selection_bg,
|
"selection-bg": selection_bg,
|
||||||
"selection-fg": selection_fg,
|
"selection-fg": selection_fg,
|
||||||
"cursor-bg": cursor_bg,
|
"cursor-bg": cursor_bg,
|
||||||
"cursor-fg": cursor_fg,
|
"cursor-fg": cursor_fg,
|
||||||
**{"base-{:02X}".format(index): color for index, color in enumerate(base16_colors)},
|
**{"base-{:02X}".format(index): color for index, color in enumerate(base16_colors)},
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
import _theme as theme
|
import _theme as theme
|
||||||
|
|
||||||
|
|
||||||
print(
|
print(
|
||||||
"""\
|
"""\
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
|
@ -13,9 +14,9 @@ print(
|
||||||
|
|
||||||
|
|
||||||
def print_color(key_name, color):
|
def print_color(key_name, color):
|
||||||
r, g, b = [float(int(color[2 * i + 1 : 2 * i + 3], 16)) / 255 for i in range(3)]
|
r, g, b = [float(int(color[2 * i + 1:2 * i + 3], 16)) / 255 for i in range(3)]
|
||||||
print(
|
print(
|
||||||
"""\
|
"""\
|
||||||
<key>{} Color</key>
|
<key>{} Color</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>Color Space</key>
|
<key>Color Space</key>
|
||||||
|
@ -27,10 +28,8 @@ def print_color(key_name, color):
|
||||||
<key>Blue Component</key>
|
<key>Blue Component</key>
|
||||||
<real>{}</real>
|
<real>{}</real>
|
||||||
</dict>\
|
</dict>\
|
||||||
""".format(
|
""".format(key_name, r, g, b)
|
||||||
key_name, r, g, b
|
)
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
print_color("Background", theme.bg)
|
print_color("Background", theme.bg)
|
||||||
|
@ -41,12 +40,10 @@ print_color("Cursor Text", theme.cursor_fg)
|
||||||
print_color("Selection Color", theme.selection_bg)
|
print_color("Selection Color", theme.selection_bg)
|
||||||
print_color("Selected Text Color", theme.selection_fg)
|
print_color("Selected Text Color", theme.selection_fg)
|
||||||
for index, color in enumerate(theme.ansi_colors[:16]):
|
for index, color in enumerate(theme.ansi_colors[:16]):
|
||||||
print_color("Ansi " + str(index), color)
|
print_color("Ansi " + str(index), color)
|
||||||
print_color("Link", theme.link_color)
|
print_color("Link", theme.link_color)
|
||||||
|
|
||||||
print(
|
print("""\
|
||||||
"""\
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>\
|
</plist>\
|
||||||
"""
|
""")
|
||||||
)
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import _theme as theme
|
||||||
|
|
||||||
|
|
||||||
def print_color(key_name, color):
|
def print_color(key_name, color):
|
||||||
print("{} {}".format(key_name, color))
|
print("{} {}".format(key_name, color))
|
||||||
|
|
||||||
|
|
||||||
print_color("background", theme.bg)
|
print_color("background", theme.bg)
|
||||||
|
@ -14,7 +14,7 @@ print_color("cursor_text_color", theme.cursor_fg)
|
||||||
print_color("selection_background", theme.selection_bg)
|
print_color("selection_background", theme.selection_bg)
|
||||||
print_color("selection_foreground", theme.selection_fg)
|
print_color("selection_foreground", theme.selection_fg)
|
||||||
for index, color in enumerate(theme.ansi_colors[:16]):
|
for index, color in enumerate(theme.ansi_colors[:16]):
|
||||||
print_color("color" + str(index), color)
|
print_color("color" + str(index), color)
|
||||||
print_color("url_color", theme.link_color)
|
print_color("url_color", theme.link_color)
|
||||||
|
|
||||||
print_color("active_border_color", theme.ansi_colors[2])
|
print_color("active_border_color", theme.ansi_colors[2])
|
||||||
|
|
|
@ -4,11 +4,9 @@ import _theme as theme
|
||||||
import os
|
import os
|
||||||
|
|
||||||
with open(os.path.join(os.path.dirname(__file__), "prismjs-theme-src.css")) as f:
|
with open(os.path.join(os.path.dirname(__file__), "prismjs-theme-src.css")) as f:
|
||||||
css_src = f.read()
|
css_src = f.read()
|
||||||
|
|
||||||
for var_name, color in theme.css_variables.items():
|
for var_name, color in theme.css_variables.items():
|
||||||
css_src = css_src.replace(
|
css_src = css_src.replace("var(--{}{})".format(theme.css_variables_prefix, var_name), color)
|
||||||
"var(--{}{})".format(theme.css_variables_prefix, var_name), color
|
|
||||||
)
|
|
||||||
|
|
||||||
print(css_src)
|
print(css_src)
|
||||||
|
|
|
@ -8,11 +8,4 @@ import _theme as theme
|
||||||
# 0,0,0,0,170,170,170,170,85,85,85,85,255,255,255,255
|
# 0,0,0,0,170,170,170,170,85,85,85,85,255,255,255,255
|
||||||
|
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
print(
|
print(",".join([str(int(color[2 * i + 1:2 * i + 3], 16)) for color in theme.ansi_colors[:16]]))
|
||||||
",".join(
|
|
||||||
[
|
|
||||||
str(int(color[2 * i + 1 : 2 * i + 3], 16))
|
|
||||||
for color in theme.ansi_colors[:16]
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
|
@ -4,11 +4,11 @@ import _theme as theme
|
||||||
|
|
||||||
|
|
||||||
def print_color(key_name, color):
|
def print_color(key_name, color):
|
||||||
print("{}={}".format(key_name, color))
|
print("{}={}".format(key_name, color))
|
||||||
|
|
||||||
|
|
||||||
print_color("background", theme.bg)
|
print_color("background", theme.bg)
|
||||||
print_color("foreground", theme.fg)
|
print_color("foreground", theme.fg)
|
||||||
print_color("cursor", theme.cursor_bg)
|
print_color("cursor", theme.cursor_bg)
|
||||||
for index, color in enumerate(theme.ansi_colors[:16]):
|
for index, color in enumerate(theme.ansi_colors[:16]):
|
||||||
print_color("color" + str(index), color)
|
print_color("color" + str(index), color)
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
import _theme as theme
|
import _theme as theme
|
||||||
|
|
||||||
|
|
||||||
print(":root {")
|
print(":root {")
|
||||||
for var_name, color in theme.css_variables.items():
|
for var_name, color in theme.css_variables.items():
|
||||||
print(" --{}{}: {};".format(theme.css_variables_prefix, var_name, color))
|
print(" --{}{}: {};".format(theme.css_variables_prefix, var_name, color))
|
||||||
print("}")
|
print("}")
|
||||||
|
|
|
@ -2,20 +2,21 @@
|
||||||
|
|
||||||
import _theme as theme
|
import _theme as theme
|
||||||
|
|
||||||
|
|
||||||
print("let dotfiles_colorscheme_name = '{}'".format(theme.name))
|
print("let dotfiles_colorscheme_name = '{}'".format(theme.name))
|
||||||
print("let dotfiles_colorscheme_base16_name = '{}'".format(theme.base16_name))
|
print("let dotfiles_colorscheme_base16_name = '{}'".format(theme.base16_name))
|
||||||
print("let dotfiles_colorscheme_base16_colors = [")
|
print("let dotfiles_colorscheme_base16_colors = [")
|
||||||
gui_to_cterm_mapping = [0, 18, 19, 8, 20, 7, 21, 15, 1, 16, 3, 2, 6, 4, 5, 17]
|
gui_to_cterm_mapping = [0, 18, 19, 8, 20, 7, 21, 15, 1, 16, 3, 2, 6, 4, 5, 17]
|
||||||
for colors_pair in zip(theme.base16_colors[:16], gui_to_cterm_mapping):
|
for colors_pair in zip(theme.base16_colors[:16], gui_to_cterm_mapping):
|
||||||
print("\\ {{'gui': '{}', 'cterm': '{:>02}'}},".format(*colors_pair))
|
print("\\ {{'gui': '{}', 'cterm': '{:>02}'}},".format(*colors_pair))
|
||||||
print("\\ ]")
|
print("\\ ]")
|
||||||
|
|
||||||
|
|
||||||
def print_terminal_color(key_name, color):
|
def print_terminal_color(key_name, color):
|
||||||
print("let terminal_color_{} = '{}'".format(key_name, color))
|
print("let terminal_color_{} = '{}'".format(key_name, color))
|
||||||
|
|
||||||
|
|
||||||
print_terminal_color("background", theme.bg)
|
print_terminal_color("background", theme.bg)
|
||||||
print_terminal_color("foreground", theme.fg)
|
print_terminal_color("foreground", theme.fg)
|
||||||
for index, color in enumerate(theme.ansi_colors[:16]):
|
for index, color in enumerate(theme.ansi_colors[:16]):
|
||||||
print_terminal_color(str(index), color)
|
print_terminal_color(str(index), color)
|
||||||
|
|
|
@ -5,31 +5,27 @@ import json
|
||||||
|
|
||||||
|
|
||||||
ANSI_COLOR_NAMES = [
|
ANSI_COLOR_NAMES = [
|
||||||
"Black",
|
"Black",
|
||||||
"Red",
|
"Red",
|
||||||
"Green",
|
"Green",
|
||||||
"Yellow",
|
"Yellow",
|
||||||
"Blue",
|
"Blue",
|
||||||
"Magenta",
|
"Magenta",
|
||||||
"Cyan",
|
"Cyan",
|
||||||
"White",
|
"White",
|
||||||
]
|
]
|
||||||
|
|
||||||
colors = {
|
colors = {
|
||||||
"terminal.background": theme.bg,
|
"terminal.background": theme.bg,
|
||||||
"terminal.foreground": theme.fg,
|
"terminal.foreground": theme.fg,
|
||||||
"terminal.selectionBackground": theme.selection_bg,
|
"terminal.selectionBackground": theme.selection_bg,
|
||||||
"terminalCursor.background": theme.cursor_fg,
|
"terminalCursor.background": theme.cursor_fg,
|
||||||
"terminalCursor.foreground": theme.cursor_bg,
|
"terminalCursor.foreground": theme.cursor_bg,
|
||||||
}
|
}
|
||||||
|
|
||||||
for color_brightness in [False, True]:
|
for color_brightness in [False, True]:
|
||||||
for color_index, color_name in enumerate(ANSI_COLOR_NAMES):
|
for color_index, color_name in enumerate(ANSI_COLOR_NAMES):
|
||||||
color = theme.ansi_colors[
|
color = theme.ansi_colors[color_index + int(color_brightness) * len(ANSI_COLOR_NAMES)]
|
||||||
color_index + int(color_brightness) * len(ANSI_COLOR_NAMES)
|
colors["terminal.ansi" + ("Bright" if color_brightness else "") + color_name] = color
|
||||||
]
|
|
||||||
colors[
|
|
||||||
"terminal.ansi" + ("Bright" if color_brightness else "") + color_name
|
|
||||||
] = color
|
|
||||||
|
|
||||||
print(json.dumps(colors, ensure_ascii=False, indent=2))
|
print(json.dumps(colors, ensure_ascii=False, indent=2))
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import _theme as theme
|
import _theme as theme
|
||||||
|
|
||||||
|
|
||||||
print("[Scheme]")
|
print("[Scheme]")
|
||||||
print("Name=dmitmel's dotfiles colorscheme")
|
print("Name=dmitmel's dotfiles colorscheme")
|
||||||
print("ColorForeground={}".format(theme.fg))
|
print("ColorForeground={}".format(theme.fg))
|
||||||
|
|
|
@ -2,19 +2,18 @@
|
||||||
|
|
||||||
import _theme as theme
|
import _theme as theme
|
||||||
|
|
||||||
|
|
||||||
for attr in [
|
for attr in [
|
||||||
"bg",
|
"bg",
|
||||||
"fg",
|
"fg",
|
||||||
"cursor_bg",
|
"cursor_bg",
|
||||||
"cursor_fg",
|
"cursor_fg",
|
||||||
"selection_bg",
|
"selection_bg",
|
||||||
"selection_fg",
|
"selection_fg",
|
||||||
"link_color",
|
"link_color",
|
||||||
]:
|
]:
|
||||||
color = getattr(theme, attr)
|
color = getattr(theme, attr)
|
||||||
print("colorscheme_{}={}".format(attr, color[1:]))
|
print("colorscheme_{}={}".format(attr, color[1:]))
|
||||||
print("colorscheme_ansi_colors=(")
|
print("colorscheme_ansi_colors=(")
|
||||||
for color in theme.ansi_colors:
|
for color in theme.ansi_colors:
|
||||||
print(" {}".format(color[1:]))
|
print(" {}".format(color[1:]))
|
||||||
print(")")
|
print(")")
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
setlocal nofoldenable foldmethod=manual
|
|
@ -1,3 +1 @@
|
||||||
let g:haskall_test = 1
|
setlocal foldmethod< foldtext<
|
||||||
setlocal foldmethod<
|
|
||||||
setlocal foldtext<
|
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
setlocal foldmethod<
|
setlocal foldmethod< foldtext<
|
||||||
setlocal foldtext<
|
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
setlocal foldmethod<
|
setlocal foldmethod< foldtext<
|
||||||
setlocal foldtext<
|
|
||||||
|
|
|
@ -4,5 +4,4 @@
|
||||||
" sourced in `syntax/nginx.vim` in vim-polyglot, which resets the `commentstring`
|
" sourced in `syntax/nginx.vim` in vim-polyglot, which resets the `commentstring`
|
||||||
" set in `ftplugin/nginx.vim` and sets `comments` to some garbage. This script
|
" set in `ftplugin/nginx.vim` and sets `comments` to some garbage. This script
|
||||||
" undoes that damage.
|
" undoes that damage.
|
||||||
setlocal comments<
|
setlocal comments< commentstring=#%s
|
||||||
setlocal commentstring=#%s
|
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
let g:coc_global_extensions += ['coc-pyright']
|
let g:coc_global_extensions += ['coc-pyright']
|
||||||
let g:coc_filetypes += ['python']
|
let g:coc_filetypes += ['python']
|
||||||
" let g:coc_user_config['pyls.plugins.pycodestyle.ignore'] = ['E501']
|
|
||||||
" let g:coc_user_config['python.autocomplete.showAdvancedMembers'] = v:false
|
" let g:coc_user_config['python.autocomplete.showAdvancedMembers'] = v:false
|
||||||
let g:coc_user_config['python'] = {
|
let g:coc_user_config['python'] = {
|
||||||
\ 'formatting': { 'provider': 'black' },
|
\ 'formatting': {
|
||||||
|
\ 'provider': 'yapf',
|
||||||
|
\ 'yapfArgs': ['--style=' . simplify(g:nvim_dotfiles_dir.'/../python/yapf.ini')]
|
||||||
|
\ },
|
||||||
\ 'linting': {
|
\ 'linting': {
|
||||||
\ 'pylintEnabled': v:false,
|
\ 'pylintEnabled': v:false,
|
||||||
\ 'flake8Enabled': v:true,
|
\ 'flake8Enabled': v:true,
|
||||||
\ 'flake8Args': ['--ignore', 'E501'],
|
\ 'flake8Args': ['--config=' . simplify(g:nvim_dotfiles_dir.'/../python/flake8.ini')],
|
||||||
\ },
|
\ },
|
||||||
\ }
|
\ }
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
Plug 'tpope/vim-repeat'
|
Plug 'tpope/vim-repeat'
|
||||||
" if g:vim_ide
|
" if g:vim_ide
|
||||||
Plug 'tomtom/tcomment_vim'
|
Plug 'tomtom/tcomment_vim'
|
||||||
|
Plug 'glts/vim-textobj-comment'
|
||||||
" else
|
" else
|
||||||
" Plug 'tpope/vim-commentary'
|
" Plug 'tpope/vim-commentary'
|
||||||
" endif
|
" endif
|
||||||
|
@ -44,9 +45,6 @@
|
||||||
Plug 'vim-airline/vim-airline'
|
Plug 'vim-airline/vim-airline'
|
||||||
Plug 'tpope/vim-obsession'
|
Plug 'tpope/vim-obsession'
|
||||||
Plug 'romainl/vim-qf'
|
Plug 'romainl/vim-qf'
|
||||||
if g:vim_ide
|
|
||||||
Plug 'dyng/ctrlsf.vim'
|
|
||||||
endif
|
|
||||||
" }}}
|
" }}}
|
||||||
|
|
||||||
" Git {{{
|
" Git {{{
|
||||||
|
|
|
@ -58,23 +58,17 @@ set commentstring=//%s
|
||||||
|
|
||||||
|
|
||||||
" Cursor and Scrolling {{{
|
" Cursor and Scrolling {{{
|
||||||
|
set number relativenumber cursorline
|
||||||
set number
|
|
||||||
set relativenumber
|
|
||||||
set cursorline
|
|
||||||
|
|
||||||
" remember cursor position
|
" remember cursor position
|
||||||
augroup vimrc-editing-remember-cursor-position
|
augroup vimrc-editing-remember-cursor-position
|
||||||
autocmd!
|
autocmd!
|
||||||
autocmd BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exec "normal! g`\"" | endif
|
autocmd BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exec "normal! g`\"" | endif
|
||||||
augroup END
|
augroup END
|
||||||
|
|
||||||
" }}}
|
" }}}
|
||||||
|
|
||||||
|
|
||||||
" Wrapping {{{
|
" Wrapping {{{
|
||||||
set nowrap
|
set nowrap colorcolumn=81,101,121
|
||||||
set colorcolumn=81,101,121
|
|
||||||
" }}}
|
" }}}
|
||||||
|
|
||||||
|
|
||||||
|
@ -236,6 +230,7 @@ set commentstring=//%s
|
||||||
" Remove the mappings that I won't use
|
" Remove the mappings that I won't use
|
||||||
let g:tcomment_maps = 0
|
let g:tcomment_maps = 0
|
||||||
|
|
||||||
|
" Closely replicate the behavior of tpope/vim-commentary
|
||||||
nmap <silent> gc <Plug>TComment_gc
|
nmap <silent> gc <Plug>TComment_gc
|
||||||
nmap <silent> gcc <Plug>TComment_gcc
|
nmap <silent> gcc <Plug>TComment_gcc
|
||||||
nmap <silent> gC <Plug>TComment_gcb
|
nmap <silent> gC <Plug>TComment_gcb
|
||||||
|
@ -244,6 +239,8 @@ set commentstring=//%s
|
||||||
nmap <silent> gCC m'o<Esc>''<Plug>TComment_gcb+
|
nmap <silent> gCC m'o<Esc>''<Plug>TComment_gcb+
|
||||||
xnoremap <silent> gc :TCommentMaybeInline<CR>
|
xnoremap <silent> gc :TCommentMaybeInline<CR>
|
||||||
xnoremap <silent> gC :TCommentBlock<CR>
|
xnoremap <silent> gC :TCommentBlock<CR>
|
||||||
|
" Make an alias for the comment text object
|
||||||
|
omap <silent> gc ac
|
||||||
|
|
||||||
" }}}
|
" }}}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,23 @@ nnoremap <silent><expr> <CR> empty(&buftype) ? ":write<bar>wall\<CR>" : "\<CR>"
|
||||||
command! -bang -nargs=* Rg call fzf#vim#grep(s:rg_cmd . ' --column --line-number --no-heading --fixed-strings --smart-case --color always ' . shellescape(<q-args>), 1, <bang>0)
|
command! -bang -nargs=* Rg call fzf#vim#grep(s:rg_cmd . ' --column --line-number --no-heading --fixed-strings --smart-case --color always ' . shellescape(<q-args>), 1, <bang>0)
|
||||||
command! -bang -nargs=* Find Rg<bang> <args>
|
command! -bang -nargs=* Find Rg<bang> <args>
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
nnoremap <leader>/ :<C-u>grep<space>
|
||||||
|
|
||||||
|
function! s:grep_mapping_star_normal()
|
||||||
|
let word = expand("<cword>")
|
||||||
|
if !empty(word)
|
||||||
|
call feedkeys(":\<C-u>grep " . shellescape('\b' . word . '\b'), 'n')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
function! s:grep_mapping_star_visual()
|
||||||
|
let tmp = @"
|
||||||
|
normal! y
|
||||||
|
call feedkeys(":\<C-u>grep " . shellescape(@"), 'n')
|
||||||
|
let @" = tmp
|
||||||
|
endfunction
|
||||||
|
nnoremap <leader>* <Cmd>call <SID>grep_mapping_star_normal()<CR>
|
||||||
|
xnoremap <leader>* <Cmd>call <SID>grep_mapping_star_visual()<CR>
|
||||||
" }}}
|
" }}}
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,7 +46,10 @@ nnoremap <silent><expr> <CR> empty(&buftype) ? ":write<bar>wall\<CR>" : "\<CR>"
|
||||||
let g:loaded_netrwPlugin = 1
|
let g:loaded_netrwPlugin = 1
|
||||||
" re-add Netrw's gx mappings since we've disabled them
|
" re-add Netrw's gx mappings since we've disabled them
|
||||||
nnoremap <silent> gx <Cmd>call netrw#BrowseX(expand('<cfile>'),netrw#CheckIfRemote())<CR>
|
nnoremap <silent> gx <Cmd>call netrw#BrowseX(expand('<cfile>'),netrw#CheckIfRemote())<CR>
|
||||||
xnoremap <silent> gx <Cmd>call netrw#BrowseXVis()<CR>
|
" This one can be rewritten in a way to not clobber the yank register...
|
||||||
|
" Most notably, the built-in mapping, which uses netrw#BrowseXVis(), doesn't
|
||||||
|
" work and breaks the editor, at least for me.
|
||||||
|
xnoremap <silent> gx y:<C-u>call netrw#BrowseX(@",netrw#CheckIfRemote())<CR>
|
||||||
" }}}
|
" }}}
|
||||||
|
|
||||||
|
|
||||||
|
@ -176,10 +196,3 @@ nnoremap <silent><expr> <CR> empty(&buftype) ? ":write<bar>wall\<CR>" : "\<CR>"
|
||||||
augroup END
|
augroup END
|
||||||
|
|
||||||
" }}}
|
" }}}
|
||||||
|
|
||||||
|
|
||||||
" CtrlSF {{{
|
|
||||||
nmap <leader>/ <Plug>CtrlSFPrompt
|
|
||||||
nmap <leader>* <Plug>CtrlSFCwordPath
|
|
||||||
xmap <leader>* <Plug>CtrlSFVwordPath
|
|
||||||
" }}}
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
[flake8]
|
||||||
|
ignore =
|
||||||
|
# Indent is not a multiple of 4
|
||||||
|
E111
|
||||||
|
# Indent is not a multiple of 4 for comments
|
||||||
|
E114
|
||||||
|
# Indent for continuation lines is smaller than expected
|
||||||
|
E121
|
||||||
|
# Import not at the top of the file
|
||||||
|
E402
|
||||||
|
# Line too long
|
||||||
|
E501
|
|
@ -0,0 +1,9 @@
|
||||||
|
[style]
|
||||||
|
based_on_style = google
|
||||||
|
column_limit = 99
|
||||||
|
indent_width = 2
|
||||||
|
continuation_indent_width = 2
|
||||||
|
blank_lines_between_top_level_imports_and_variables = 2
|
||||||
|
dedent_closing_brackets = true
|
||||||
|
coalesce_brackets = true
|
||||||
|
spaces_around_power_operator = true
|
|
@ -4,95 +4,90 @@ import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Iterable, NoReturn
|
from typing import Iterable, NoReturn
|
||||||
|
|
||||||
|
|
||||||
if os.name == "posix":
|
if os.name == "posix":
|
||||||
DOTFILES_CONFIG_DIR: Path = Path.home() / ".config" / "dotfiles"
|
DOTFILES_CONFIG_DIR: Path = Path.home() / ".config" / "dotfiles"
|
||||||
DOTFILES_CACHE_DIR: Path = Path.home() / ".cache" / "dotfiles"
|
DOTFILES_CACHE_DIR: Path = Path.home() / ".cache" / "dotfiles"
|
||||||
|
|
||||||
|
|
||||||
def platform_not_supported_error() -> NoReturn:
|
def platform_not_supported_error() -> NoReturn:
|
||||||
raise Exception("platform '{}' is not supported!".format(sys.platform))
|
raise Exception("platform '{}' is not supported!".format(sys.platform))
|
||||||
|
|
||||||
|
|
||||||
def run_chooser(
|
def run_chooser(choices: Iterable[str], prompt: str = None, async_read: bool = False) -> int:
|
||||||
choices: Iterable[str], prompt: str = None, async_read: bool = False
|
supports_result_index = True
|
||||||
) -> int:
|
if os.isatty(sys.stderr.fileno()):
|
||||||
supports_result_index = True
|
process_args = [
|
||||||
if os.isatty(sys.stderr.fileno()):
|
"fzf",
|
||||||
process_args = [
|
"--with-nth=2..",
|
||||||
"fzf",
|
"--height=50%",
|
||||||
"--with-nth=2..",
|
"--reverse",
|
||||||
"--height=50%",
|
"--tiebreak=index",
|
||||||
"--reverse",
|
]
|
||||||
"--tiebreak=index",
|
supports_result_index = False
|
||||||
]
|
elif sys.platform == "darwin":
|
||||||
supports_result_index = False
|
process_args = ["choose", "-i"]
|
||||||
elif sys.platform == "darwin":
|
elif os.name == "posix":
|
||||||
process_args = ["choose", "-i"]
|
process_args = ["rofi", "-dmenu", "-i", "-format", "i"]
|
||||||
elif os.name == "posix":
|
if prompt is not None:
|
||||||
process_args = ["rofi", "-dmenu", "-i", "-format", "i"]
|
process_args += ["-p", prompt]
|
||||||
if prompt is not None:
|
if async_read:
|
||||||
process_args += ["-p", prompt]
|
process_args += ["-async-pre-read", "0"]
|
||||||
if async_read:
|
else:
|
||||||
process_args += ["-async-pre-read", "0"]
|
platform_not_supported_error()
|
||||||
else:
|
|
||||||
platform_not_supported_error()
|
|
||||||
|
|
||||||
chooser_process = subprocess.Popen(
|
chooser_process = subprocess.Popen(process_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||||
process_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE
|
|
||||||
)
|
|
||||||
|
|
||||||
with chooser_process.stdin as pipe:
|
with chooser_process.stdin as pipe:
|
||||||
for index, choice in enumerate(choices):
|
for index, choice in enumerate(choices):
|
||||||
assert "\n" not in choice
|
assert "\n" not in choice
|
||||||
if not supports_result_index:
|
if not supports_result_index:
|
||||||
pipe.write(str(index).encode())
|
pipe.write(str(index).encode())
|
||||||
pipe.write(b" ")
|
pipe.write(b" ")
|
||||||
pipe.write(choice.encode())
|
pipe.write(choice.encode())
|
||||||
pipe.write(b"\n")
|
pipe.write(b"\n")
|
||||||
|
|
||||||
exit_code: int = chooser_process.wait()
|
exit_code: int = chooser_process.wait()
|
||||||
if exit_code != 0:
|
if exit_code != 0:
|
||||||
raise Exception("chooser process failed with exit code {}".format(exit_code))
|
raise Exception("chooser process failed with exit code {}".format(exit_code))
|
||||||
|
|
||||||
chosen_index = int(chooser_process.stdout.read().strip().split()[0])
|
chosen_index = int(chooser_process.stdout.read().strip().split()[0])
|
||||||
return chosen_index
|
return chosen_index
|
||||||
|
|
||||||
|
|
||||||
def send_notification(title: str, message: str, url: str = None) -> None:
|
def send_notification(title: str, message: str, url: str = None) -> None:
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
process_args = [
|
process_args = [
|
||||||
"terminal-notifier",
|
"terminal-notifier",
|
||||||
"-title",
|
"-title",
|
||||||
title,
|
title,
|
||||||
"-message",
|
"-message",
|
||||||
message,
|
message,
|
||||||
"-open",
|
"-open",
|
||||||
]
|
]
|
||||||
if url is not None:
|
if url is not None:
|
||||||
process_args += [url]
|
process_args += [url]
|
||||||
elif os.name == "posix":
|
elif os.name == "posix":
|
||||||
process_args = [
|
process_args = [
|
||||||
"notify-send",
|
"notify-send",
|
||||||
"--icon=utilities-terminal",
|
"--icon=utilities-terminal",
|
||||||
"--expire-time=3000",
|
"--expire-time=3000",
|
||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
platform_not_supported_error()
|
platform_not_supported_error()
|
||||||
|
|
||||||
subprocess.run(process_args, check=True)
|
subprocess.run(process_args, check=True)
|
||||||
|
|
||||||
|
|
||||||
def set_clipboard(text: str) -> None:
|
def set_clipboard(text: str) -> None:
|
||||||
# TODO: somehow merge program selection with the logic in `zsh/functions.zsh`
|
# TODO: somehow merge program selection with the logic in `zsh/functions.zsh`
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
process_args = ["pbcopy"]
|
process_args = ["pbcopy"]
|
||||||
elif os.name == "posix":
|
elif os.name == "posix":
|
||||||
process_args = ["xsel", "--clipboard", "--input"]
|
process_args = ["xsel", "--clipboard", "--input"]
|
||||||
# process_args = ["xclip", "-in", "-selection", "clipboard"]
|
# process_args = ["xclip", "-in", "-selection", "clipboard"]
|
||||||
else:
|
else:
|
||||||
platform_not_supported_error()
|
platform_not_supported_error()
|
||||||
|
|
||||||
subprocess.run(process_args, input=text.encode(), check=True)
|
subprocess.run(process_args, input=text.encode(), check=True)
|
||||||
|
|
|
@ -9,58 +9,58 @@ from typing import Any, IO
|
||||||
|
|
||||||
|
|
||||||
def read_bool(buf: IO[bytes]) -> bool:
|
def read_bool(buf: IO[bytes]) -> bool:
|
||||||
return buf.read(1)[0] == 1
|
return buf.read(1)[0] == 1
|
||||||
|
|
||||||
|
|
||||||
def read_number(buf: IO[bytes]) -> float:
|
def read_number(buf: IO[bytes]) -> float:
|
||||||
return struct.unpack("<d", buf.read(8))[0]
|
return struct.unpack("<d", buf.read(8))[0]
|
||||||
|
|
||||||
|
|
||||||
def _read_length(buf: IO[bytes]) -> int:
|
def _read_length(buf: IO[bytes]) -> int:
|
||||||
return struct.unpack("<I", buf.read(4))[0]
|
return struct.unpack("<I", buf.read(4))[0]
|
||||||
|
|
||||||
|
|
||||||
def read_string(buf: IO[bytes]) -> str:
|
def read_string(buf: IO[bytes]) -> str:
|
||||||
is_empty = read_bool(buf)
|
is_empty = read_bool(buf)
|
||||||
if is_empty:
|
if is_empty:
|
||||||
return ""
|
return ""
|
||||||
len_ = buf.read(1)[0]
|
len_ = buf.read(1)[0]
|
||||||
if len_ == 0xFF:
|
if len_ == 0xFF:
|
||||||
len_ = _read_length(buf)
|
len_ = _read_length(buf)
|
||||||
return buf.read(len_).decode("utf8")
|
return buf.read(len_).decode("utf8")
|
||||||
|
|
||||||
|
|
||||||
def read_dictionary(buf: IO[bytes]) -> dict[str, Any]:
|
def read_dictionary(buf: IO[bytes]) -> dict[str, Any]:
|
||||||
len_ = _read_length(buf)
|
len_ = _read_length(buf)
|
||||||
value: dict[str, Any] = {}
|
value: dict[str, Any] = {}
|
||||||
for _ in range(len_):
|
for _ in range(len_):
|
||||||
key = read_string(buf)
|
key = read_string(buf)
|
||||||
value[key] = read(buf)
|
value[key] = read(buf)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def read_list(buf: IO[bytes]) -> list[Any]:
|
def read_list(buf: IO[bytes]) -> list[Any]:
|
||||||
len_ = _read_length(buf)
|
len_ = _read_length(buf)
|
||||||
value: list[Any] = []
|
value: list[Any] = []
|
||||||
for _ in range(len_):
|
for _ in range(len_):
|
||||||
read_string(buf)
|
read_string(buf)
|
||||||
value.append(read(buf))
|
value.append(read(buf))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def read(buf: IO[bytes]) -> Any:
|
def read(buf: IO[bytes]) -> Any:
|
||||||
type_, _any_type_flag = buf.read(2)
|
type_, _any_type_flag = buf.read(2)
|
||||||
if type_ == 0:
|
if type_ == 0:
|
||||||
return None
|
return None
|
||||||
elif type_ == 1:
|
elif type_ == 1:
|
||||||
return read_bool(buf)
|
return read_bool(buf)
|
||||||
elif type_ == 2:
|
elif type_ == 2:
|
||||||
return read_number(buf)
|
return read_number(buf)
|
||||||
elif type_ == 3:
|
elif type_ == 3:
|
||||||
return read_string(buf)
|
return read_string(buf)
|
||||||
elif type_ == 4:
|
elif type_ == 4:
|
||||||
return read_list(buf)
|
return read_list(buf)
|
||||||
elif type_ == 5:
|
elif type_ == 5:
|
||||||
return read_dictionary(buf)
|
return read_dictionary(buf)
|
||||||
else:
|
else:
|
||||||
raise Exception("unknown property tree type 0x{:02x}".format(type_))
|
raise Exception("unknown property tree type 0x{:02x}".format(type_))
|
||||||
|
|
|
@ -3,29 +3,29 @@ from fractions import Fraction
|
||||||
|
|
||||||
|
|
||||||
def factors(n):
|
def factors(n):
|
||||||
result = set()
|
result = set()
|
||||||
for i in range(1, int(sqrt(n)) + 1):
|
for i in range(1, int(sqrt(n)) + 1):
|
||||||
if n % i == 0:
|
if n % i == 0:
|
||||||
result.add(i)
|
result.add(i)
|
||||||
result.add(n // i)
|
result.add(n // i)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def solve_quadratic(a, b, c):
|
def solve_quadratic(a, b, c):
|
||||||
if a == 0:
|
if a == 0:
|
||||||
raise Exception("not a quadratic equation")
|
raise Exception("not a quadratic equation")
|
||||||
|
else:
|
||||||
|
d = b ** 2 - 4 * a * c
|
||||||
|
print("D = " + str(d))
|
||||||
|
if d < 0:
|
||||||
|
print("no solutions")
|
||||||
|
elif d > 0:
|
||||||
|
sd = sqrt(d)
|
||||||
|
print("sqrt(D) = " + str(sd))
|
||||||
|
print("x1 = " + str((-b + sd) / (2 * a)))
|
||||||
|
print("x2 = " + str((-b - sd) / (2 * a)))
|
||||||
else:
|
else:
|
||||||
d = b ** 2 - 4 * a * c
|
print("x = " + str(-b / (2 * a)))
|
||||||
print("D = " + str(d))
|
|
||||||
if d < 0:
|
|
||||||
print("no solutions")
|
|
||||||
elif d > 0:
|
|
||||||
sd = sqrt(d)
|
|
||||||
print("sqrt(D) = " + str(sd))
|
|
||||||
print("x1 = " + str((-b + sd) / (2 * a)))
|
|
||||||
print("x2 = " + str((-b - sd) / (2 * a)))
|
|
||||||
else:
|
|
||||||
print("x = " + str(-b / (2 * a)))
|
|
||||||
|
|
||||||
|
|
||||||
print("loaded Python calculator")
|
print("loaded Python calculator")
|
||||||
|
|
|
@ -1,21 +1,22 @@
|
||||||
from colorama import Fore, Style, ansi
|
from colorama import Fore, Style, ansi
|
||||||
|
|
||||||
|
|
||||||
COLORS = [ansi.code_to_chars(30 + color_index) for color_index in range(0, 8)]
|
COLORS = [ansi.code_to_chars(30 + color_index) for color_index in range(0, 8)]
|
||||||
|
|
||||||
|
|
||||||
def colored(string, *colors):
|
def colored(string, *colors):
|
||||||
return "".join(colors + (string, Style.RESET_ALL))
|
return "".join(colors + (string, Style.RESET_ALL))
|
||||||
|
|
||||||
|
|
||||||
def bright_colored(string, *colors):
|
def bright_colored(string, *colors):
|
||||||
return "".join(colors + (Style.BRIGHT, string, Style.RESET_ALL))
|
return "".join(colors + (Style.BRIGHT, string, Style.RESET_ALL))
|
||||||
|
|
||||||
|
|
||||||
def colorize_percent(percent, warning, critical, inverse=False):
|
def colorize_percent(percent, warning, critical, inverse=False):
|
||||||
COLORS = [Fore.GREEN, Fore.YELLOW, Fore.RED]
|
COLORS = [Fore.GREEN, Fore.YELLOW, Fore.RED]
|
||||||
|
|
||||||
color_index = 0 if percent < warning else 1 if percent < critical else 2
|
color_index = 0 if percent < warning else 1 if percent < critical else 2
|
||||||
if inverse:
|
if inverse:
|
||||||
color_index = 2 - color_index
|
color_index = 2 - color_index
|
||||||
|
|
||||||
return colored("%.2f%%" % percent, COLORS[color_index])
|
return colored("%.2f%%" % percent, COLORS[color_index])
|
||||||
|
|
|
@ -1,34 +1,34 @@
|
||||||
def humanize_timedelta(timedelta):
|
def humanize_timedelta(timedelta):
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
days = timedelta.days
|
days = timedelta.days
|
||||||
mm, ss = divmod(timedelta.seconds, 60)
|
mm, ss = divmod(timedelta.seconds, 60)
|
||||||
hh, mm = divmod(mm, 60)
|
hh, mm = divmod(mm, 60)
|
||||||
|
|
||||||
def plural(n):
|
def plural(n):
|
||||||
return n, "s" if abs(n) != 1 else ""
|
return n, "s" if abs(n) != 1 else ""
|
||||||
|
|
||||||
if days > 0:
|
if days > 0:
|
||||||
result.append("%d day%s" % plural(days))
|
result.append("%d day%s" % plural(days))
|
||||||
if hh > 0 or result:
|
if hh > 0 or result:
|
||||||
result.append("%d hour%s" % plural(hh))
|
result.append("%d hour%s" % plural(hh))
|
||||||
if mm > 0 or result:
|
if mm > 0 or result:
|
||||||
result.append("%d min%s" % plural(mm))
|
result.append("%d min%s" % plural(mm))
|
||||||
if len(result) <= 1:
|
if len(result) <= 1:
|
||||||
result.append("%d sec%s" % plural(ss))
|
result.append("%d sec%s" % plural(ss))
|
||||||
|
|
||||||
return ", ".join(result)
|
return ", ".join(result)
|
||||||
|
|
||||||
|
|
||||||
def humanize_bytes(bytes):
|
def humanize_bytes(bytes):
|
||||||
units = ["B", "kB", "MB", "GB"]
|
units = ["B", "kB", "MB", "GB"]
|
||||||
|
|
||||||
factor = 1
|
factor = 1
|
||||||
unit = ""
|
unit = ""
|
||||||
for unit in units:
|
for unit in units:
|
||||||
next_factor = factor << 10
|
next_factor = factor << 10
|
||||||
if bytes < next_factor:
|
if bytes < next_factor:
|
||||||
break
|
break
|
||||||
factor = next_factor
|
factor = next_factor
|
||||||
|
|
||||||
return "%.2f %s" % (float(bytes) / factor, unit)
|
return "%.2f %s" % (float(bytes) / factor, unit)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import re
|
||||||
from colors import COLORS, Style
|
from colors import COLORS, Style
|
||||||
from system_info import get_system_info
|
from system_info import get_system_info
|
||||||
|
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
logo_lines, info_lines = get_system_info()
|
logo_lines, info_lines = get_system_info()
|
||||||
|
@ -12,24 +13,24 @@ logo_line_widths = [len(re.sub(r"{\d}", "", line)) for line in logo_lines]
|
||||||
logo_width = max(logo_line_widths)
|
logo_width = max(logo_line_widths)
|
||||||
|
|
||||||
for line_index in range(0, max(len(logo_lines), len(info_lines))):
|
for line_index in range(0, max(len(logo_lines), len(info_lines))):
|
||||||
line = ""
|
line = ""
|
||||||
|
|
||||||
logo_line_width = 0
|
logo_line_width = 0
|
||||||
|
|
||||||
if line_index < len(logo_lines):
|
if line_index < len(logo_lines):
|
||||||
logo_line = logo_lines[line_index]
|
logo_line = logo_lines[line_index]
|
||||||
logo_line_width = logo_line_widths[line_index]
|
logo_line_width = logo_line_widths[line_index]
|
||||||
|
|
||||||
line += Style.BRIGHT
|
line += Style.BRIGHT
|
||||||
line += logo_line.format(*COLORS)
|
line += logo_line.format(*COLORS)
|
||||||
line += Style.RESET_ALL
|
line += Style.RESET_ALL
|
||||||
|
|
||||||
line += " " * (logo_width - logo_line_width + 3)
|
line += " " * (logo_width - logo_line_width + 3)
|
||||||
|
|
||||||
if line_index < len(info_lines):
|
if line_index < len(info_lines):
|
||||||
info_line = info_lines[line_index]
|
info_line = info_lines[line_index]
|
||||||
line += info_line
|
line += info_line
|
||||||
|
|
||||||
print(line)
|
print(line)
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
|
|
|
@ -11,206 +11,200 @@ from humanize import humanize_bytes, humanize_timedelta
|
||||||
|
|
||||||
|
|
||||||
def get_system_info():
|
def get_system_info():
|
||||||
info_lines = []
|
info_lines = []
|
||||||
|
|
||||||
def info(name, value, *format_args):
|
def info(name, value, *format_args):
|
||||||
line = bright_colored(name + ":", Fore.YELLOW) + " " + value
|
line = bright_colored(name + ":", Fore.YELLOW) + " " + value
|
||||||
if format_args:
|
if format_args:
|
||||||
line = line % format_args
|
line = line % format_args
|
||||||
info_lines.append(line)
|
info_lines.append(line)
|
||||||
|
|
||||||
username = getuser()
|
username = getuser()
|
||||||
hostname = _get_hostname()
|
hostname = _get_hostname()
|
||||||
|
|
||||||
info_lines.append(
|
info_lines.append(bright_colored(username, Fore.BLUE) + "@" + bright_colored(hostname, Fore.RED))
|
||||||
bright_colored(username, Fore.BLUE) + "@" + bright_colored(hostname, Fore.RED)
|
info_lines.append("")
|
||||||
)
|
|
||||||
info_lines.append("")
|
|
||||||
|
|
||||||
distro_id, distro_name, distro_version, distro_codename = _get_distro_info()
|
distro_id, distro_name, distro_version, distro_codename = _get_distro_info()
|
||||||
info("OS", " ".join([distro_name, distro_version, distro_codename]))
|
info("OS", " ".join([distro_name, distro_version, distro_codename]))
|
||||||
|
|
||||||
logo_path = os.path.join(os.path.dirname(__file__), "logos", distro_id)
|
logo_path = os.path.join(os.path.dirname(__file__), "logos", distro_id)
|
||||||
with open(logo_path) as logo_file:
|
with open(logo_path) as logo_file:
|
||||||
logo_lines = logo_file.read().splitlines()
|
logo_lines = logo_file.read().splitlines()
|
||||||
|
|
||||||
info("Kernel", "%s %s", platform.system(), platform.release())
|
info("Kernel", "%s %s", platform.system(), platform.release())
|
||||||
|
|
||||||
info("Uptime", humanize_timedelta(_get_uptime()))
|
info("Uptime", humanize_timedelta(_get_uptime()))
|
||||||
|
|
||||||
users_info = _get_users()
|
users_info = _get_users()
|
||||||
if users_info:
|
if users_info:
|
||||||
info("Users", users_info)
|
info("Users", users_info)
|
||||||
|
|
||||||
shell = _get_shell()
|
shell = _get_shell()
|
||||||
if shell is not None:
|
if shell is not None:
|
||||||
info("Shell", shell)
|
info("Shell", shell)
|
||||||
|
|
||||||
info_lines.append("")
|
info_lines.append("")
|
||||||
|
|
||||||
cpu_usage_info = _get_cpu_usage()
|
cpu_usage_info = _get_cpu_usage()
|
||||||
if cpu_usage_info is not None:
|
if cpu_usage_info is not None:
|
||||||
info("CPU Usage", "%s", cpu_usage_info)
|
info("CPU Usage", "%s", cpu_usage_info)
|
||||||
info("Memory", "%s / %s (%s)", *_get_memory())
|
info("Memory", "%s / %s (%s)", *_get_memory())
|
||||||
|
|
||||||
for disk_info in _get_disks():
|
for disk_info in _get_disks():
|
||||||
info("Disk (%s)", "%s / %s (%s)", *disk_info)
|
info("Disk (%s)", "%s / %s (%s)", *disk_info)
|
||||||
|
|
||||||
battery_info = _get_battery()
|
battery_info = _get_battery()
|
||||||
if battery_info is not None:
|
if battery_info is not None:
|
||||||
info("Battery", "%s (%s)", *battery_info)
|
info("Battery", "%s (%s)", *battery_info)
|
||||||
|
|
||||||
info_lines.append("")
|
info_lines.append("")
|
||||||
|
|
||||||
for local_ip_address in _get_local_ipv4_addresses():
|
for local_ip_address in _get_local_ipv4_addresses():
|
||||||
info("Local IPv4 Address (%s)", "%s", *local_ip_address)
|
info("Local IPv4 Address (%s)", "%s", *local_ip_address)
|
||||||
|
|
||||||
return logo_lines, info_lines
|
return logo_lines, info_lines
|
||||||
|
|
||||||
|
|
||||||
def _get_hostname():
|
def _get_hostname():
|
||||||
hostname = socket.gethostname()
|
hostname = socket.gethostname()
|
||||||
return hostname
|
return hostname
|
||||||
|
|
||||||
|
|
||||||
def _get_uptime():
|
def _get_uptime():
|
||||||
return datetime.now() - datetime.fromtimestamp(psutil.boot_time())
|
return datetime.now() - datetime.fromtimestamp(psutil.boot_time())
|
||||||
|
|
||||||
|
|
||||||
def _get_users():
|
def _get_users():
|
||||||
users = {}
|
users = {}
|
||||||
|
|
||||||
for user in psutil.users():
|
for user in psutil.users():
|
||||||
name = user.name
|
name = user.name
|
||||||
terminal = user.terminal
|
terminal = user.terminal
|
||||||
if name in users:
|
if name in users:
|
||||||
users[name].append(terminal)
|
users[name].append(terminal)
|
||||||
else:
|
else:
|
||||||
users[name] = [terminal]
|
users[name] = [terminal]
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for name in users:
|
for name in users:
|
||||||
terminals = users[name]
|
terminals = users[name]
|
||||||
|
|
||||||
colored_name = bright_colored(name, Fore.BLUE)
|
colored_name = bright_colored(name, Fore.BLUE)
|
||||||
colored_terminals = [
|
colored_terminals = [colored(str(term), Style.DIM, Fore.WHITE) for term in terminals]
|
||||||
colored(str(term), Style.DIM, Fore.WHITE) for term in terminals
|
|
||||||
]
|
|
||||||
|
|
||||||
terminals_str = ", ".join(colored_terminals)
|
terminals_str = ", ".join(colored_terminals)
|
||||||
if len(colored_terminals) > 1:
|
if len(colored_terminals) > 1:
|
||||||
terminals_str = "(%s)" % terminals_str
|
terminals_str = "(%s)" % terminals_str
|
||||||
result.append(colored_name + "@" + terminals_str)
|
result.append(colored_name + "@" + terminals_str)
|
||||||
|
|
||||||
return ", ".join(result)
|
return ", ".join(result)
|
||||||
|
|
||||||
|
|
||||||
def _get_shell():
|
def _get_shell():
|
||||||
return os.environ.get("SHELL")
|
return os.environ.get("SHELL")
|
||||||
|
|
||||||
|
|
||||||
def _get_cpu_usage():
|
def _get_cpu_usage():
|
||||||
try:
|
try:
|
||||||
percent = psutil.cpu_percent()
|
percent = psutil.cpu_percent()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Error in _get_cpu_usage:", e)
|
print("Error in _get_cpu_usage:", e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return colorize_percent(percent, warning=60, critical=80)
|
return colorize_percent(percent, warning=60, critical=80)
|
||||||
|
|
||||||
|
|
||||||
def _get_memory():
|
def _get_memory():
|
||||||
memory = psutil.virtual_memory()
|
memory = psutil.virtual_memory()
|
||||||
return (
|
return (
|
||||||
humanize_bytes(memory.used),
|
humanize_bytes(memory.used),
|
||||||
humanize_bytes(memory.total),
|
humanize_bytes(memory.total),
|
||||||
colorize_percent(memory.percent, warning=60, critical=80),
|
colorize_percent(memory.percent, warning=60, critical=80),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _get_disks():
|
def _get_disks():
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for disk in psutil.disk_partitions(all=False):
|
for disk in psutil.disk_partitions(all=False):
|
||||||
if psutil.WINDOWS and ("cdrom" in disk.opts or disk.fstype == ""):
|
if psutil.WINDOWS and ("cdrom" in disk.opts or disk.fstype == ""):
|
||||||
# skip cd-rom drives with no disk in it on Windows; they may raise
|
# skip cd-rom drives with no disk in it on Windows; they may raise
|
||||||
# ENOENT, pop-up a Windows GUI error for a non-ready partition or
|
# ENOENT, pop-up a Windows GUI error for a non-ready partition or
|
||||||
# just hang
|
# just hang
|
||||||
continue
|
continue
|
||||||
|
|
||||||
usage = psutil.disk_usage(disk.mountpoint)
|
usage = psutil.disk_usage(disk.mountpoint)
|
||||||
result.append(
|
result.append((
|
||||||
(
|
disk.mountpoint,
|
||||||
disk.mountpoint,
|
humanize_bytes(usage.used),
|
||||||
humanize_bytes(usage.used),
|
humanize_bytes(usage.total),
|
||||||
humanize_bytes(usage.total),
|
colorize_percent(usage.percent, warning=70, critical=85),
|
||||||
colorize_percent(usage.percent, warning=70, critical=85),
|
))
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def _get_battery():
|
def _get_battery():
|
||||||
if not hasattr(psutil, "sensors_battery"):
|
if not hasattr(psutil, "sensors_battery"):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
battery = psutil.sensors_battery()
|
battery = psutil.sensors_battery()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Error in _get_battery:", e)
|
print("Error in _get_battery:", e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if battery is None:
|
if battery is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
percent = battery.percent
|
percent = battery.percent
|
||||||
if battery.power_plugged:
|
if battery.power_plugged:
|
||||||
status = "charging" if percent < 100 else "fully charged"
|
status = "charging" if percent < 100 else "fully charged"
|
||||||
else:
|
else:
|
||||||
status = "%s left" % humanize_timedelta(timedelta(seconds=battery.secsleft))
|
status = "%s left" % humanize_timedelta(timedelta(seconds=battery.secsleft))
|
||||||
return colorize_percent(percent, critical=10, warning=20, inverse=True), status
|
return colorize_percent(percent, critical=10, warning=20, inverse=True), status
|
||||||
|
|
||||||
|
|
||||||
def _get_local_ipv4_addresses():
|
def _get_local_ipv4_addresses():
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for interface, addresses in psutil.net_if_addrs().items():
|
for interface, addresses in psutil.net_if_addrs().items():
|
||||||
for address in addresses:
|
for address in addresses:
|
||||||
if address.family != socket.AF_INET:
|
if address.family != socket.AF_INET:
|
||||||
# allow only IPv4 addresses (skip IPv6 and MAC, for example)
|
# allow only IPv4 addresses (skip IPv6 and MAC, for example)
|
||||||
continue
|
continue
|
||||||
if interface.startswith("lo"):
|
if interface.startswith("lo"):
|
||||||
# skip loopback interfaces
|
# skip loopback interfaces
|
||||||
continue
|
continue
|
||||||
|
|
||||||
result.append((interface, address.address))
|
result.append((interface, address.address))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def _get_distro_info():
|
def _get_distro_info():
|
||||||
if psutil.WINDOWS:
|
if psutil.WINDOWS:
|
||||||
return "windows", platform.system(), platform.release(), ""
|
return "windows", platform.system(), platform.release(), ""
|
||||||
elif psutil.OSX:
|
elif psutil.OSX:
|
||||||
import plistlib
|
import plistlib
|
||||||
|
|
||||||
with open("/System/Library/CoreServices/SystemVersion.plist", "rb") as f:
|
with open("/System/Library/CoreServices/SystemVersion.plist", "rb") as f:
|
||||||
sw_vers = plistlib.load(f)
|
sw_vers = plistlib.load(f)
|
||||||
return "mac", sw_vers["ProductName"], sw_vers["ProductVersion"], ""
|
return "mac", sw_vers["ProductName"], sw_vers["ProductVersion"], ""
|
||||||
elif _is_android():
|
elif _is_android():
|
||||||
from subprocess import check_output
|
from subprocess import check_output
|
||||||
|
|
||||||
android_version = check_output(["getprop", "ro.build.version.release"])
|
android_version = check_output(["getprop", "ro.build.version.release"])
|
||||||
return "android", "Android", android_version.decode().strip(), ""
|
return "android", "Android", android_version.decode().strip(), ""
|
||||||
elif psutil.LINUX:
|
elif psutil.LINUX:
|
||||||
import distro
|
import distro
|
||||||
|
|
||||||
return distro.id(), distro.name(), distro.version(), distro.codename()
|
return distro.id(), distro.name(), distro.version(), distro.codename()
|
||||||
|
|
||||||
raise NotImplementedError("unsupported OS")
|
raise NotImplementedError("unsupported OS")
|
||||||
|
|
||||||
|
|
||||||
def _is_android():
|
def _is_android():
|
||||||
return os.path.isdir("/system/app") and os.path.isdir("/system/priv-app")
|
return os.path.isdir("/system/app") and os.path.isdir("/system/priv-app")
|
||||||
|
|
|
@ -9,88 +9,76 @@ from typing import Any, Generator, Optional, Union
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
|
||||||
|
|
||||||
sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "script-resources"))
|
sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "script-resources"))
|
||||||
import common_script_utils
|
import common_script_utils
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_REGISTRY_DUMP_URL = "https://stronghold.crosscode.ru/~ccbot/emote-registry.json"
|
DEFAULT_REGISTRY_DUMP_URL = "https://stronghold.crosscode.ru/~ccbot/emote-registry.json"
|
||||||
|
|
||||||
|
|
||||||
if os.name == "posix":
|
if os.name == "posix":
|
||||||
config_path: Path = (
|
config_path: Path = (common_script_utils.DOTFILES_CONFIG_DIR / "copy-crosscode-emoji-url.ini")
|
||||||
common_script_utils.DOTFILES_CONFIG_DIR / "copy-crosscode-emoji-url.ini"
|
default_registry_dump_file: Path = (common_script_utils.DOTFILES_CACHE_DIR / "dotfiles")
|
||||||
)
|
|
||||||
default_registry_dump_file: Path = (
|
|
||||||
common_script_utils.DOTFILES_CACHE_DIR / "dotfiles"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
common_script_utils.platform_not_supported_error()
|
common_script_utils.platform_not_supported_error()
|
||||||
config = ConfigParser(interpolation=None)
|
config = ConfigParser(interpolation=None)
|
||||||
config.read(config_path)
|
config.read(config_path)
|
||||||
|
|
||||||
|
|
||||||
emotes: list[dict[str, Any]] = []
|
emotes: list[dict[str, Any]] = []
|
||||||
|
|
||||||
|
|
||||||
def emote_downloader_and_iterator() -> Generator[str, None, None]:
|
def emote_downloader_and_iterator() -> Generator[str, None, None]:
|
||||||
global emotes
|
global emotes
|
||||||
|
|
||||||
registry_dump_file: Optional[Union[str, Path]] = config.get(
|
registry_dump_file: Optional[Union[
|
||||||
"default", "ccbot_emote_registry_dump_file", fallback=None
|
str, Path]] = config.get("default", "ccbot_emote_registry_dump_file", fallback=None)
|
||||||
)
|
if registry_dump_file is not None:
|
||||||
if registry_dump_file is not None:
|
registry_dump_file = os.path.expanduser(registry_dump_file)
|
||||||
registry_dump_file = os.path.expanduser(registry_dump_file)
|
else:
|
||||||
else:
|
registry_dump_file = default_registry_dump_file
|
||||||
registry_dump_file = default_registry_dump_file
|
|
||||||
|
|
||||||
registry_dump_url = config.get(
|
registry_dump_url = config.get(
|
||||||
"default", "ccbot_emote_registry_dump_url", fallback=DEFAULT_REGISTRY_DUMP_URL
|
"default", "ccbot_emote_registry_dump_url", fallback=DEFAULT_REGISTRY_DUMP_URL
|
||||||
)
|
)
|
||||||
|
|
||||||
emote_registry_data: dict[str, Any]
|
emote_registry_data: dict[str, Any]
|
||||||
try:
|
try:
|
||||||
with open(registry_dump_file, "r") as f:
|
with open(registry_dump_file, "r") as f:
|
||||||
emote_registry_data = json.load(f)
|
emote_registry_data = json.load(f)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
with urllib.request.urlopen(registry_dump_url, timeout=10) as response:
|
with urllib.request.urlopen(registry_dump_url, timeout=10) as response:
|
||||||
emote_registry_data = json.load(response)
|
emote_registry_data = json.load(response)
|
||||||
|
|
||||||
assert emote_registry_data["version"] == 1
|
assert emote_registry_data["version"] == 1
|
||||||
|
|
||||||
emotes = [emote for emote in emote_registry_data["list"]
|
emotes = [emote for emote in emote_registry_data["list"]]
|
||||||
# if emote["safe"]
|
|
||||||
]
|
|
||||||
|
|
||||||
for emote in emotes:
|
for emote in emotes:
|
||||||
yield "{emote[ref]} [{emote[guild_name]}]".format(emote=emote)
|
yield "{emote[ref]} [{emote[guild_name]}]".format(emote=emote)
|
||||||
|
|
||||||
|
|
||||||
chosen_index = common_script_utils.run_chooser(
|
chosen_index = common_script_utils.run_chooser(
|
||||||
emote_downloader_and_iterator(), prompt="emote", async_read=True
|
emote_downloader_and_iterator(), prompt="emote", async_read=True
|
||||||
)
|
)
|
||||||
if chosen_index >= 0:
|
if chosen_index >= 0:
|
||||||
chosen_emote = emotes[chosen_index]
|
chosen_emote = emotes[chosen_index]
|
||||||
|
|
||||||
emote_url: urllib.parse.ParseResult = urllib.parse.urlparse(chosen_emote["url"])
|
emote_url: urllib.parse.ParseResult = urllib.parse.urlparse(chosen_emote["url"])
|
||||||
emote_url_query: dict[str, list[str]] = urllib.parse.parse_qs(emote_url.query)
|
emote_url_query: dict[str, list[str]] = urllib.parse.parse_qs(emote_url.query)
|
||||||
|
|
||||||
if config.getboolean("default", "add_emote_name_to_url", fallback=False):
|
if config.getboolean("default", "add_emote_name_to_url", fallback=False):
|
||||||
emote_url_query["name"] = [chosen_emote["name"]]
|
emote_url_query["name"] = [chosen_emote["name"]]
|
||||||
|
|
||||||
default_emote_image_size = config.getint(
|
default_emote_image_size = config.getint("default", "default_emote_image_size", fallback=None)
|
||||||
"default", "default_emote_image_size", fallback=None
|
if default_emote_image_size is not None:
|
||||||
)
|
emote_url_query["size"] = [str(default_emote_image_size)]
|
||||||
if default_emote_image_size is not None:
|
|
||||||
emote_url_query["size"] = [str(default_emote_image_size)]
|
|
||||||
|
|
||||||
emote_url_query_str = urllib.parse.urlencode(emote_url_query, doseq=True)
|
emote_url_query_str = urllib.parse.urlencode(emote_url_query, doseq=True)
|
||||||
emote_url_str = urllib.parse.urlunparse(
|
emote_url_str = urllib.parse.urlunparse(emote_url._replace(query=emote_url_query_str))
|
||||||
emote_url._replace(query=emote_url_query_str)
|
|
||||||
)
|
|
||||||
|
|
||||||
common_script_utils.set_clipboard(emote_url_str)
|
common_script_utils.set_clipboard(emote_url_str)
|
||||||
|
|
||||||
common_script_utils.send_notification(
|
common_script_utils.send_notification(
|
||||||
os.path.basename(__file__),
|
os.path.basename(__file__),
|
||||||
"copied URL of {} to clipboard!".format(chosen_emote["ref"]),
|
"copied URL of {} to clipboard!".format(chosen_emote["ref"]),
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,17 +6,16 @@ import sys
|
||||||
import colorama
|
import colorama
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
DISCORD_EPOCH = 1420070400000 # milliseconds
|
DISCORD_EPOCH = 1420070400000 # milliseconds
|
||||||
|
|
||||||
user_snowflake = int(sys.argv[1])
|
user_snowflake = int(sys.argv[1])
|
||||||
|
|
||||||
|
|
||||||
def print_field(name, value):
|
def print_field(name, value):
|
||||||
print(
|
print(
|
||||||
"{}{}:{} {}".format(
|
"{}{}:{} {}".format(colorama.Style.BRIGHT, name.rjust(21), colorama.Style.RESET_ALL, value)
|
||||||
colorama.Style.BRIGHT, name.rjust(21), colorama.Style.RESET_ALL, value
|
)
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
creation_time = (user_snowflake >> 22) + DISCORD_EPOCH
|
creation_time = (user_snowflake >> 22) + DISCORD_EPOCH
|
||||||
|
@ -25,11 +24,11 @@ internal_process_id = (user_snowflake >> 12) & 0x1F
|
||||||
increment = user_snowflake & 0xFFF
|
increment = user_snowflake & 0xFFF
|
||||||
|
|
||||||
print_field(
|
print_field(
|
||||||
"Created at",
|
"Created at",
|
||||||
"{}.{}".format(
|
"{}.{}".format(
|
||||||
time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(creation_time // 1000)),
|
time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(creation_time // 1000)),
|
||||||
creation_time % 1000,
|
creation_time % 1000,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
print_field("Internal worker ID", internal_worker_id)
|
print_field("Internal worker ID", internal_worker_id)
|
||||||
print_field("Internal process ID", internal_process_id)
|
print_field("Internal process ID", internal_process_id)
|
||||||
|
|
|
@ -4,35 +4,33 @@ import discord
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
guild_id = int(sys.argv[1])
|
guild_id = int(sys.argv[1])
|
||||||
voice_channel_id = int(sys.argv[2])
|
voice_channel_id = int(sys.argv[2])
|
||||||
pulseaudio_device = sys.argv[3]
|
pulseaudio_device = sys.argv[3]
|
||||||
|
|
||||||
with open(os.path.expanduser("~/.config/dotfiles/discord-tools-user-token.txt")) as f:
|
with open(os.path.expanduser("~/.config/dotfiles/discord-tools-user-token.txt")) as f:
|
||||||
bot_token = f.read().strip()
|
bot_token = f.read().strip()
|
||||||
|
|
||||||
|
|
||||||
bot = discord.Client()
|
bot = discord.Client()
|
||||||
|
|
||||||
|
|
||||||
@bot.event
|
@bot.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
print("logged in as {0} ({0.id})".format(bot.user))
|
print("logged in as {0} ({0.id})".format(bot.user))
|
||||||
|
|
||||||
guild: discord.Guild = bot.get_guild(guild_id)
|
guild: discord.Guild = bot.get_guild(guild_id)
|
||||||
if guild is None:
|
if guild is None:
|
||||||
raise Exception("guild not found")
|
raise Exception("guild not found")
|
||||||
voice_channel: discord.VoiceChannel = guild.get_channel(voice_channel_id)
|
voice_channel: discord.VoiceChannel = guild.get_channel(voice_channel_id)
|
||||||
if voice_channel is None:
|
if voice_channel is None:
|
||||||
raise Exception("channel not found")
|
raise Exception("channel not found")
|
||||||
|
|
||||||
voice_client = await voice_channel.connect()
|
voice_client = await voice_channel.connect()
|
||||||
print("connected to {0} ({0.id}) in {1} ({1.id})".format(voice_channel, guild))
|
print("connected to {0} ({0.id}) in {1} ({1.id})".format(voice_channel, guild))
|
||||||
|
|
||||||
source = discord.FFmpegPCMAudio(pulseaudio_device, before_options="-f pulse")
|
source = discord.FFmpegPCMAudio(pulseaudio_device, before_options="-f pulse")
|
||||||
voice_client.play(
|
voice_client.play(source, after=lambda e: print("Player error: %s" % e) if e else None)
|
||||||
source, after=lambda e: print("Player error: %s" % e) if e else None
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
bot.run(bot_token, bot=False)
|
bot.run(bot_token, bot=False)
|
||||||
|
|
|
@ -18,22 +18,21 @@ import typing
|
||||||
DISCORD_EPOCH = 1420070400000 # milliseconds
|
DISCORD_EPOCH = 1420070400000 # milliseconds
|
||||||
# https://discord.com/developers/docs/resources/user#user-object-user-flags
|
# https://discord.com/developers/docs/resources/user#user-object-user-flags
|
||||||
DISCORD_FLAGS = {
|
DISCORD_FLAGS = {
|
||||||
"Discord Employee": 1 << 0,
|
"Discord Employee": 1 << 0,
|
||||||
"Discord Partner": 1 << 1,
|
"Discord Partner": 1 << 1,
|
||||||
"HypeSquad Events": 1 << 2,
|
"HypeSquad Events": 1 << 2,
|
||||||
"Bug Hunter Level 1": 1 << 3,
|
"Bug Hunter Level 1": 1 << 3,
|
||||||
"House of Bravery": 1 << 6,
|
"House of Bravery": 1 << 6,
|
||||||
"House of Brilliance": 1 << 7,
|
"House of Brilliance": 1 << 7,
|
||||||
"House of Balance": 1 << 8,
|
"House of Balance": 1 << 8,
|
||||||
"Early Supporter": 1 << 9,
|
"Early Supporter": 1 << 9,
|
||||||
"Team User": 1 << 10,
|
"Team User": 1 << 10,
|
||||||
"System": 1 << 12,
|
"System": 1 << 12,
|
||||||
"Bug Hunter Level 2": 1 << 14,
|
"Bug Hunter Level 2": 1 << 14,
|
||||||
"Verified Bot": 1 << 16,
|
"Verified Bot": 1 << 16,
|
||||||
"Verified Bot Developer": 1 << 17,
|
"Verified Bot Developer": 1 << 17,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("user_snowflake", type=int)
|
parser.add_argument("user_snowflake", type=int)
|
||||||
parser.add_argument("--bot-token", type=str)
|
parser.add_argument("--bot-token", type=str)
|
||||||
|
@ -45,32 +44,29 @@ user_snowflake = cli_args.user_snowflake
|
||||||
|
|
||||||
bot_token = cli_args.bot_token
|
bot_token = cli_args.bot_token
|
||||||
if bot_token is None:
|
if bot_token is None:
|
||||||
with open(
|
with open(os.path.expanduser("~/.config/dotfiles/discord-tools-bot-token.txt")) as f:
|
||||||
os.path.expanduser("~/.config/dotfiles/discord-tools-bot-token.txt")
|
bot_token = f.read().strip()
|
||||||
) as f:
|
|
||||||
bot_token = f.read().strip()
|
|
||||||
|
|
||||||
image_size = cli_args.image_size
|
image_size = cli_args.image_size
|
||||||
if not (image_size is None or (image_size > 0 and image_size & (image_size - 1)) == 0):
|
if not (image_size is None or (image_size > 0 and image_size & (image_size - 1)) == 0):
|
||||||
parser.error("image_size must be greater than zero and a power of two")
|
parser.error("image_size must be greater than zero and a power of two")
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opener = urllib.request.build_opener()
|
opener = urllib.request.build_opener()
|
||||||
# Don't send the User-Agent header, Discord blocks the default one
|
# Don't send the User-Agent header, Discord blocks the default one
|
||||||
opener.addheaders = []
|
opener.addheaders = []
|
||||||
with opener.open(
|
with opener.open(
|
||||||
urllib.request.Request(
|
urllib.request.Request(
|
||||||
"http://discord.com/api/users/{}".format(user_snowflake),
|
"http://discord.com/api/users/{}".format(user_snowflake),
|
||||||
headers={"Authorization": "Bot {}".format(bot_token)},
|
headers={"Authorization": "Bot {}".format(bot_token)},
|
||||||
),
|
),
|
||||||
timeout=10,
|
timeout=10,
|
||||||
) as response:
|
) as response:
|
||||||
raw_data = json.load(response)
|
raw_data = json.load(response)
|
||||||
except urllib.error.HTTPError as err:
|
except urllib.error.HTTPError as err:
|
||||||
print(err, file=sys.stderr)
|
print(err, file=sys.stderr)
|
||||||
print(err.read(), file=sys.stderr)
|
print(err.read(), file=sys.stderr)
|
||||||
raise err
|
raise err
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
|
@ -78,19 +74,17 @@ data["ID"] = raw_data["id"]
|
||||||
data["Name"] = "{}#{}".format(raw_data["username"], raw_data["discriminator"])
|
data["Name"] = "{}#{}".format(raw_data["username"], raw_data["discriminator"])
|
||||||
|
|
||||||
default_avatar_url = "https://cdn.discordapp.com/embed/avatars/{}.png".format(
|
default_avatar_url = "https://cdn.discordapp.com/embed/avatars/{}.png".format(
|
||||||
int(raw_data["discriminator"], 10) % 5
|
int(raw_data["discriminator"], 10) % 5
|
||||||
)
|
)
|
||||||
avatar_url = (
|
avatar_url = (
|
||||||
"https://cdn.discordapp.com/avatars/{}/{}.{}".format(
|
"https://cdn.discordapp.com/avatars/{}/{}.{}".format(
|
||||||
raw_data["id"],
|
raw_data["id"],
|
||||||
raw_data["avatar"],
|
raw_data["avatar"],
|
||||||
"gif" if raw_data["avatar"].startswith("a_") else "png",
|
"gif" if raw_data["avatar"].startswith("a_") else "png",
|
||||||
)
|
) if raw_data["avatar"] is not None else default_avatar_url
|
||||||
if raw_data["avatar"] is not None
|
|
||||||
else default_avatar_url
|
|
||||||
)
|
)
|
||||||
if image_size is not None:
|
if image_size is not None:
|
||||||
avatar_url += "?size={}".format(image_size)
|
avatar_url += "?size={}".format(image_size)
|
||||||
|
|
||||||
data["Avatar"] = avatar_url
|
data["Avatar"] = avatar_url
|
||||||
data["Default avatar"] = default_avatar_url
|
data["Default avatar"] = default_avatar_url
|
||||||
|
@ -101,38 +95,37 @@ data["System user"] = raw_data.get("system", False)
|
||||||
# https://discord.com/developers/docs/reference#convert-snowflake-to-datetime
|
# https://discord.com/developers/docs/reference#convert-snowflake-to-datetime
|
||||||
snowflake_creation_time = (user_snowflake >> 22) + DISCORD_EPOCH
|
snowflake_creation_time = (user_snowflake >> 22) + DISCORD_EPOCH
|
||||||
data["Created at"] = "{}.{} UTC".format(
|
data["Created at"] = "{}.{} UTC".format(
|
||||||
time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(snowflake_creation_time // 1000)),
|
time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(snowflake_creation_time // 1000)),
|
||||||
snowflake_creation_time % 1000,
|
snowflake_creation_time % 1000,
|
||||||
)
|
)
|
||||||
|
|
||||||
user_flags = raw_data["public_flags"]
|
user_flags = raw_data["public_flags"]
|
||||||
if user_flags == 0:
|
if user_flags == 0:
|
||||||
data["Flags"] = "<none>"
|
data["Flags"] = "<none>"
|
||||||
else:
|
else:
|
||||||
user_flag_names = []
|
user_flag_names = []
|
||||||
for flag_name, bitmask in DISCORD_FLAGS.items():
|
for flag_name, bitmask in DISCORD_FLAGS.items():
|
||||||
if user_flags & bitmask:
|
if user_flags & bitmask:
|
||||||
user_flag_names.append(flag_name)
|
user_flag_names.append(flag_name)
|
||||||
data["Flags"] = ", ".join(user_flag_names)
|
data["Flags"] = ", ".join(user_flag_names)
|
||||||
|
|
||||||
|
|
||||||
if cli_args.get_prop is None:
|
if cli_args.get_prop is None:
|
||||||
max_name_length = max(map(len, data.keys()))
|
max_name_length = max(map(len, data.keys()))
|
||||||
for name, value in data.items():
|
for name, value in data.items():
|
||||||
|
|
||||||
if value is True:
|
if value is True:
|
||||||
value = "yes"
|
value = "yes"
|
||||||
elif value is False:
|
elif value is False:
|
||||||
value = "no"
|
value = "no"
|
||||||
|
|
||||||
print(
|
print(
|
||||||
"{}{:>{}}:{} {}".format(
|
"{}{:>{}}:{} {}".format(
|
||||||
colorama.Style.BRIGHT,
|
colorama.Style.BRIGHT,
|
||||||
name,
|
name,
|
||||||
max_name_length + 1,
|
max_name_length + 1,
|
||||||
colorama.Style.RESET_ALL,
|
colorama.Style.RESET_ALL,
|
||||||
value,
|
value,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
print(data[cli_args.get_prop])
|
print(data[cli_args.get_prop])
|
||||||
|
|
|
@ -10,31 +10,29 @@ from pathlib import Path
|
||||||
import struct
|
import struct
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
|
||||||
sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "script-resources"))
|
sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "script-resources"))
|
||||||
import factorio.property_tree
|
import factorio.property_tree
|
||||||
|
|
||||||
|
|
||||||
with open(Path.home() / ".factorio" / "mods" / "mod-settings.dat", "rb") as f:
|
with open(Path.home() / ".factorio" / "mods" / "mod-settings.dat", "rb") as f:
|
||||||
|
|
||||||
version_main: int
|
version_main: int
|
||||||
version_major: int
|
version_major: int
|
||||||
version_minor: int
|
version_minor: int
|
||||||
version_developer: int
|
version_developer: int
|
||||||
version_main, version_major, version_minor, version_developer = struct.unpack(
|
version_main, version_major, version_minor, version_developer = struct.unpack("<HHHH", f.read(8))
|
||||||
"<HHHH", f.read(8)
|
|
||||||
)
|
|
||||||
|
|
||||||
always_false_flag = factorio.property_tree.read_bool(f)
|
always_false_flag = factorio.property_tree.read_bool(f)
|
||||||
assert not always_false_flag
|
assert not always_false_flag
|
||||||
|
|
||||||
deserialized_data = {
|
deserialized_data = {
|
||||||
"factorio_version": {
|
"factorio_version": {
|
||||||
"main": version_main,
|
"main": version_main,
|
||||||
"major": version_major,
|
"major": version_major,
|
||||||
"minor": version_minor,
|
"minor": version_minor,
|
||||||
"developer": version_developer,
|
"developer": version_developer,
|
||||||
},
|
},
|
||||||
"data": factorio.property_tree.read(f),
|
"data": factorio.property_tree.read(f),
|
||||||
}
|
}
|
||||||
|
|
||||||
print(json.dumps(deserialized_data, indent=2))
|
print(json.dumps(deserialized_data, indent=2))
|
||||||
|
|
|
@ -7,6 +7,7 @@ import json
|
||||||
from sys import stdout
|
from sys import stdout
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
encoding_names = ["utf8", "base16", "base32", "base64", "base85"]
|
encoding_names = ["utf8", "base16", "base32", "base64", "base85"]
|
||||||
parser.add_argument("--encoding", "-e", choices=encoding_names, default="utf8")
|
parser.add_argument("--encoding", "-e", choices=encoding_names, default="utf8")
|
||||||
|
@ -17,33 +18,33 @@ cli_args = parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
def bytes_to_json(b: bytes, encoding: str) -> Union[str, list[int]]:
|
def bytes_to_json(b: bytes, encoding: str) -> Union[str, list[int]]:
|
||||||
if encoding == "utf8":
|
if encoding == "utf8":
|
||||||
try:
|
try:
|
||||||
return b.decode("utf8")
|
return b.decode("utf8")
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
return list(b)
|
return list(b)
|
||||||
elif encoding == "base16":
|
elif encoding == "base16":
|
||||||
return base64.b16encode(b).decode("ascii")
|
return base64.b16encode(b).decode("ascii")
|
||||||
elif encoding == "base32":
|
elif encoding == "base32":
|
||||||
return base64.b32encode(b).decode("ascii")
|
return base64.b32encode(b).decode("ascii")
|
||||||
elif encoding == "base64":
|
elif encoding == "base64":
|
||||||
return base64.b64encode(b).decode("ascii")
|
return base64.b64encode(b).decode("ascii")
|
||||||
elif encoding == "base85":
|
elif encoding == "base85":
|
||||||
return base64.b85encode(b).decode("ascii")
|
return base64.b85encode(b).decode("ascii")
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
|
||||||
key_encoding: str = cli_args.key_encoding or cli_args.encoding
|
key_encoding: str = cli_args.key_encoding or cli_args.encoding
|
||||||
value_encoding: str = cli_args.value_encoding or cli_args.encoding
|
value_encoding: str = cli_args.value_encoding or cli_args.encoding
|
||||||
db = plyvel.DB(str(cli_args.db_path), create_if_missing=False)
|
db = plyvel.DB(str(cli_args.db_path), create_if_missing=False)
|
||||||
with db.iterator() as iterator:
|
with db.iterator() as iterator:
|
||||||
for key, value in iterator:
|
for key, value in iterator:
|
||||||
json.dump(
|
json.dump(
|
||||||
{
|
{
|
||||||
"key": bytes_to_json(key, key_encoding),
|
"key": bytes_to_json(key, key_encoding),
|
||||||
"value": bytes_to_json(value, value_encoding),
|
"value": bytes_to_json(value, value_encoding),
|
||||||
},
|
},
|
||||||
stdout,
|
stdout,
|
||||||
)
|
)
|
||||||
stdout.write("\n")
|
stdout.write("\n")
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/env python3
|
||||||
# Taken from <https://unix.stackexchange.com/a/509417/411555>
|
# Taken from <https://unix.stackexchange.com/a/509417/411555>
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
from gi.repository import Gtk, Gio, GLib # noqa E402
|
from gi.repository import Gtk, Gio, GLib
|
||||||
|
|
||||||
|
|
||||||
rec_mgr = Gtk.RecentManager.get_default()
|
rec_mgr = Gtk.RecentManager.get_default()
|
||||||
for arg in sys.argv[1:]:
|
for arg in sys.argv[1:]:
|
||||||
rec_mgr.add_item(Gio.File.new_for_path(arg).get_uri())
|
rec_mgr.add_item(Gio.File.new_for_path(arg).get_uri())
|
||||||
GLib.idle_add(Gtk.main_quit)
|
GLib.idle_add(Gtk.main_quit)
|
||||||
Gtk.main()
|
Gtk.main()
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
# - The module `skins.citizen.scripts` references search inputs which aren't
|
# - The module `skins.citizen.scripts` references search inputs which aren't
|
||||||
# created by this script.
|
# created by this script.
|
||||||
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import mwclient
|
import mwclient
|
||||||
import json
|
import json
|
||||||
|
@ -51,85 +50,85 @@ LANG = "en"
|
||||||
LANG_TEXT_DIRECTION = "ltr"
|
LANG_TEXT_DIRECTION = "ltr"
|
||||||
|
|
||||||
MODULES_POST_LOAD = {
|
MODULES_POST_LOAD = {
|
||||||
"vector": [
|
"vector": [
|
||||||
"site",
|
"site",
|
||||||
"mediawiki.page.startup",
|
"mediawiki.page.startup",
|
||||||
"mediawiki.page.ready",
|
"mediawiki.page.ready",
|
||||||
"mediawiki.toc",
|
"mediawiki.toc",
|
||||||
# "mediawiki.searchSuggest",
|
# "mediawiki.searchSuggest",
|
||||||
# "mediawiki.page.watch.ajax",
|
# "mediawiki.page.watch.ajax",
|
||||||
"skins.vector.js",
|
"skins.vector.js",
|
||||||
],
|
],
|
||||||
"citizen": [
|
"citizen": [
|
||||||
# "site",
|
# "site",
|
||||||
# "mediawiki.page.startup",
|
# "mediawiki.page.startup",
|
||||||
# "mediawiki.page.ready",
|
# "mediawiki.page.ready",
|
||||||
# "mediawiki.toc",
|
# "mediawiki.toc",
|
||||||
# "skins.citizen.scripts.toc",
|
# "skins.citizen.scripts.toc",
|
||||||
# "skins.citizen.scripts.search",
|
# "skins.citizen.scripts.search",
|
||||||
# "skins.citizen.styles.search",
|
# "skins.citizen.styles.search",
|
||||||
# "skins.citizen.icons.search",
|
# "skins.citizen.icons.search",
|
||||||
# "skins.citizen.scripts",
|
# "skins.citizen.scripts",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULES_POST_LOAD_BLOCKED = {
|
MODULES_POST_LOAD_BLOCKED = {
|
||||||
"citizen": [
|
"citizen": [
|
||||||
"skins.citizen.scripts.toc",
|
"skins.citizen.scripts.toc",
|
||||||
"skins.citizen.scripts.search",
|
"skins.citizen.scripts.search",
|
||||||
"skins.citizen.styles.search",
|
"skins.citizen.styles.search",
|
||||||
"skins.citizen.icons.search",
|
"skins.citizen.icons.search",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULES_PRELOAD_STYLES = {
|
MODULES_PRELOAD_STYLES = {
|
||||||
"vector": [
|
"vector": [
|
||||||
"mediawiki.legacy.commonPrint",
|
"mediawiki.legacy.commonPrint",
|
||||||
"mediawiki.legacy.shared",
|
"mediawiki.legacy.shared",
|
||||||
"mediawiki.skinning.interface",
|
"mediawiki.skinning.interface",
|
||||||
"mediawiki.toc.styles",
|
"mediawiki.toc.styles",
|
||||||
"skins.vector.styles",
|
"skins.vector.styles",
|
||||||
"site.styles",
|
"site.styles",
|
||||||
],
|
],
|
||||||
"citizen": [
|
"citizen": [
|
||||||
# "mediawiki.legacy.commonPrint",
|
# "mediawiki.legacy.commonPrint",
|
||||||
# "mediawiki.legacy.shared",
|
# "mediawiki.legacy.shared",
|
||||||
"mediawiki.skinning.content.externallinks",
|
"mediawiki.skinning.content.externallinks",
|
||||||
# "mediawiki.toc.styles",
|
# "mediawiki.toc.styles",
|
||||||
"skins.citizen.icons",
|
"skins.citizen.icons",
|
||||||
"skins.citizen.styles",
|
"skins.citizen.styles",
|
||||||
"skins.citizen.icons.ca",
|
"skins.citizen.icons.ca",
|
||||||
"skins.citizen.icons.es",
|
"skins.citizen.icons.es",
|
||||||
"skins.citizen.icons.footer",
|
"skins.citizen.icons.footer",
|
||||||
"skins.citizen.icons.n",
|
"skins.citizen.icons.n",
|
||||||
"skins.citizen.icons.pt",
|
"skins.citizen.icons.pt",
|
||||||
"skins.citizen.icons.t",
|
"skins.citizen.icons.t",
|
||||||
"skins.citizen.styles.fonts",
|
"skins.citizen.styles.fonts",
|
||||||
"skins.citizen.styles.toc",
|
"skins.citizen.styles.toc",
|
||||||
"site.styles",
|
"site.styles",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULES_PRELOAD_SCRIPTS = {
|
MODULES_PRELOAD_SCRIPTS = {
|
||||||
"vector": ["startup"],
|
"vector": ["startup"],
|
||||||
"citizen": ["startup"],
|
"citizen": ["startup"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# ported from <https://github.com/wikimedia/mediawiki/blob/c15ded31a6ca79fa65c00d151a7220632ad90b6d/includes/parser/Sanitizer.php#L1205-L1222>
|
# ported from <https://github.com/wikimedia/mediawiki/blob/c15ded31a6ca79fa65c00d151a7220632ad90b6d/includes/parser/Sanitizer.php#L1205-L1222>
|
||||||
def escape_css_class(class_str):
|
def escape_css_class(class_str):
|
||||||
class_str = re.sub(
|
class_str = re.sub(
|
||||||
r"""(^[0-9\-])|[\x00-\x20!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~]|\xA0""",
|
r"""(^[0-9\-])|[\x00-\x20!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~]|\xA0""",
|
||||||
"_",
|
"_",
|
||||||
class_str,
|
class_str,
|
||||||
)
|
)
|
||||||
class_str = re.sub(r"_+", "_", class_str)
|
class_str = re.sub(r"_+", "_", class_str)
|
||||||
class_str = class_str.rstrip("_")
|
class_str = class_str.rstrip("_")
|
||||||
return class_str
|
return class_str
|
||||||
|
|
||||||
|
|
||||||
def json_dumps_compact(data):
|
def json_dumps_compact(data):
|
||||||
return json.dumps(data, indent=None, separators=(",", ":"))
|
return json.dumps(data, indent=None, separators=(",", ":"))
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
@ -137,50 +136,55 @@ parser.add_argument("--site", type=str, required=True)
|
||||||
parser.add_argument("--scheme", type=str, default="https")
|
parser.add_argument("--scheme", type=str, default="https")
|
||||||
parser.add_argument("--skin", type=str, default="vector")
|
parser.add_argument("--skin", type=str, default="vector")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--input", type=str, required=True,
|
"--input",
|
||||||
|
type=str,
|
||||||
|
required=True,
|
||||||
)
|
)
|
||||||
parser.add_argument("--title", type=str)
|
parser.add_argument("--title", type=str)
|
||||||
parser.add_argument("--output", type=str, required=True)
|
parser.add_argument("--output", type=str, required=True)
|
||||||
cli_args = parser.parse_args()
|
cli_args = parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
site = mwclient.Site(cli_args.site, scheme=cli_args.scheme)
|
site = mwclient.Site(cli_args.site, scheme=cli_args.scheme)
|
||||||
|
|
||||||
|
|
||||||
def get_load_script_url(**args):
|
def get_load_script_url(**args):
|
||||||
return "{path}load{ext}?{args}".format(
|
return "{path}load{ext}?{args}".format(
|
||||||
path=site.path,
|
path=site.path,
|
||||||
ext=site.ext,
|
ext=site.ext,
|
||||||
args=urlencode({"lang": LANG, "skin": cli_args.skin, **args}),
|
args=urlencode({
|
||||||
)
|
"lang": LANG,
|
||||||
|
"skin": cli_args.skin,
|
||||||
|
**args
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
with open(cli_args.input, "r") as f:
|
with open(cli_args.input, "r") as f:
|
||||||
wikitext_str = f.read()
|
wikitext_str = f.read()
|
||||||
|
|
||||||
result = site.post(
|
result = site.post(
|
||||||
"parse",
|
"parse",
|
||||||
title=cli_args.title,
|
title=cli_args.title,
|
||||||
text=wikitext_str,
|
text=wikitext_str,
|
||||||
contentmodel="wikitext",
|
contentmodel="wikitext",
|
||||||
prop="text|indicators|displaytitle|modules|jsconfigvars|categorieshtml",
|
prop="text|indicators|displaytitle|modules|jsconfigvars|categorieshtml",
|
||||||
preview=True,
|
preview=True,
|
||||||
pst=True, # pre-save transforms
|
pst=True, # pre-save transforms
|
||||||
sectionpreview=False,
|
sectionpreview=False,
|
||||||
disableeditsection=True, # disables "[edit]" links next to headers
|
disableeditsection=True, # disables "[edit]" links next to headers
|
||||||
useskin=cli_args.skin,
|
useskin=cli_args.skin,
|
||||||
uselang=LANG,
|
uselang=LANG,
|
||||||
)["parse"]
|
)["parse"]
|
||||||
|
|
||||||
|
|
||||||
def get_modules(page_modules, added_modules_dict, blocked_modules_dict={}):
|
def get_modules(page_modules, added_modules_dict, blocked_modules_dict={}):
|
||||||
modules = page_modules + added_modules_dict[cli_args.skin]
|
modules = page_modules + added_modules_dict[cli_args.skin]
|
||||||
for blocked_module in blocked_modules_dict.get(cli_args.skin, []):
|
for blocked_module in blocked_modules_dict.get(cli_args.skin, []):
|
||||||
try:
|
try:
|
||||||
modules.remove(blocked_module)
|
modules.remove(blocked_module)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
return modules
|
return modules
|
||||||
|
|
||||||
|
|
||||||
rendered_html = """\
|
rendered_html = """\
|
||||||
|
@ -240,53 +244,43 @@ rendered_html = """\
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
""".format(
|
""".format(
|
||||||
lang=html.escape(LANG),
|
lang=html.escape(LANG),
|
||||||
text_dir=html.escape(LANG_TEXT_DIRECTION),
|
text_dir=html.escape(LANG_TEXT_DIRECTION),
|
||||||
base_url=html.escape("{}://{}".format(site.scheme, site.host)),
|
base_url=html.escape("{}://{}".format(site.scheme, site.host)),
|
||||||
page_modules_state_json=json_dumps_compact(
|
page_modules_state_json=json_dumps_compact({
|
||||||
{
|
"noscript": "ready",
|
||||||
"noscript": "ready",
|
"user.options": "ready",
|
||||||
"user.options": "ready",
|
"user.tokens": "loading",
|
||||||
"user.tokens": "loading",
|
**{name: "ready" for name in MODULES_PRELOAD_STYLES[cli_args.skin]},
|
||||||
**{name: "ready" for name in MODULES_PRELOAD_STYLES[cli_args.skin]},
|
}),
|
||||||
}
|
page_config_json=json_dumps_compact(result["jsconfigvars"]),
|
||||||
),
|
page_modules_json=json_dumps_compact(
|
||||||
page_config_json=json_dumps_compact(result["jsconfigvars"]),
|
get_modules(result["modules"], MODULES_POST_LOAD, MODULES_POST_LOAD_BLOCKED)
|
||||||
page_modules_json=json_dumps_compact(
|
),
|
||||||
get_modules(result["modules"], MODULES_POST_LOAD, MODULES_POST_LOAD_BLOCKED)
|
style_url=html.escape(
|
||||||
),
|
get_load_script_url(
|
||||||
style_url=html.escape(
|
only="styles",
|
||||||
get_load_script_url(
|
modules="|".join(get_modules(result["modulestyles"], MODULES_PRELOAD_STYLES)),
|
||||||
only="styles",
|
)
|
||||||
modules="|".join(
|
),
|
||||||
get_modules(result["modulestyles"], MODULES_PRELOAD_STYLES)
|
script_url=html.escape(
|
||||||
),
|
get_load_script_url(
|
||||||
)
|
only="scripts",
|
||||||
),
|
modules="|".join(get_modules(result["modulescripts"], MODULES_PRELOAD_SCRIPTS)),
|
||||||
script_url=html.escape(
|
raw="1",
|
||||||
get_load_script_url(
|
)
|
||||||
only="scripts",
|
),
|
||||||
modules="|".join(
|
skin=html.escape(cli_args.skin),
|
||||||
get_modules(result["modulescripts"], MODULES_PRELOAD_SCRIPTS)
|
page_class=html.escape(escape_css_class(result["displaytitle"])),
|
||||||
),
|
title=html.escape(result["displaytitle"]),
|
||||||
raw="1",
|
indicators_html="\n".join([
|
||||||
)
|
'<div id="mw-indicator-{}" class="mw-indicator">{}</div>'.format(
|
||||||
),
|
indicator["name"], indicator["*"]
|
||||||
skin=html.escape(cli_args.skin),
|
) for indicator in result["indicators"]
|
||||||
page_class=html.escape(escape_css_class(result["displaytitle"])),
|
]),
|
||||||
title=html.escape(result["displaytitle"]),
|
content_html=result["text"]["*"],
|
||||||
indicators_html="\n".join(
|
categories_html=result["categorieshtml"]["*"],
|
||||||
[
|
|
||||||
'<div id="mw-indicator-{}" class="mw-indicator">{}</div>'.format(
|
|
||||||
indicator["name"], indicator["*"]
|
|
||||||
)
|
|
||||||
for indicator in result["indicators"]
|
|
||||||
]
|
|
||||||
),
|
|
||||||
content_html=result["text"]["*"],
|
|
||||||
categories_html=result["categorieshtml"]["*"],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
with open(cli_args.output, "w") as f:
|
with open(cli_args.output, "w") as f:
|
||||||
f.write(rendered_html)
|
f.write(rendered_html)
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
import gi
|
import gi
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
from gi.repository import Gtk, Gdk, Pango # noqa: E402
|
from gi.repository import Gtk, Gdk, Pango
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
@ -12,7 +13,6 @@ args = parser.parse_args()
|
||||||
|
|
||||||
message = " ".join(args.message)
|
message = " ".join(args.message)
|
||||||
|
|
||||||
|
|
||||||
window = Gtk.ApplicationWindow()
|
window = Gtk.ApplicationWindow()
|
||||||
window.set_keep_above(True)
|
window.set_keep_above(True)
|
||||||
window.set_decorated(False)
|
window.set_decorated(False)
|
||||||
|
@ -25,17 +25,17 @@ window.add(scrolled_window)
|
||||||
|
|
||||||
|
|
||||||
def on_key_release(target, event):
|
def on_key_release(target, event):
|
||||||
key = event.keyval
|
key = event.keyval
|
||||||
if key in [Gdk.KEY_Escape, Gdk.KEY_q, Gdk.KEY_Q]:
|
if key in [Gdk.KEY_Escape, Gdk.KEY_q, Gdk.KEY_Q]:
|
||||||
window.close()
|
window.close()
|
||||||
|
|
||||||
|
|
||||||
def on_configure(target, event):
|
def on_configure(target, event):
|
||||||
if target != window or event.type != Gdk.EventType.CONFIGURE:
|
if target != window or event.type != Gdk.EventType.CONFIGURE:
|
||||||
return
|
return
|
||||||
font_desc = Pango.FontDescription()
|
font_desc = Pango.FontDescription()
|
||||||
font_desc.set_size(Pango.SCALE * event.height * 2 / 3)
|
font_desc.set_size(Pango.SCALE * event.height * 2 / 3)
|
||||||
label.override_font(font_desc)
|
label.override_font(font_desc)
|
||||||
|
|
||||||
|
|
||||||
window.connect("configure-event", on_configure)
|
window.connect("configure-event", on_configure)
|
||||||
|
|
|
@ -9,162 +9,162 @@
|
||||||
import math
|
import math
|
||||||
import gi
|
import gi
|
||||||
|
|
||||||
|
|
||||||
gi.require_version("Playerctl", "2.0")
|
gi.require_version("Playerctl", "2.0")
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
gi.require_version("Gdk", "3.0")
|
gi.require_version("Gdk", "3.0")
|
||||||
gi.require_version("Pango", "1.0")
|
gi.require_version("Pango", "1.0")
|
||||||
from gi.repository import Playerctl, Gtk, Gdk, GLib, Pango # noqa: E402
|
from gi.repository import Playerctl, Gtk, Gdk, GLib, Pango
|
||||||
|
|
||||||
|
|
||||||
# Larger priority values will make the player with this name appear higher in
|
# Larger priority values will make the player with this name appear higher in
|
||||||
# the menu. The default priority is 0.
|
# the menu. The default priority is 0.
|
||||||
PLAYER_NAME_PRIORITIES = {
|
PLAYER_NAME_PRIORITIES = {
|
||||||
"audacious": 2,
|
"audacious": 2,
|
||||||
"mpv": 1,
|
"mpv": 1,
|
||||||
"vlc": 1,
|
"vlc": 1,
|
||||||
"firefox": -1,
|
"firefox": -1,
|
||||||
"chrome": -2,
|
"chrome": -2,
|
||||||
"chromium": -2,
|
"chromium": -2,
|
||||||
}
|
}
|
||||||
|
|
||||||
PLAYER_ICON_NAME_FIXES = {
|
PLAYER_ICON_NAME_FIXES = {
|
||||||
"chrome": "google-chrome",
|
"chrome": "google-chrome",
|
||||||
}
|
}
|
||||||
|
|
||||||
PLAYER_PLAYBACK_STATUS_EMOJIS = {
|
PLAYER_PLAYBACK_STATUS_EMOJIS = {
|
||||||
Playerctl.PlaybackStatus.PLAYING: "\u25B6",
|
Playerctl.PlaybackStatus.PLAYING: "\u25B6",
|
||||||
Playerctl.PlaybackStatus.PAUSED: "\u23F8",
|
Playerctl.PlaybackStatus.PAUSED: "\u23F8",
|
||||||
Playerctl.PlaybackStatus.STOPPED: "\u23F9",
|
Playerctl.PlaybackStatus.STOPPED: "\u23F9",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def humanize_duration(duration):
|
def humanize_duration(duration):
|
||||||
minutes, seconds = divmod(math.floor(duration), 60)
|
minutes, seconds = divmod(math.floor(duration), 60)
|
||||||
hours, minutes = divmod(minutes, 60)
|
hours, minutes = divmod(minutes, 60)
|
||||||
text = "{:02}:{:02}".format(minutes, seconds)
|
text = "{:02}:{:02}".format(minutes, seconds)
|
||||||
if hours > 0:
|
if hours > 0:
|
||||||
text = "{}:{}".format(hours, text)
|
text = "{}:{}".format(hours, text)
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
def iter_metadata_entries_for_player(player):
|
def iter_metadata_entries_for_player(player):
|
||||||
metadata = player.props.metadata
|
metadata = player.props.metadata
|
||||||
|
|
||||||
title = metadata.lookup_value("xesam:title")
|
title = metadata.lookup_value("xesam:title")
|
||||||
if title:
|
if title:
|
||||||
yield title.get_string()
|
yield title.get_string()
|
||||||
|
|
||||||
album = metadata.lookup_value("xesam:album")
|
album = metadata.lookup_value("xesam:album")
|
||||||
if album:
|
if album:
|
||||||
yield album.get_string()
|
yield album.get_string()
|
||||||
|
|
||||||
if player.props.can_seek:
|
if player.props.can_seek:
|
||||||
position_secs = player.props.position / 1e6
|
position_secs = player.props.position / 1e6
|
||||||
duration = metadata.lookup_value("mpris:length")
|
duration = metadata.lookup_value("mpris:length")
|
||||||
if duration is not None and duration.is_of_type(GLib.VariantType.new("x")):
|
if duration is not None and duration.is_of_type(GLib.VariantType.new("x")):
|
||||||
duration_secs = duration.get_int64() / 1e6
|
duration_secs = duration.get_int64() / 1e6
|
||||||
yield "Time: {} / {}".format(
|
yield "Time: {} / {}".format(
|
||||||
humanize_duration(position_secs), humanize_duration(duration_secs)
|
humanize_duration(position_secs), humanize_duration(duration_secs)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def iter_actions_for_player(player):
|
def iter_actions_for_player(player):
|
||||||
if not player.props.can_control:
|
if not player.props.can_control:
|
||||||
yield ("This player can't be controlled!", None, False, None)
|
yield ("This player can't be controlled!", None, False, None)
|
||||||
return
|
return
|
||||||
|
|
||||||
playback_status = player.props.playback_status
|
playback_status = player.props.playback_status
|
||||||
if playback_status == Playerctl.PlaybackStatus.PLAYING:
|
if playback_status == Playerctl.PlaybackStatus.PLAYING:
|
||||||
yield (
|
|
||||||
"_Pause",
|
|
||||||
"media-playback-pause",
|
|
||||||
player.props.can_pause,
|
|
||||||
player.pause,
|
|
||||||
)
|
|
||||||
elif playback_status == Playerctl.PlaybackStatus.PAUSED:
|
|
||||||
yield (
|
|
||||||
"Resume (_P)",
|
|
||||||
"media-playback-start",
|
|
||||||
player.props.can_play,
|
|
||||||
player.play,
|
|
||||||
)
|
|
||||||
elif playback_status == Playerctl.PlaybackStatus.STOPPED:
|
|
||||||
yield (
|
|
||||||
"_Play",
|
|
||||||
"media-playback-start",
|
|
||||||
player.props.can_play,
|
|
||||||
player.play,
|
|
||||||
)
|
|
||||||
|
|
||||||
# See <https://github.com/altdesktop/playerctl/blob/c83a12a97031f64b260ea7f1be03386c3886b2d4/playerctl/playerctl-cli.c#L231-L235>
|
|
||||||
yield (
|
yield (
|
||||||
"_Stop",
|
"_Pause",
|
||||||
"media-playback-stop",
|
"media-playback-pause",
|
||||||
player.props.can_play and playback_status != Playerctl.PlaybackStatus.STOPPED,
|
player.props.can_pause,
|
||||||
player.stop,
|
player.pause,
|
||||||
|
)
|
||||||
|
elif playback_status == Playerctl.PlaybackStatus.PAUSED:
|
||||||
|
yield (
|
||||||
|
"Resume (_P)",
|
||||||
|
"media-playback-start",
|
||||||
|
player.props.can_play,
|
||||||
|
player.play,
|
||||||
|
)
|
||||||
|
elif playback_status == Playerctl.PlaybackStatus.STOPPED:
|
||||||
|
yield (
|
||||||
|
"_Play",
|
||||||
|
"media-playback-start",
|
||||||
|
player.props.can_play,
|
||||||
|
player.play,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# See <https://github.com/altdesktop/playerctl/blob/c83a12a97031f64b260ea7f1be03386c3886b2d4/playerctl/playerctl-cli.c#L231-L235>
|
||||||
|
yield (
|
||||||
|
"_Stop",
|
||||||
|
"media-playback-stop",
|
||||||
|
player.props.can_play and playback_status != Playerctl.PlaybackStatus.STOPPED,
|
||||||
|
player.stop,
|
||||||
|
)
|
||||||
|
|
||||||
|
yield (
|
||||||
|
"_Mute" if player.props.volume != 0.0 else "Nor_mal volume",
|
||||||
|
"audio-volume-muted" if player.props.volume != 0.0 else "audio-volume-high",
|
||||||
|
True,
|
||||||
|
lambda volume: player.set_volume(volume),
|
||||||
|
0.0 if player.props.volume != 0.0 else 1.0,
|
||||||
|
)
|
||||||
|
yield (
|
||||||
|
"Volume +10%",
|
||||||
|
"audio-volume-medium",
|
||||||
|
True,
|
||||||
|
lambda: player.set_volume(min(player.props.volume + 0.1, 1.0)),
|
||||||
|
)
|
||||||
|
yield (
|
||||||
|
"Volume -10%",
|
||||||
|
"audio-volume-low",
|
||||||
|
True,
|
||||||
|
lambda: player.set_volume(max(player.props.volume - 0.1, 0.0)),
|
||||||
|
)
|
||||||
|
|
||||||
|
yield (
|
||||||
|
"_Next",
|
||||||
|
"media-skip-forward",
|
||||||
|
player.props.can_go_next,
|
||||||
|
player.next,
|
||||||
|
)
|
||||||
|
yield (
|
||||||
|
"Previous (_B)",
|
||||||
|
"media-skip-backward",
|
||||||
|
player.props.can_go_previous,
|
||||||
|
player.previous,
|
||||||
|
)
|
||||||
|
|
||||||
|
shuffle = player.props.shuffle
|
||||||
|
yield (
|
||||||
|
"Don't shuffle (_R)" if shuffle else "Shuffle (_R)",
|
||||||
|
"media-playlist-shuffle",
|
||||||
|
True,
|
||||||
|
lambda: player.set_shuffle(not shuffle),
|
||||||
|
)
|
||||||
|
|
||||||
|
loop_status = player.props.loop_status
|
||||||
|
for loop_action_name, loop_action_status in [
|
||||||
|
("Don't _loop", Playerctl.LoopStatus.NONE),
|
||||||
|
("Loop _one", Playerctl.LoopStatus.TRACK),
|
||||||
|
("Loop _all", Playerctl.LoopStatus.PLAYLIST),
|
||||||
|
]:
|
||||||
yield (
|
yield (
|
||||||
"_Mute" if player.props.volume != 0.0 else "Nor_mal volume",
|
loop_action_name,
|
||||||
"audio-volume-muted" if player.props.volume != 0.0 else "audio-volume-high",
|
"media-playlist-repeat",
|
||||||
True,
|
loop_action_status != loop_status,
|
||||||
lambda volume: player.set_volume(volume),
|
lambda loop_action_status: player.set_loop_status(loop_action_status),
|
||||||
0.0 if player.props.volume != 0.0 else 1.0,
|
loop_action_status,
|
||||||
)
|
|
||||||
yield (
|
|
||||||
"Volume +10%",
|
|
||||||
"audio-volume-medium",
|
|
||||||
True,
|
|
||||||
lambda: player.set_volume(min(player.props.volume + 0.1, 1.0)),
|
|
||||||
)
|
|
||||||
yield (
|
|
||||||
"Volume -10%",
|
|
||||||
"audio-volume-low",
|
|
||||||
True,
|
|
||||||
lambda: player.set_volume(max(player.props.volume - 0.1, 0.0)),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
yield (
|
yield (
|
||||||
"_Next",
|
"Play a_gain",
|
||||||
"media-skip-forward",
|
"go-first",
|
||||||
player.props.can_go_next,
|
player.props.can_seek,
|
||||||
player.next,
|
lambda: player.set_position(0),
|
||||||
)
|
)
|
||||||
yield (
|
|
||||||
"Previous (_B)",
|
|
||||||
"media-skip-backward",
|
|
||||||
player.props.can_go_previous,
|
|
||||||
player.previous,
|
|
||||||
)
|
|
||||||
|
|
||||||
shuffle = player.props.shuffle
|
|
||||||
yield (
|
|
||||||
"Don't shuffle (_R)" if shuffle else "Shuffle (_R)",
|
|
||||||
"media-playlist-shuffle",
|
|
||||||
True,
|
|
||||||
lambda: player.set_shuffle(not shuffle),
|
|
||||||
)
|
|
||||||
|
|
||||||
loop_status = player.props.loop_status
|
|
||||||
for loop_action_name, loop_action_status in [
|
|
||||||
("Don't _loop", Playerctl.LoopStatus.NONE),
|
|
||||||
("Loop _one", Playerctl.LoopStatus.TRACK),
|
|
||||||
("Loop _all", Playerctl.LoopStatus.PLAYLIST),
|
|
||||||
]:
|
|
||||||
yield (
|
|
||||||
loop_action_name,
|
|
||||||
"media-playlist-repeat",
|
|
||||||
loop_action_status != loop_status,
|
|
||||||
lambda loop_action_status: player.set_loop_status(loop_action_status),
|
|
||||||
loop_action_status,
|
|
||||||
)
|
|
||||||
|
|
||||||
yield (
|
|
||||||
"Play a_gain",
|
|
||||||
"go-first",
|
|
||||||
player.props.can_seek,
|
|
||||||
lambda: player.set_position(0),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
root_menu = Gtk.Menu()
|
root_menu = Gtk.Menu()
|
||||||
|
@ -172,93 +172,84 @@ root_menu = Gtk.Menu()
|
||||||
player_names = Playerctl.list_players()
|
player_names = Playerctl.list_players()
|
||||||
|
|
||||||
if len(player_names) > 0:
|
if len(player_names) > 0:
|
||||||
players = []
|
players = []
|
||||||
for player_name in player_names:
|
for player_name in player_names:
|
||||||
player = Playerctl.Player.new_from_name(player_name)
|
player = Playerctl.Player.new_from_name(player_name)
|
||||||
players.append(
|
players.append({
|
||||||
{
|
"player":
|
||||||
"player": player,
|
player,
|
||||||
"player_name": player_name,
|
"player_name":
|
||||||
"sorting_key": (
|
player_name,
|
||||||
player.props.playback_status != Playerctl.PlaybackStatus.PLAYING,
|
"sorting_key": (
|
||||||
-PLAYER_NAME_PRIORITIES.get(player_name.name, 0),
|
player.props.playback_status != Playerctl.PlaybackStatus.PLAYING,
|
||||||
player_name.instance,
|
-PLAYER_NAME_PRIORITIES.get(player_name.name, 0),
|
||||||
),
|
player_name.instance,
|
||||||
}
|
),
|
||||||
)
|
})
|
||||||
players = sorted(
|
players = sorted(players, key=lambda player_and_meta: player_and_meta["sorting_key"])
|
||||||
players, key=lambda player_and_meta: player_and_meta["sorting_key"]
|
|
||||||
|
for player_and_meta in players:
|
||||||
|
player_name = player_and_meta["player_name"]
|
||||||
|
player = player_and_meta["player"]
|
||||||
|
|
||||||
|
player_menu_item = Gtk.ImageMenuItem.new_with_label(
|
||||||
|
"{} [{}]".format(
|
||||||
|
player_name.instance,
|
||||||
|
PLAYER_PLAYBACK_STATUS_EMOJIS[player.props.playback_status],
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
for player_and_meta in players:
|
player_icon_name = PLAYER_ICON_NAME_FIXES.get(player_name.name, player_name.name)
|
||||||
player_name = player_and_meta["player_name"]
|
player_icon = Gtk.Image.new_from_icon_name(player_icon_name, Gtk.IconSize.MENU)
|
||||||
player = player_and_meta["player"]
|
player_menu_item.set_image(player_icon)
|
||||||
|
|
||||||
player_menu_item = Gtk.ImageMenuItem.new_with_label(
|
actions_menu = Gtk.Menu()
|
||||||
"{} [{}]".format(
|
|
||||||
player_name.instance,
|
track_metadata = player.props.metadata
|
||||||
PLAYER_PLAYBACK_STATUS_EMOJIS[player.props.playback_status],
|
any_metadata_was_added = False
|
||||||
)
|
for meta_entry_text in iter_metadata_entries_for_player(player):
|
||||||
|
meta_menu_item = Gtk.MenuItem.new_with_label(meta_entry_text)
|
||||||
|
meta_menu_item.set_sensitive(False)
|
||||||
|
meta_menu_item_label = meta_menu_item.get_child()
|
||||||
|
meta_menu_item_label.set_ellipsize(Pango.EllipsizeMode.END)
|
||||||
|
meta_menu_item_label.set_max_width_chars(20)
|
||||||
|
|
||||||
|
actions_menu.append(meta_menu_item)
|
||||||
|
any_metadata_was_added = True
|
||||||
|
|
||||||
|
if any_metadata_was_added:
|
||||||
|
actions_menu.append(Gtk.SeparatorMenuItem.new())
|
||||||
|
|
||||||
|
for (
|
||||||
|
action_name,
|
||||||
|
action_icon_name,
|
||||||
|
action_enabled,
|
||||||
|
action_fn,
|
||||||
|
*action_fn_args,
|
||||||
|
) in iter_actions_for_player(player):
|
||||||
|
action_menu_item = Gtk.ImageMenuItem.new_with_mnemonic(action_name)
|
||||||
|
|
||||||
|
if action_icon_name is not None:
|
||||||
|
action_icon = Gtk.Image.new_from_icon_name(action_icon_name, Gtk.IconSize.MENU)
|
||||||
|
action_menu_item.set_image(action_icon)
|
||||||
|
|
||||||
|
action_menu_item.set_sensitive(action_enabled)
|
||||||
|
if action_fn is not None:
|
||||||
|
action_menu_item.connect(
|
||||||
|
"activate",
|
||||||
|
lambda _menu_item, action_fn, action_fn_args: action_fn(*action_fn_args),
|
||||||
|
action_fn,
|
||||||
|
action_fn_args,
|
||||||
)
|
)
|
||||||
|
|
||||||
player_icon_name = PLAYER_ICON_NAME_FIXES.get(
|
actions_menu.append(action_menu_item)
|
||||||
player_name.name, player_name.name
|
|
||||||
)
|
|
||||||
player_icon = Gtk.Image.new_from_icon_name(player_icon_name, Gtk.IconSize.MENU)
|
|
||||||
player_menu_item.set_image(player_icon)
|
|
||||||
|
|
||||||
actions_menu = Gtk.Menu()
|
player_menu_item.set_submenu(actions_menu)
|
||||||
|
root_menu.append(player_menu_item)
|
||||||
track_metadata = player.props.metadata
|
|
||||||
any_metadata_was_added = False
|
|
||||||
for meta_entry_text in iter_metadata_entries_for_player(player):
|
|
||||||
meta_menu_item = Gtk.MenuItem.new_with_label(meta_entry_text)
|
|
||||||
meta_menu_item.set_sensitive(False)
|
|
||||||
meta_menu_item_label = meta_menu_item.get_child()
|
|
||||||
meta_menu_item_label.set_ellipsize(Pango.EllipsizeMode.END)
|
|
||||||
meta_menu_item_label.set_max_width_chars(20)
|
|
||||||
|
|
||||||
actions_menu.append(meta_menu_item)
|
|
||||||
any_metadata_was_added = True
|
|
||||||
|
|
||||||
if any_metadata_was_added:
|
|
||||||
actions_menu.append(Gtk.SeparatorMenuItem.new())
|
|
||||||
|
|
||||||
for (
|
|
||||||
action_name,
|
|
||||||
action_icon_name,
|
|
||||||
action_enabled,
|
|
||||||
action_fn,
|
|
||||||
*action_fn_args,
|
|
||||||
) in iter_actions_for_player(player):
|
|
||||||
action_menu_item = Gtk.ImageMenuItem.new_with_mnemonic(action_name)
|
|
||||||
|
|
||||||
if action_icon_name is not None:
|
|
||||||
action_icon = Gtk.Image.new_from_icon_name(
|
|
||||||
action_icon_name, Gtk.IconSize.MENU
|
|
||||||
)
|
|
||||||
action_menu_item.set_image(action_icon)
|
|
||||||
|
|
||||||
action_menu_item.set_sensitive(action_enabled)
|
|
||||||
if action_fn is not None:
|
|
||||||
action_menu_item.connect(
|
|
||||||
"activate",
|
|
||||||
lambda _menu_item, action_fn, action_fn_args: action_fn(
|
|
||||||
*action_fn_args
|
|
||||||
),
|
|
||||||
action_fn,
|
|
||||||
action_fn_args,
|
|
||||||
)
|
|
||||||
|
|
||||||
actions_menu.append(action_menu_item)
|
|
||||||
|
|
||||||
player_menu_item.set_submenu(actions_menu)
|
|
||||||
root_menu.append(player_menu_item)
|
|
||||||
else:
|
else:
|
||||||
menu_item = Gtk.MenuItem.new_with_label("No players were detected!")
|
menu_item = Gtk.MenuItem.new_with_label("No players were detected!")
|
||||||
menu_item.set_sensitive(False)
|
menu_item.set_sensitive(False)
|
||||||
root_menu.append(menu_item)
|
root_menu.append(menu_item)
|
||||||
|
|
||||||
|
|
||||||
root_menu.connect("selection-done", Gtk.main_quit)
|
root_menu.connect("selection-done", Gtk.main_quit)
|
||||||
root_menu.connect("deactivate", Gtk.main_quit)
|
root_menu.connect("deactivate", Gtk.main_quit)
|
||||||
|
|
|
@ -16,35 +16,31 @@ import shutil
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from typing import Optional, Tuple, Generator
|
from typing import Optional, Tuple, Generator
|
||||||
|
|
||||||
|
|
||||||
sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "script-resources"))
|
sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "script-resources"))
|
||||||
import common_script_utils
|
import common_script_utils
|
||||||
|
|
||||||
|
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
firefox_home: Path = Path.home() / "Library" / "Application Support" / "Firefox"
|
firefox_home: Path = Path.home() / "Library" / "Application Support" / "Firefox"
|
||||||
elif os.name == "posix":
|
elif os.name == "posix":
|
||||||
firefox_home: Path = Path.home() / ".mozilla" / "firefox"
|
firefox_home: Path = Path.home() / ".mozilla" / "firefox"
|
||||||
else:
|
else:
|
||||||
common_script_utils.platform_not_supported_error()
|
common_script_utils.platform_not_supported_error()
|
||||||
|
|
||||||
|
|
||||||
profiles_config = ConfigParser(interpolation=None)
|
profiles_config = ConfigParser(interpolation=None)
|
||||||
profiles_config.read(firefox_home / "profiles.ini")
|
profiles_config.read(firefox_home / "profiles.ini")
|
||||||
|
|
||||||
installs_sections: list[str] = [
|
installs_sections: list[str] = [s for s in profiles_config.sections() if s.startswith("Install")]
|
||||||
s for s in profiles_config.sections() if s.startswith("Install")
|
|
||||||
]
|
|
||||||
if not installs_sections:
|
if not installs_sections:
|
||||||
raise Exception("no Firefox installations detected!")
|
raise Exception("no Firefox installations detected!")
|
||||||
if len(installs_sections) > 1:
|
if len(installs_sections) > 1:
|
||||||
raise Exception("multiple Firefox installations are not supported!")
|
raise Exception("multiple Firefox installations are not supported!")
|
||||||
profile_dir: Path = firefox_home / profiles_config.get(installs_sections[0], "Default")
|
profile_dir: Path = firefox_home / profiles_config.get(installs_sections[0], "Default")
|
||||||
|
|
||||||
# should places.sqlite be used instead?
|
# should places.sqlite be used instead?
|
||||||
db_path: Path = profile_dir / "weave" / "bookmarks.sqlite"
|
db_path: Path = profile_dir / "weave" / "bookmarks.sqlite"
|
||||||
if not db_path.is_file():
|
if not db_path.is_file():
|
||||||
raise Exception("'{}' is not a file".format(db_path))
|
raise Exception("'{}' is not a file".format(db_path))
|
||||||
|
|
||||||
|
|
||||||
# Firefox holds a lock over the database file, so I can't connect to it even
|
# Firefox holds a lock over the database file, so I can't connect to it even
|
||||||
# in the readonly mode: https://stackoverflow.com/a/7857866/12005228
|
# in the readonly mode: https://stackoverflow.com/a/7857866/12005228
|
||||||
|
@ -55,78 +51,74 @@ os.close(db_copy_fd)
|
||||||
chooser_entries: list[Tuple[str, str, Optional[str]]] = []
|
chooser_entries: list[Tuple[str, str, Optional[str]]] = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
shutil.copyfile(db_path, db_copy_path)
|
shutil.copyfile(db_path, db_copy_path)
|
||||||
db = sqlite3.connect(db_copy_path)
|
db = sqlite3.connect(db_copy_path)
|
||||||
|
|
||||||
urls: dict[int, str] = {}
|
urls: dict[int, str] = {}
|
||||||
url_id: int
|
url_id: int
|
||||||
url: str
|
url: str
|
||||||
for url_id, url in db.execute("SELECT id, url FROM urls"):
|
for url_id, url in db.execute("SELECT id, url FROM urls"):
|
||||||
urls[url_id] = url
|
urls[url_id] = url
|
||||||
|
|
||||||
folders: dict[str, Tuple[Optional[str], str]] = {}
|
folders: dict[str, Tuple[Optional[str], str]] = {}
|
||||||
folder_id: str
|
folder_id: str
|
||||||
parent_folder_id: str
|
parent_folder_id: str
|
||||||
folder_title: str
|
folder_title: str
|
||||||
for folder_id, parent_folder_id, folder_title in db.execute(
|
for folder_id, parent_folder_id, folder_title in db.execute(
|
||||||
"SELECT guid, parentGuid, title FROM items WHERE kind = 3 AND validity AND NOT isDeleted"
|
"SELECT guid, parentGuid, title FROM items WHERE kind = 3 AND validity AND NOT isDeleted"
|
||||||
):
|
):
|
||||||
folders[folder_id] = (
|
folders[folder_id] = (
|
||||||
parent_folder_id if parent_folder_id != folder_id else None,
|
parent_folder_id if parent_folder_id != folder_id else None,
|
||||||
folder_title,
|
folder_title,
|
||||||
)
|
)
|
||||||
|
|
||||||
url_title: str
|
url_title: str
|
||||||
url_id: int
|
url_id: int
|
||||||
url_keyword: str
|
url_keyword: str
|
||||||
parent_folder_id: str
|
parent_folder_id: str
|
||||||
for url_title, url_id, url_keyword, parent_folder_id in db.execute(
|
for url_title, url_id, url_keyword, parent_folder_id in db.execute(
|
||||||
"SELECT title, urlId, keyword, parentGuid FROM items WHERE kind = 1 AND validity AND NOT isDeleted"
|
"SELECT title, urlId, keyword, parentGuid FROM items WHERE kind = 1 AND validity AND NOT isDeleted"
|
||||||
):
|
):
|
||||||
url = urls[url_id]
|
url = urls[url_id]
|
||||||
|
|
||||||
folder_path = list[str]()
|
folder_path = list[str]()
|
||||||
parent_folder_id_2: Optional[str] = parent_folder_id
|
parent_folder_id_2: Optional[str] = parent_folder_id
|
||||||
while parent_folder_id_2 is not None:
|
while parent_folder_id_2 is not None:
|
||||||
folder = folders.get(parent_folder_id_2, None)
|
folder = folders.get(parent_folder_id_2, None)
|
||||||
if folder is None:
|
if folder is None:
|
||||||
# broken folder structure?
|
# broken folder structure?
|
||||||
folder_path.clear()
|
folder_path.clear()
|
||||||
break
|
break
|
||||||
parent_folder_id_2, folder_title = folder
|
parent_folder_id_2, folder_title = folder
|
||||||
if folder_title is not None:
|
if folder_title is not None:
|
||||||
folder_path.append(folder_title)
|
folder_path.append(folder_title)
|
||||||
|
|
||||||
folder_path_str = (
|
folder_path_str = (("/" + "/".join(reversed(folder_path))) if len(folder_path) > 0 else None)
|
||||||
("/" + "/".join(reversed(folder_path))) if len(folder_path) > 0 else None
|
|
||||||
)
|
|
||||||
|
|
||||||
chooser_entries.append((url_title, url, folder_path_str))
|
chooser_entries.append((url_title, url, folder_path_str))
|
||||||
if url_keyword is not None:
|
if url_keyword is not None:
|
||||||
chooser_entries.append((url_keyword, url, folder_path_str))
|
chooser_entries.append((url_keyword, url, folder_path_str))
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
os.remove(db_copy_path)
|
os.remove(db_copy_path)
|
||||||
|
|
||||||
|
|
||||||
def chooser_entries_iter() -> Generator[str, None, None]:
|
def chooser_entries_iter() -> Generator[str, None, None]:
|
||||||
for title, url, folder_path_str in chooser_entries:
|
for title, url, folder_path_str in chooser_entries:
|
||||||
entry_items = [title, url]
|
entry_items = [title, url]
|
||||||
if folder_path_str is not None:
|
if folder_path_str is not None:
|
||||||
entry_items.append(folder_path_str)
|
entry_items.append(folder_path_str)
|
||||||
entry = " \u2014\u2014 ".join(entry_items)
|
entry = " \u2014\u2014 ".join(entry_items)
|
||||||
yield entry
|
yield entry
|
||||||
|
|
||||||
|
|
||||||
chosen_index = common_script_utils.run_chooser(
|
chosen_index = common_script_utils.run_chooser(chooser_entries_iter(), prompt="bookmark")
|
||||||
chooser_entries_iter(), prompt="bookmark"
|
|
||||||
)
|
|
||||||
|
|
||||||
if chosen_index >= 0:
|
if chosen_index >= 0:
|
||||||
_title, url, _folder_path_str = chooser_entries[chosen_index]
|
_title, url, _folder_path_str = chooser_entries[chosen_index]
|
||||||
print(url)
|
print(url)
|
||||||
|
|
||||||
common_script_utils.set_clipboard(url)
|
common_script_utils.set_clipboard(url)
|
||||||
common_script_utils.send_notification(
|
common_script_utils.send_notification(
|
||||||
os.path.basename(__file__), "bookmark URL copied to clipboard!", url
|
os.path.basename(__file__), "bookmark URL copied to clipboard!", url
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
|
||||||
def randbyte() -> int:
|
def randbyte() -> int:
|
||||||
return random.randrange(0, 256)
|
return random.randrange(0, 256)
|
||||||
|
|
||||||
|
|
||||||
print("127.{}.{}.{}".format(randbyte(), randbyte(), randbyte()))
|
print("127.{}.{}.{}".format(randbyte(), randbyte(), randbyte()))
|
||||||
|
|
|
@ -0,0 +1,359 @@
|
||||||
|
#compdef keybase
|
||||||
|
#autoload
|
||||||
|
|
||||||
|
# keybase completion, based on cli help text
|
||||||
|
# https://github.com/fnoris/keybase-zsh-completion
|
||||||
|
|
||||||
|
# The MIT License (MIT)
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014 David Tiersch
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
local curcontext="$curcontext" state line ret=1
|
||||||
|
local -a _command_args
|
||||||
|
local -a _global_args
|
||||||
|
local -a _subcommands
|
||||||
|
|
||||||
|
local IFS=$'\n'
|
||||||
|
_global_args=($(keybase advanced | grep '^\s*--' | sed -r 's/^[\t ]*(--[^\t ,]+)( [^\t ,]*)?,? ?(--?[^\t ]+)?[\t ]*(.*)$/(\3)\1[\4]/'))
|
||||||
|
|
||||||
|
_arguments -C -A "-v" -A "--version"\
|
||||||
|
'(- 1 *)'{-v,--version}'[display version information]' \
|
||||||
|
'1: :->cmds' \
|
||||||
|
$_global_args \
|
||||||
|
'*:: :->args' && ret=0
|
||||||
|
|
||||||
|
case $state in
|
||||||
|
cmds)
|
||||||
|
_subcommands=(
|
||||||
|
"base62:base62 operations"
|
||||||
|
"cert:print the CA cert for api.keybase.io"
|
||||||
|
"chat:chat securely with keybase users"
|
||||||
|
"ctl:control the background keybase service"
|
||||||
|
"currency:manage cyrptocurrency address"
|
||||||
|
"decrypt:decrypt messages or files for keybase users"
|
||||||
|
"deprovision:revoke the current device, log out, and delete local state"
|
||||||
|
"device:manage your devices"
|
||||||
|
"dump-keyfamily:print out a user's current key family"
|
||||||
|
"encrypt:encrypt messages or files for keybase users"
|
||||||
|
"follow:verify a user's authenticity and optionally follow them"
|
||||||
|
"track:verify a user's authenticity and optionally follow them"
|
||||||
|
"fs:perform filesystem operations"
|
||||||
|
"id:identify a user and check their signature chain"
|
||||||
|
"list-followers:list thost who follow you"
|
||||||
|
"list-following:list who you or the given user is following"
|
||||||
|
"log:manage keybase log"
|
||||||
|
"login:establish a session with the keybase server"
|
||||||
|
"logout:logout and remove session information"
|
||||||
|
"paperkey:generate paper keys for recovering your account"
|
||||||
|
"passphrase:change or recover your keybase passphrase"
|
||||||
|
"pgp:manage keybase PGP keys"
|
||||||
|
"ping:ping the keybase API server"
|
||||||
|
"prove:generate a new proof"
|
||||||
|
"rekey:rekey status and actions"
|
||||||
|
"search:search for keybase users"
|
||||||
|
"sign:sign a document"
|
||||||
|
"signup:signup for a new account"
|
||||||
|
"sigs:manage signatures"
|
||||||
|
"status:show information about current user"
|
||||||
|
"unfollow:unfollow a user"
|
||||||
|
"untrack:unfollow a user"
|
||||||
|
"update:the updater"
|
||||||
|
"verify:verify message or file signatures for keybase users"
|
||||||
|
"version:print out version and build information"
|
||||||
|
"help, h:shows a list fo commands or help for one command"
|
||||||
|
)
|
||||||
|
_describe -t subcommands 'Keybase subcommands' _subcommands && ret=0
|
||||||
|
;;
|
||||||
|
args)
|
||||||
|
case $line[1] in
|
||||||
|
help)
|
||||||
|
_values 'commands' \
|
||||||
|
'base62' \
|
||||||
|
'cert' \
|
||||||
|
'chat' \
|
||||||
|
'ctl' \
|
||||||
|
'currency' \
|
||||||
|
'decrypt' \
|
||||||
|
'deprovision' \
|
||||||
|
'device' \
|
||||||
|
'dump-keyfamily' \
|
||||||
|
'encrypt' \
|
||||||
|
'follow' \
|
||||||
|
'track' \
|
||||||
|
'fs' \
|
||||||
|
'id' \
|
||||||
|
'list-followers' \
|
||||||
|
'list-following' \
|
||||||
|
'log' \
|
||||||
|
'login' \
|
||||||
|
'logout' \
|
||||||
|
'paperkey' \
|
||||||
|
'pasphrase' \
|
||||||
|
'pgp' \
|
||||||
|
'ping' \
|
||||||
|
'prove' \
|
||||||
|
'rekey' \
|
||||||
|
'search' \
|
||||||
|
'sign' \
|
||||||
|
'signup' \
|
||||||
|
'sigs' \
|
||||||
|
'status' \
|
||||||
|
'unfollow' \
|
||||||
|
'untrack' \
|
||||||
|
'update' \
|
||||||
|
'verify' \
|
||||||
|
'version' \
|
||||||
|
'help, h' && ret=0
|
||||||
|
;;
|
||||||
|
base62)
|
||||||
|
_values "command" \
|
||||||
|
'decode[base62 decode]' \
|
||||||
|
'encode[base62 encode]' \
|
||||||
|
'help[Shows a list of commands or help for one command]'
|
||||||
|
;;
|
||||||
|
chat)
|
||||||
|
_values "command" \
|
||||||
|
'api[JSON api]' \
|
||||||
|
'download[Download an attachment from a conversation]' \
|
||||||
|
'hide[Hide or block a conversation]' \
|
||||||
|
'list[List conversations, sorted by activity]' \
|
||||||
|
'ls[List conversations, sorted by activity]' \
|
||||||
|
"list-unread[List conversations, with unread messages at the top]" \
|
||||||
|
"lsur[List conversations, with unread messages at the top]" \
|
||||||
|
'mute[Mute or unmute a conversation]' \
|
||||||
|
'read[Show new messages in a conversation and mark them as read]' \
|
||||||
|
'report[Report a conversation (also blocks it)]' \
|
||||||
|
'send[Send a message to a conversation]' \
|
||||||
|
'upload[Upload an attachment to a conversation]' \
|
||||||
|
'help[Shows a list of commands or help for one command]'
|
||||||
|
;;
|
||||||
|
ctl)
|
||||||
|
_values "command" \
|
||||||
|
'start[Start the backgroung keybase service]' \
|
||||||
|
'stop[Stop the backgroung keybase service]' \
|
||||||
|
'reload[Reload config file]' \
|
||||||
|
'restart[Restart the background keybase service]' \
|
||||||
|
"log-rotate[Close and open the keybase service's log file]" \
|
||||||
|
'watchdog[Start, watch and prop up the backgound service]' \
|
||||||
|
'watchdog2[Start and monitor background services]' \
|
||||||
|
'app-exit[Exit the Keybase app]' \
|
||||||
|
'help[Shows a list of commands or help for one command]'
|
||||||
|
;;
|
||||||
|
currency)
|
||||||
|
_values "command" \
|
||||||
|
'add[Sign a cryptocurrency (bitcoin or zcash) address into your identity]' \
|
||||||
|
'help[Shows a list of commands or help for one command]'
|
||||||
|
;;
|
||||||
|
decrypt)
|
||||||
|
_command_args=(
|
||||||
|
'(--infile)--infile[Specify an input file]' \
|
||||||
|
'(--message)--message[Provide the message on the command line]' \
|
||||||
|
'(--outfile)--outfile[Specify an outfile (stdout by default)]' \
|
||||||
|
'(--interactive)--interactive[Interactive prompt for decryption after sender verification]' \
|
||||||
|
'(--force)--force[Force unprompted decryption, even on an indentify failure]' \
|
||||||
|
'(--paperkey)--paperkey[Use a paper key for decryption]' \
|
||||||
|
'(--encryptor-outfile)--encryptor-outfile[Write the Keybase name of the encryptor to this file]'
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
device)
|
||||||
|
_values "command" \
|
||||||
|
'remove[Remove a device]' \
|
||||||
|
'list[List devices]' \
|
||||||
|
'add[Authorize a new device]' \
|
||||||
|
'help[Shows a list of commands or help for one command]'
|
||||||
|
;;
|
||||||
|
encrypt)
|
||||||
|
_command_args=(
|
||||||
|
'(--binary)--binary[Output in binary (rather than ASCII/armored)]' \
|
||||||
|
'(--infile)--infile[Specify an input file]' \
|
||||||
|
'(message)--message[Provide the message on the command line]' \
|
||||||
|
'(--outfile)--outfile[Specify an outfile (stdout by default)]' \
|
||||||
|
"(--hide-recipients)--hide-recipients[Don't include recipients in metadata]" \
|
||||||
|
"(--anonymous)--anonymous[Don't include sender or recipients in metadata. Implies --hide-recipients]" \
|
||||||
|
"(--no-self)--no-self[Don't encrypt for yourself]"
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
follow)
|
||||||
|
_command_args=(
|
||||||
|
"(--local)--local[Only follow locally, don't send a public statement to the server]" \
|
||||||
|
'(-y)-y[Approve remote following without prompting]' \
|
||||||
|
'(--skip-proof-cache)--skip-proof-cache[Skip cached proofs, force re-check]'
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
track)
|
||||||
|
_command_args=(
|
||||||
|
"(--local)--local[Only follow locally, don't send a public statement to the server]" \
|
||||||
|
'(-y)-y[Approve remote following without prompting]' \
|
||||||
|
'(--skip-proof-cache)--skip-proof-cache[Skip cached proofs, force re-check]'
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
fs)
|
||||||
|
_values "command" \
|
||||||
|
'ls[list directory contents]' \
|
||||||
|
'cp[copy one or more directory elements to dest]' \
|
||||||
|
'mv[move one or more directory elements to dest]' \
|
||||||
|
'read[output file contents to standard output]' \
|
||||||
|
'rm[remove one or more directory elements]' \
|
||||||
|
'mkdir[create directory]' \
|
||||||
|
'stat[stat directory element]' \
|
||||||
|
'get-status[get status of pending operation]' \
|
||||||
|
'kill[kill operation]' \
|
||||||
|
'ps[list running operations]' \
|
||||||
|
'write[write input to file]' \
|
||||||
|
'help[Shows a list of commands or help for one command]'
|
||||||
|
;;
|
||||||
|
id)
|
||||||
|
_command_args=(
|
||||||
|
'(--skip-proof-cache)--skip-proof-cache[Skip cached proofs, force re-check]'
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
list-followers)
|
||||||
|
_command_args=(
|
||||||
|
'(--verbose)--verbose[A full dump, with more gory details]'
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
list-following)
|
||||||
|
_command_args=(
|
||||||
|
'(--filter)--filter[Provide a regex filter]' \
|
||||||
|
'(--headers)--headers[Show column headers]' \
|
||||||
|
'(--json)--json[Output as JSON (default is text)]' \
|
||||||
|
'(--verbose)--verbose[A full dump, with more gory details]'
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
log)
|
||||||
|
_values "command" \
|
||||||
|
'send[Send recent debug logs to keybase]' \
|
||||||
|
'help[Shows a list of commands or help for one command]'
|
||||||
|
;;
|
||||||
|
login)
|
||||||
|
_command_args=(
|
||||||
|
'(--provision-by-email)--provision-by-email[Use an email address associated with a keybase account to provision a device]'
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
passphrase)
|
||||||
|
_values "command" \
|
||||||
|
'change[Change your keybase account passphrase]' \
|
||||||
|
'recover[Recover your keybase account passphrase]' \
|
||||||
|
'help[Shows a list of commands or help for one command]'
|
||||||
|
;;
|
||||||
|
pgp)
|
||||||
|
_values "command" \
|
||||||
|
'gen[Generate a new PGP key and write to local secret keychain]' \
|
||||||
|
'pull[Download the latest PGP keys for people you track]' \
|
||||||
|
'update[Update your public PGP keys on keybase with those exported from the local GPG keyring]' \
|
||||||
|
'select[Select a key as your own and register the public half with the server]' \
|
||||||
|
'sign[PGP sign a document]' \
|
||||||
|
'encrypt[PGP encrypt messages or files for keybase users]' \
|
||||||
|
'decrypt[PGP decrypt messages or files for keybase users]' \
|
||||||
|
'verify[PGP verify message or file signatures for keybase users]' \
|
||||||
|
'export[Export a PGP key from keybase]' \
|
||||||
|
'import[Import a PGP key into keybase]' \
|
||||||
|
'drop[Drop Keybases use of a PGP key]' \
|
||||||
|
'list[List the active PGP keys in your account]' \
|
||||||
|
'purge[Purge all PGP keys from Keybase keyring]' \
|
||||||
|
'help[Shows a list of commands or help for one command]'
|
||||||
|
;;
|
||||||
|
ping)
|
||||||
|
_command_args=(
|
||||||
|
'(--gregor)--gregor[Ping the Gregor server]'
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
prove)
|
||||||
|
_command_args=(
|
||||||
|
'(--output)--output[Output proof text to file (rather than standard out)]' \
|
||||||
|
"(--force)--force[Don't prompt]" \
|
||||||
|
)
|
||||||
|
_values "prove command" \
|
||||||
|
'service[Supported services are: coinbase, hackernews, reddit, dns, github, twitter, web, http, https]' \
|
||||||
|
'service username[Username or hostname at that service]'
|
||||||
|
;;
|
||||||
|
rekey)
|
||||||
|
_values "command" \
|
||||||
|
'status[Get pending rekey status]' \
|
||||||
|
'paper[Submit a paper key to help rekeying]' \
|
||||||
|
'help[Shows a list of commands or help for one command]'
|
||||||
|
;;
|
||||||
|
search)
|
||||||
|
_command_args=(
|
||||||
|
'(--json)--json[Output as JSON]'
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
sign)
|
||||||
|
_command_args=(
|
||||||
|
'(--binary)--binary[Output binary message (default is armored)]' \
|
||||||
|
'(--detached)--detached[Detached signature (default is attached)]' \
|
||||||
|
'(--infile)--infile[Specify an input file]' \
|
||||||
|
'(--message)--message[Provide the message to sign on the command line]' \
|
||||||
|
'(--outfile)--outfile[Specify an outfile (default is STDOUT)]'
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
signup)
|
||||||
|
_command_args=(
|
||||||
|
'(--invite-code)--invite-code[Specify an invite code]' \
|
||||||
|
'(--email)--email[Specify an account email]' \
|
||||||
|
'(--username)--username[Specify a username]'
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
sigs)
|
||||||
|
_values "command" \
|
||||||
|
'list[List signatures]' \
|
||||||
|
'revoke[Revoke a signature by sig ID]' \
|
||||||
|
'help[Shows a list of commands or help for one command]'
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
_command_args=(
|
||||||
|
'(--json)--json[Output status as JSON]' \
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
update)
|
||||||
|
_values "command" \
|
||||||
|
'check[Trigger an update check]' \
|
||||||
|
'run[Run the update with custom options]' \
|
||||||
|
'check-in-use[Check if we are in use (safe for restart)]' \
|
||||||
|
'notify[Notify the service about an update event]'
|
||||||
|
;;
|
||||||
|
verify)
|
||||||
|
_command_args=(
|
||||||
|
'(--detached)--detached[Specify a detached signature file]' \
|
||||||
|
'(--infile)--infile[Specify an input file]' \
|
||||||
|
'(--message)--message[Provide the message to verify on the command line]' \
|
||||||
|
"(--no-output)--no-output[Don't output the verified message]" \
|
||||||
|
'(--outfile)--outfile[Specify an outfile (default is STDOUT)]'
|
||||||
|
'(--signed-by)--signed-by[Assert signed by the given user (can use user assertion fomat)]' \
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
version)
|
||||||
|
_command_args=(
|
||||||
|
"(--format)--format[Alternate format for version output. Specify 's' for simple (1.2.3) or 'v' for verbose. Default (blank) includes build number (1.2.3-400)]" \
|
||||||
|
"(--no-service)--no-service[Don't report on the service's build information]"
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
_arguments \
|
||||||
|
$_command_args \
|
||||||
|
&& ret=0
|
||||||
|
|
||||||
|
return ret
|
||||||
|
s
|
Loading…
Reference in New Issue