resolved merge conflict

This commit is contained in:
Daniel Fichtinger 2025-06-13 15:43:05 -04:00
commit 110b65e396
31 changed files with 1662 additions and 87 deletions

View file

@ -63,7 +63,7 @@ proc_sorting = "memory"
proc_reversed = False
#* Show processes as a tree.
proc_tree = False
proc_tree = True
#* Use the cpu graph colors in the process list.
proc_colors = True

View file

@ -1,15 +1,14 @@
if status is-login
if not set -q __sourced_profile
set -x __sourced_profile 1
exec bash -c "\
test -e /etc/profile && source /etc/profile
test -e $HOME/.bash_profile && source $HOME/.bash_profile
exec fish --login
"
end
# if status is-login
# if not set -q __sourced_profile
# set -x __sourced_profile 1
# exec bash -c "\
# test -e /etc/profile && source /etc/profile
# test -e $HOME/.bash_profile && source $HOME/.bash_profile
# exec fish --login
# "
# end
set -e __sourced_profile
end
# end
if status is-interactive
# source ~/.config/fish/custom_cd.fish
@ -23,5 +22,7 @@ if status is-interactive
set -gx COLORTERM truecolor
set -gx TERM xterm-256color
end
end
set -gx EDITOR kak

View file

@ -2,6 +2,7 @@
# VERSION: 3.0
SETUVAR --export AUTOYADMPUSH:1
SETUVAR --export EDITOR:kak
SETUVAR --export IGREP_CUSTOM_EDITOR:kak\x20\x2b\x7bline_number\x7d\x20\x7bfile_name\x7d
SETUVAR --export KAKOUNE_POSIX_SHELL:/usr/bin/dash
SETUVAR --export XDG_CONFIG_HOME:/home/fic/\x2econfig
SETUVAR Z_DATA_DIR:/home/fic/\x2elocal/share/z

View file

@ -86,6 +86,8 @@ function kak-session -w kak --description "kakoune where sessions are derived fr
cat $fifo >/dev/null
command rm -r "$fifo_dir"
# echo "hook -once global BufCreate ^(?!.*\\*scratch\\*).* %{ delete-buffer *scratch* }" | kak -p "$session_id"
# command kak -c "$session_id" -e 'delete-buffer! *scratch*' $flags $files
command kak -c "$session_id" -e 'try %{ delete-buffer *scratch*; bar-buflist; echo }' $flags $files
else
command kak -s "$session_id" -e "cd %[$kakroot]" $flags $files
@ -116,6 +118,8 @@ function kak-session -w kak --description "kakoune where sessions are derived fr
setsid kak -d -s "$session_id" -E "cd %[$git_dir]; echo -to-file $fifo ready" &
cat $fifo >/dev/null
command rm -r "$fifo_dir"
# echo "hook -once global BufCreate [*]scratch[*] %{ delete-buffer *scratch* }" | kak -p "$session_id"
# command kak -c "$session_id" -e 'delete-buffer! *scratch*' $flags $files
command kak -c "$session_id" -e 'try %{ delete-buffer *scratch*; bar-buflist; echo }' $flags $files
else
command kak -s "$session_id" -e "cd %[$git_dir]" $flags $files

View file

@ -96,3 +96,47 @@ pin = "7275b7f85014aad7e15d4987ec4f2249572eecfb"
[language.ini.queries]
path = "runtime/queries/ini"
[language.just]
aliases = ["justfile"]
[language.just.grammar.source.git]
url = "https://github.com/poliorcetics/tree-sitter-just"
pin = "8d03cfdd7ab89ff76d935827de1b93450fa0ec0a"
[language.just.grammar]
path = "src"
compile = "cc"
compile_args = ["-c", "-fpic", "../parser.c", "-I", ".."]
compile_flags = ["-O3"]
link = "cc"
link_args = ["-shared", "-fpic", "parser.o", "-o", "just.so"]
link_flags = ["-O3"]
[language.just.queries.source.git]
url = "https://github.com/helix-editor/helix"
pin = "f6878f62f74430cff188e7978d06c5ed143179e9"
[language.just.queries]
path = "runtime/queries/just"
# typescript
[language.typescript.grammar.source.git]
url = "https://github.com/tree-sitter/tree-sitter-typescript"
pin = "b1bf4825d9eaa0f3bdeb1e52f099533328acfbdf"
[language.typescript.grammar]
path = "typescript/src"
compile = "cc"
compile_args = ["-c", "-fpic", "../scanner.c", "../parser.c", "-I", ".."]
compile_flags = ["-O3"]
link = "cc"
link_args = ["-shared", "-fpic", "scanner.o", "parser.o", "-o", "typescript.so"]
link_flags = ["-O3"]
[language.typescript.queries.source.git]
url = "https://git.sr.ht/~ficd/kak-tree-sitter"
pin = "d8afa2ddcf2f97d29f495eccc08ad9ccff8d9199"
[language.typescript.queries]
path = "runtime/queries/typescript"

View file

@ -1,4 +1,56 @@
map -docstring "yank the selection into the clipboard" global user y "<a-|> wl-copy<ret>"
declare-option -docstring %{
Command for copying to system clipboard.
} str clipboard_copy_cmd 'wl-copy'
declare-option int clip_selcount 0
define-command -hidden clip-trim %{
try %{
execute-keys <a-k>\n<ret>
execute-keys bjGjd
}
}
define-command -docstring %{
clip-copy [-split]: copy selections to system clipboard
Set the clipboard_copy_cmd option to change the command
Switches:
-split ensure each selection separated by newline
} -params 0..1 clipboard-copy %{
# preserve registers
evaluate-commands -save-regs 'a|' %{
set-option local clip_selcount %val{selection_count}
# copy selections
execute-keys '"ay'
# set shell register to copy command
set-register | %opt{clipboard_copy_cmd}
# branch based on switch
execute-keys %sh{
if [ "$kak_opt_clip_selcount" -gt 1 ]; then
echo ': edit -scratch<ret>'
if [ ${#} = 1 ] && [ ${1} = '-split' ]; then
# paste all
# reduce selections to those without newline
# append a newline
# delete extra newlines
# select all, pipe to copy cmd
echo '"a<a-P><a-K>\n<ret>a<ret><esc>'
echo 'gj: clip-trim<ret>'
echo '%<a-|><ret>'
else
# paste all, select all, pipe to copy cmd
echo '"a<a-P>%<a-|><ret>'
fi
echo ": delete-buffer<ret>"
else
echo '<a-|><ret>'
fi
}
}
}
map -docstring "yank the selections into the clipboard" global user y ": clipboard-copy<ret>"
map -docstring "yank the split selections into the clipboard" global user Y ": clipboard-copy -split<ret>"
map -docstring "paste the clipboard" global user p "<a-!> wl-paste -n<ret>"
map -docstring "paste the clipboard before" global user P "! wl-paste -n<ret>"

View file

@ -0,0 +1,106 @@
# http://editorconfig.org/#file-format-details
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Patch by Daniel <daniel@ficd.ca>:
# Support editorconfig for scratch buffers.
# If we're in a scratch buffer, we check the filetype,
# create a temp file with the appropriate extension, and pass
# it to editorconfig. If there's no .editorconfig in /tmp,
# we copy the one from $HOME. We clean up the files after.
# Detection
# ‾‾‾‾‾‾‾‾‾
hook global BufCreate .*[.](editorconfig) %{
set-option buffer filetype ini
set-option buffer static_words indent_style indent_size tab_width \
end_of_line charset insert_final_newline trim_trailing_whitespace root \
latin1 utf-8 utf-8-bom utf-16be utf-16le lf cr crlf unset space tab max_line_length
}
define-command editorconfig-load -params ..1 -docstring "editorconfig-load [file]: set formatting behavior according to editorconfig" %{
evaluate-commands %sh{
command -v editorconfig >/dev/null 2>&1 || { echo "fail editorconfig could not be found"; exit 1; }
file="${1:-$kak_buffile}"
filetype="$kak_opt_filetype"
# check if we have a real file or a scratch buffer
if [ ! -f "$file" ]; then
scratch="true"
# need to create .editorconfig in /tmp if it's not there
if [ ! -f "/tmp/.editorconfig" ]; then
cp "$HOME/.editorconfig" "/tmp/.editorconfig"
fi
case "$filetype" in
markdown)
file="/tmp/scratch.md"
touch "$file";;
python)
file="/tmp/scratch.py"
touch "$file";;
sh)
file="/tmp/scratch.sh"
touch "$file";;
bash)
file="/tmp/scratch.sh"
touch "$file";;
fish)
file="/tmp/scratch.fish"
touch "$file";;
json)
file="/tmp/scratch.json"
touch "$file";;
toml)
file="/tmp/scratch.toml"
touch "$file";;
*)
file="/tmp/scratch.txt"
touch "$file";;
esac
fi
case $file in
/*) # $kak_buffile is a full path that starts with a '/'
printf %s\\n "remove-hooks buffer editorconfig-hooks"
editorconfig "$file" | awk -v file="$file" -F= -- '
$1 == "indent_style" { indent_style = $2 }
$1 == "indent_size" { indent_size = $2 == "tab" ? 4 : $2 }
$1 == "tab_width" { tab_width = $2 }
$1 == "end_of_line" { end_of_line = $2 }
$1 == "charset" { charset = $2 }
$1 == "trim_trailing_whitespace" { trim_trailing_whitespace = $2 }
$1 == "max_line_length" { max_line_length = $2 }
END {
if (indent_style == "tab") {
print "set-option buffer indentwidth 0"
}
if (indent_style == "space") {
print "set-option buffer indentwidth " indent_size
}
if (indent_size || tab_width) {
print "set-option buffer tabstop " (tab_width ? tab_width : indent_size)
}
if (end_of_line == "lf" || end_of_line == "crlf") {
print "set-option buffer eolformat " end_of_line
}
if (charset == "utf-8-bom") {
print "set-option buffer BOM utf8"
}
if (trim_trailing_whitespace == "true") {
print "hook buffer BufWritePre \"" file "\" -group editorconfig-hooks %{ try %{ execute-keys -draft %{%s\\h+$<ret>d} } }"
}
if (max_line_length && max_line_length != "off") {
print "set window autowrap_column " max_line_length
print "autowrap-enable"
print "add-highlighter window/ column %sh{ echo $((" max_line_length "+1)) } default,bright-black"
}
}
' ;;
esac
if [ -n "$scratch" ]; then
rm "/tmp/.editorconfig"
rm "$file"
fi
}
}
complete-command editorconfig-load file

View file

@ -21,19 +21,19 @@ hook global WinSetOption filetype=kak %{
hook global WinSetOption filetype=typst %{
set-option buffer formatcmd "typstyle --wrap-text"
hook -group typst-auto-format window BufWritePre .* format
hook -once -always WinSetOption filetype=.* %{
hook -once -always window WinSetOption filetype=.* %{
unset-option window formatcmd
remove-hooks window typst-auto-format
}
define-command -docstring %{
Spawns a Zathura pdf preview and Typst watcher for the currently open Typst file
} typst %{
nop %sh{
{
"$kak_config/scripts/kak-typ-zathura.fish" -k -w "$kak_buffile" "$kak_client_pid"
} > /dev/null 2>&1 < /dev/null &
}
}
define-command -docstring %{
Spawns a Zathura pdf preview and Typst watcher for the currently open Typst file
} typst %{
nop %sh{
{
"$kak_config/scripts/kak-typ-zathura.fish" -k -w "$kak_buffile" "$kak_client_pid"
} > /dev/null 2>&1 < /dev/null &
}
}
}
hook global WinSetOption filetype=fish %{

View file

@ -0,0 +1,83 @@
# Detection
# ‾‾‾‾‾‾‾‾‾
hook global BufCreate .*/?[jJ]ustfile %{
set-option buffer filetype justfile
}
hook global WinSetOption tree_sitter_lang=justfile %{
set-option window tree_sitter_lang just
}
hook global WinSetOption filetype=justfile %{
require-module justfile
hook window ModeChange pop:insert:.* -group justfile-trim-indent justfile-trim-indent
hook window InsertChar \n -group justfile-insert just-insert-on-new-line
hook window InsertChar \n -group justfile-indent just-indent-on-new-line
hook -once -always window WinSetOption filetype=.* %{ remove-hooks window justfile-.+ }
}
hook -group justfile-highlight global WinSetOption filetype=justfile %{
add-highlighter window/justfile ref justfile
hook -once -always window WinSetOption filetype=.* %{ remove-highlighter window/justfile }
}
provide-module justfile %{
# Indentation
# ‾‾‾‾‾‾‾‾‾‾‾
define-command -hidden justfile-trim-indent %{
evaluate-commands -no-hooks -draft -itersel %{
execute-keys x
# remove trailing white spaces
try %{ execute-keys -draft s \h + $ <ret> d }
}
}
define-command -hidden just-insert-on-new-line %{
# copy '#' comment prefix and following white spaces
try %{ execute-keys -draft k x s ^\h*//\h* <ret> y jgh P }
}
define-command -hidden just-indent-on-new-line %{
evaluate-commands -draft -itersel %{
# preserve previous line indent
try %{ execute-keys -draft <semicolon>K<a-&> }
# cleanup trailing white spaces on previous line
try %{ execute-keys -draft kx s \h+$ <ret>"_d }
}
}
# Highlighters
# ‾‾‾‾‾‾‾‾‾‾‾‾
add-highlighter shared/justfile regions
add-highlighter shared/justfile/content default-region group
add-highlighter shared/justfile/content/recipe regex '^@?([\w-]+)([^\n]*):(?!=)([^\n]*)' 1:function 2:meta 3:keyword
add-highlighter shared/justfile/content/assignments regex ^([\w-]+\h*:=\h*[^\n]*) 1:meta
add-highlighter shared/justfile/content/operator regex '((^@|:=|=|\+|\(|\)))' 1:operator
add-highlighter shared/justfile/content/strings regions
add-highlighter shared/justfile/content/strings/double region '"' (?<!\\)(\\\\)*" fill string
add-highlighter shared/justfile/content/strings/single region "'" (?<!\\)(\\\\)*' fill string
add-highlighter shared/justfile/comment region '#' '$' fill comment
add-highlighter shared/justfile/inline region '`' '`' ref sh
add-highlighter shared/justfile/body region '^\h+' '^[^\h]' group
add-highlighter shared/justfile/body/interpreters regions
add-highlighter shared/justfile/body/interpreters/defaultshell default-region group
add-highlighter shared/justfile/body/interpreters/defaultshell/ ref sh
add-highlighter shared/justfile/body/interpreters/defaultshell/ regex '^\h+(@)' 1:operator
add-highlighter shared/justfile/body/interpreters/bash region '^\h+#!\h?/usr/bin/env bash' '^[^\h]' ref sh
add-highlighter shared/justfile/body/interpreters/sh region '^\h+#!\h?/usr/bin/env sh' '^[^\h]' ref sh
add-highlighter shared/justfile/body/ regex '(\{{2})([\w-]+(?:\(\))?)(\}{2})' 1:operator 2:variable 3:operator
}

View file

@ -1,5 +1,42 @@
# https://git.sr.ht/~hadronized/hop.kak
evaluate-commands %sh{ hop-kak --init }
# evaluate-commands %sh{ hop-kak --init }
provide-module hop-kak %~
declare-option range-specs hop_ranges
set-face global hop_label_head %exp{%opt{background},%opt{orange_golden}+Fbua}
set-face global hop_label_tail %exp{%opt{background},%opt{orange_golden}+Fbua}
# needed so the cursor face doesn't override what hop sets
# but only temporary because otherwise we want cursor face to
# override others
define-command -hidden hop-set-cursor %{
set-face window PrimaryCursorNormal "%opt{background},%opt{orange_blaze}+b"
set-face window SecondaryCursorNormal "%opt{background},%opt{orange_muted}"
set-face window PrimaryCursorInsert "%opt{background},%opt{g_3}+b"
set-face window SecondaryCursorInsert "%opt{background},%opt{g_7}"
set-face window PrimaryCursorNormalEol "%opt{background},%opt{orange_smolder}+b"
set-face window SecondaryCursorNormalEol "%opt{background},%opt{golden_muted}"
set-face window PrimaryCursorInsertEol "%opt{background},%opt{g_1}+b"
set-face window SecondaryCursorInsertEol "%opt{background},%opt{g_5}"
set-face window PrimarySelection ",%opt{brown_dark}"
set-face window SecondarySelection ",%opt{brown_darker}"
}
define-command -hidden hop-clear-cursor %{
set-face window PrimaryCursorNormal "%opt{background},%opt{orange_blaze}+gfb"
set-face window SecondaryCursorNormal "%opt{background},%opt{orange_muted}+gf"
set-face window PrimaryCursorInsert "%opt{background},%opt{g_3}+gfb"
set-face window SecondaryCursorInsert "%opt{background},%opt{g_7}+gf"
set-face window PrimaryCursorNormalEol "%opt{background},%opt{orange_smolder}+gfb"
set-face window SecondaryCursorNormalEol "%opt{background},%opt{golden_muted}+gf"
set-face window PrimaryCursorInsertEol "%opt{background},%opt{g_1}+gfb"
set-face window SecondaryCursorInsertEol "%opt{background},%opt{g_5}+gf"
set-face window PrimarySelection ",%opt{brown_dark}+g"
set-face window SecondarySelection ",%opt{brown_darker}+g"
}
declare-option str hop_kak_keyset 'tnserigmaodhcxplfuwyqz'
@ -14,11 +51,13 @@ define-command hop-kak %{
define-command -override hop-kak-words %{
hop-set-cursor
eval "ui-scrolloff-disable"
try %{ ui-wrap-disable }
map window normal <esc> ': trigger-user-hook donehop<ret><esc>'
map window normal , ': trigger-user-hook donehop<ret>,'
hook -once window User donehop %{
hop-clear-cursor
eval "ui-scrolloff-enable"
try %{ ui-wrap-enable }
unmap window normal <esc>
@ -37,3 +76,4 @@ map -docstring %{
map -docstring %{
Hop mode
} global normal <ret> ': enter-user-mode hop<ret>'
~

View file

@ -1,5 +1,6 @@
# load plugin
eval %sh{kak-lsp}
# eval %sh{kak-lsp-diags}
# mappings
map global user l ': enter-user-mode lsp<ret>' -docstring 'LSP mode'
@ -24,7 +25,7 @@ define-command -hidden -override lsp-hide-code-actions %{
set-option global lsp_debug false
# list of filetypes for which LSP will be activated in the window scope
declare-option str-list lsp_filetypes python go rust bash fish c cpp typst markdown yaml json jsonc bash sh
declare-option str-list lsp_filetypes python go rust bash fish c cpp typst markdown yaml json jsonc bash sh typescript javascript latex
declare-option -hidden bool inlay_enabled false
@ -48,21 +49,40 @@ define-command -hidden inlay-toggle %{
}
}
declare-option -hidden bool diagnostics_enabled false
define-command -hidden diagnostics-on %{
declare-option -hidden bool inlay_diagnostics_enabled false
define-command -hidden inlay-diagnostics-on %{
lsp-inlay-diagnostics-enable window
set-option window diagnostics_enabled true
set-option window inlay_diagnostics_enabled true
}
define-command -hidden diagnostics-off %{
define-command -hidden inlay-diagnostics-off %{
lsp-inlay-diagnostics-disable window
set-option window diagnostics_enabled false
set-option window inlay_diagnostics_enabled false
}
define-command -hidden diagnostics-toggle %{
define-command -hidden inlay-diagnostics-toggle %{
evaluate-commands %sh{
if [ "$kak_opt_diagnostics_enabled" = "true" ]; then
echo "diagnostics-off"
if [ "$kak_opt_inlay_diagnostics_enabled" = "true" ]; then
echo "inlay-diagnostics-off"
else
echo "diagnostics-on"
echo "inlay-diagnostics-on"
fi
}
}
declare-option -hidden bool inline_diagnostics_enabled true
define-command -hidden inline-diagnostics-on %{
lsp-inline-diagnostics-enable window
set-option window inline_diagnostics_enabled true
}
define-command -hidden inline-diagnostics-off %{
lsp-inline-diagnostics-disable window
set-option window inline_diagnostics_enabled false
}
define-command inline-diagnostics-toggle %{
evaluate-commands %sh{
if [ "$kak_opt_inline_diagnostics_enabled" = "true" ]; then
echo "inline-diagnostics-off"
else
echo "inline-diagnostics-on"
fi
}
}
@ -76,14 +96,11 @@ define-command -hidden lsp-filetype-hooks-update %{
# commands to execute for lsp window settings
lsp-enable-window
inlay-on
try %{
# only map to UI mode if that module is available
map -docstring 'toggle inlay hints' window ui h ': inlay-toggle<ret>'
map -docstring 'toggle inlay diagnostics' window ui d ': diagnostics-toggle<ret>'
} catch %{
map -docstring 'toggle inlay hints' window lsp <a-h> ': inlay-toggle<ret>'
map -docstring 'toggle inlay diagnostics' window lsp <a-d> ': diagnostics-toggle<ret>'
}
# only map to UI mode if that module is available
map -docstring 'toggle inlay hints' window ui h ': inlay-toggle<ret>'
map -docstring 'toggle inlay diagnostics' window ui d ': inlay-diagnostics-toggle<ret>'
map -docstring 'toggle inline diagnostics' window ui e ': inline-diagnostics-toggle<ret>'
trigger-user-hook lsp-enabled
}
}
lsp-filetype-hooks-update
@ -102,7 +119,51 @@ hook -group lsp-filetype-python global BufSetOption filetype=python %{
[basedpyright-langserver.settings.basedpyright.analysis]
typeCheckingMode = "standard"
inlayHints.genericTypes = true
}
}
remove-hooks global lsp-filetype-latex
hook -group lsp-filetype-latex global BufSetOption filetype=latex %{
set-option buffer lsp_servers %{
[texlab]
root_globs = [".git", ".hg"]
[texlab.settings.texlab]
# See https://github.com/latex-lsp/texlab/wiki/Configuration
#
# Preview configuration for zathura with SyncTeX search.
# For other PDF viewers see https://github.com/latex-lsp/texlab/wiki/Previewing
build.onSave = true
forwardSearch.executable = "zathura"
forwardSearch.args = [
"%p",
"--synctex-forward", # Support texlab-forward-search
"%l:1:%f",
"--synctex-editor-command", # Inverse search: use Control+Left-Mouse-Button to jump to source.
"""
sh -c '
echo "
evaluate-commands -client %%opt{texlab_client} %%{
evaluate-commands -try-client %%opt{jumpclient} %%{
edit -- %%{input} %%{line}
}
}
" | kak -p $kak_session
'
""",
]
}
}
remove-hooks global lsp-filetype-javascript
hook -group lsp-filetype-javascript global BufSetOption filetype=(?:javascript|typescript) %{
set-option buffer lsp_servers %{
[typescript-language-server]
root_globs = ["package.json", "tsconfig.json", "jsconfig.json", ".git", ".hg"]
args = ["--stdio"]
settings_section = "_"
[typescript-language-server.settings._]
# quotePreference = "double"
# typescript.format.semicolons = "insert"
}
}
@ -115,3 +176,69 @@ hook -group lsp-filetype-fish global BufSetOption filetype=fish %{
command = "/home/fic/.config/kak/scripts/fish-lsp.fish"
}
}
remove-hooks global lsp-filetype-markdown
hook -group lsp-filetype-markdown global BufSetOption filetype=markdown %{
set-option buffer lsp_servers %{
[marksman]
root_globs = [".marksman.toml", ".git"]
args = ["server"]
[harper-ls]
root_globs = ["*"]
args = ["--stdio"]
command = "harper-ls"
[harper-ls.settings.harper-ls.linters]
LongSentences = false
}
}
remove-hooks global lsp-filetype-typst
hook -group lsp-filetype-typst global BufSetOption filetype=typst %{
set-option buffer lsp_servers %{
[tinymist]
root_globs = [".git", ".hg"]
args = ["lsp"]
settings_section = "_"
[tinymist.settings._]
# See https://myriad-dreamin.github.io/tinymist/configurations.html
exportPdf = "never"
# exportPdf = "onDocumentHasTitle"
formatterMode = "typstyle"
previewFeature = "disable"
[harper-ls]
root_globs = ["*"]
args = ["--stdio"]
command = "harper-ls"
[harper-ls.settings.harper-ls.linters]
LongSentences = false
}
set-option -add buffer lsp_servers "formatterPrintWidth = %opt{autowrap_column}"
}
# # can be empty, global, or file
# declare-option -hidden str harper_add ""
# define-command -hidden harper-add -params 1 %{
# set-option window harper_add %arg{1}
# lsp-code-actions -auto-single
# }
# # can override this to customize what's rendered in the menu
# # Each code action is two args: its name, and the corresponding command
# define-command -override -hidden lsp-perform-code-action -params 1.. -docstring "Called on :lsp-code-actions" %{
# evaluate-commands %sh{
# # harper specific filtering
# if printf '%s' "$kak_opt_lsp_servers" | grep -q 'harper-ls'; then
# if [ "$kak_opt_harper_add" = "global" ]; then
# # filter and keep only
# echo "echo -debug 'harper adding global'"
# fi
# fi
# echo "echo -debug dumping $# code actions args:"
# echo "echo -debug %arg{@}"
# }
# lsp-menu %arg{@}
# }

View file

@ -0,0 +1,287 @@
provide-module notes %~
# Global directory for notes.
declare-option str notes_root_dir "%sh{ echo $HOME/notes/kak }"
# Active directory.
#
# Global directory (`notes_root_dir`) or a local override.
declare-option str notes_active_dir "%opt{notes_root_dir}"
declare-option str notes_sym_todo 'TODO'
declare-option str notes_sym_wip 'WIP'
declare-option str notes_sym_done 'DONE'
declare-option str notes_sym_wontdo 'WONTDO'
declare-option str notes_sym_idea 'IDEA'
declare-option str notes_sym_question 'QUESTION'
declare-option str notes_sym_hold 'HOLD'
declare-option str notes_sym_review 'REVIEW'
declare-option str notes_find 'fd -t file .md'
declare-option -hidden str notes_tasks_list_current_line
declare-option -hidden str notes_journal_now
# Main notes mode.
declare-user-mode notes
# Mode to edit tasks.
declare-user-mode notes-tasks
# Mode to list tasks.
declare-user-mode notes-tasks-list
# Mode to navigate journal.
declare-user-mode notes-journal-nav
# Mode to navigate journal (last journals).
declare-user-mode notes-journal-nav-last
set-face global notes_todo green
set-face global notes_wip blue
set-face global notes_done black
set-face global notes_wontdo black
set-face global notes_idea green
set-face global notes_question cyan
set-face global notes_hold red
set-face global notes_review yellow
set-face global notes_issue cyan+u
set-face global notes_subtask_uncheck green
set-face global notes_subtask_check black
set-face global notes_tag blue+i
# Open the daily journal.
define-command notes-journal-open -docstring 'open daily journal' %{
nop %sh{
mkdir -p "$kak_opt_notes_active_dir/journal/$(date +%Y/%b)"
}
evaluate-commands %{
edit "%opt{notes_active_dir}/journal/%sh{ date '+%Y/%b/%a %d' }.md"
set-option buffer notes_journal_now %sh{ date }
}
}
# Open a journal relative to today.
define-command -hidden notes-journal-open-rel -params -1 %{
nop %sh{
mkdir -p "$kak_opt_notes_active_dir/journal/$(date -d ""$kak_opt_notes_journal_now $1"" +%Y/%b)"
}
evaluate-commands %{
edit -existing "%opt{notes_active_dir}/journal/%sh{ date -d ""$kak_opt_notes_journal_now $1"" ""+%Y/%b/%a %d"" }.md"
set-option buffer notes_journal_now %sh{ date -d """$kak_opt_notes_journal_now $1""" }
}
}
# Open a note by prompting the user with a menu.
define-command notes-open -docstring 'open note' %{
prompt -menu -shell-script-candidates "$kak_opt_notes_find $kak_opt_notes_active_dir/notes" 'open note:' %{
edit %sh{
echo "${kak_text%.md}.md"
}
}
}
# Create a new note by prompting the user for its text.
define-command notes-new-note -docstring 'new note' %{
prompt note: %{
edit %sh{
echo "$kak_opt_notes_active_dir/notes/${kak_text%.md}.md"
}
}
}
# Archive a note by prompting the user for which note to operate on.
define-command notes-archive-note -docstring 'archive note' %{
prompt -menu -shell-script-candidates "$kak_opt_notes_find $kak_opt_notes_active_dir/notes" archive: %{
nop %sh{
mkdir -p "$kak_opt_notes_active_dir/archives"
mv "$kak_text" "$kak_opt_notes_active_dir/archives/"
}
}
}
# Prompt the user to pick and open an archived note.
define-command notes-archive-open -docstring 'open archive' %{
prompt -menu -shell-script-candidates "$kak_opt_notes_find $kak_opt_notes_active_dir/archives" 'open archive:' %{
edit %sh{
echo "${kak_text%.md}.md"
}
}
}
# Capture a new note.
define-command notes-capture -docstring 'capture' %{
prompt capture: %{
nop %sh{
echo -e "> $(date '+%a %b %d %Y, %H:%M:%S')\n$kak_text\n" >> "$kak_opt_notes_active_dir/capture.md"
}
}
}
# Open the capture file.
define-command notes-open-capture -docstring 'open capture' %{
edit "%opt{notes_active_dir}/capture.md"
}
# Switch the status of a note to the input parameter.
define-command notes-task-switch-status -params 1 -docstring 'switch task' %{
execute-keys -draft "gif<space>e_c%arg{1}"
}
# Open a GitHub issue. This requires a specific formatting of the file.
define-command notes-task-gh-open-issue -docstring 'open GitHub issue' %{
evaluate-commands -save-regs 'il' %{
try %{
execute-keys -draft '<a-i>w"iy'
execute-keys -draft '%sgithub_project: <ret>;<a-W>_"ly'
nop %sh{
open "https://github.com/$kak_reg_l/issues/$kak_reg_i"
}
}
}
}
define-command -hidden notes-tasks-list-by-regex -params 1 -docstring 'list tasks by status' %{
edit -scratch *notes-tasks-list*
unset-option buffer notes_tasks_list_current_line
execute-keys "%%d|rg -n --column -e '%arg{1}' '%opt{notes_active_dir}/notes' '%opt{notes_active_dir}/journal' '%opt{notes_active_dir}/capture.md'<ret>|sort<ret>gg"
}
# List all tasks.
define-command notes-tasks-list-all -docstring 'list all tasks' %{
notes-tasks-list-by-regex "%opt{notes_sym_todo}|%opt{notes_sym_wip}|%opt{notes_sym_done}|%opt{notes_sym_wontdo}|%opt{notes_sym_idea}|%opt{notes_sym_question}|%opt{notes_sym_hold}"
}
# Command executed when pressing <ret> in a *notes-tasks-list* buffer.
define-command -hidden notes-tasks-list-open %{
set-option buffer notes_tasks_list_current_line %val{cursor_line}
execute-keys -with-hooks -save-regs 'flc' 'giT:"fyllT:"lyllT:"cy:edit "%reg{f}" %reg{l} %reg{c}<ret>'
}
# Run a grepper with the provided arguments as search query.
define-command -hidden notes-grepcmd -params 2 %{
# Initial implementation based on rg <pattern> <path>.
execute-keys ":grep %arg{2} %arg{1}<ret>"
}
# Prompt the user for terms to search in notes, journals, archives and the
# capture file.
define-command notes-search -docstring 'search notes' %{
prompt 'search notes:' %{
notes-grepcmd "%opt{notes_active_dir}" "%val{text}"
}
}
# Synchronize notes remotely.
define-command notes-sync -docstring 'synchronize notes' %{
# First, we always check-in new modifications; then, we check whether we have anything else to send
info -title 'notes' 'starting synchronizing…'
nop %sh{
cd $kak_opt_notes_active_dir
git fetch --prune origin
git rebase --autostash origin/master
git add -A .
git commit -m "$(date +'Sync update %a %b %d %Y')"
git push origin
}
info -title 'notes' 'finished synchronizing'
}
# Toggle overriding the active directory with pwd and vice versa.
define-command notes-override-active-dir -docstring 'override the active directory with PWD' %{
set-option global notes_active_dir %sh{
dir=$(pwd)
if [ "$kak_opt_notes_active_dir" == "$dir" ]; then
echo "$kak_opt_notes_root_dir"
else
echo "$dir"
fi
}
info -title notes "active dir: %opt{notes_active_dir}"
}
add-highlighter shared/notes-tasks group
add-highlighter shared/notes-tasks/todo regex "(%opt{notes_sym_todo})" 1:notes_todo
add-highlighter shared/notes-tasks/wip regex "(%opt{notes_sym_wip})" 1:notes_wip
add-highlighter shared/notes-tasks/done regex "(%opt{notes_sym_done})" 1:notes_done
add-highlighter shared/notes-tasks/wontdo regex "(%opt{notes_sym_wontdo})" 1:notes_wontdo
add-highlighter shared/notes-tasks/idea regex "(%opt{notes_sym_idea})" 1:notes_idea
add-highlighter shared/notes-tasks/question regex "(%opt{notes_sym_question})" 1:notes_question
add-highlighter shared/notes-tasks/hold regex "(%opt{notes_sym_hold})" 1:notes_hold
add-highlighter shared/notes-tasks/review regex "(%opt{notes_sym_review})" 1:notes_review
add-highlighter shared/notes-tasks/issue regex " (#[0-9]+)" 1:notes_issue
add-highlighter shared/notes-tasks/subtask-uncheck regex "-\s* (\[ \])[^\n]*" 1:notes_subtask_uncheck
add-highlighter shared/notes-tasks/subtask-check regex "-\s* (\[x\])\s*([^\n]*)"\
1:notes_subtask_check
add-highlighter shared/notes-tasks-list group
add-highlighter shared/notes-tasks-list/path regex "^((?:\w:)?[^:\n]+):(\d+):(\d+)?" 1:green 2:blue 3:blue
add-highlighter shared/notes-tasks-list/current-line line %{%opt{notes_tasks_list_current_line}} default+b
map global user o ':enter-user-mode notes<ret>' -docstring 'notes'
map global notes A ':notes-archive-note<ret>' -docstring 'archive note'
map global notes a ':notes-archive-open<ret>' -docstring 'open archived note'
map global notes C ':notes-capture<ret>' -docstring 'capture'
map global notes c ':notes-open-capture<ret>' -docstring 'open capture'
map global notes j ':notes-journal-open<ret>' -docstring 'open journal'
map global notes J ':enter-user-mode notes-journal-nav<ret>' -docstring 'navigate journals'
map global notes l ':enter-user-mode notes-tasks-list<ret>' -docstring 'tasks list'
map global notes N ':notes-new-note<ret>' -docstring 'new note'
map global notes n ':notes-open<ret>' -docstring 'open note'
map global notes / ':notes-search<ret>' -docstring 'search in notes'
map global notes S ':notes-sync<ret>' -docstring 'synchronize notes'
map global notes t ':enter-user-mode notes-tasks<ret>' -docstring 'tasks'
map global notes z ':notes-override-active-dir<ret>' -docstring 'switch notes dir with PWD'
map global notes-journal-nav l ':enter-user-mode notes-journal-nav-last<ret>' -docstring 'last…'
map global notes-journal-nav d ':notes-journal-open-rel "-1 day"<ret>' -docstring 'day before'
map global notes-journal-nav D ':notes-journal-open-rel "+1 day"<ret>' -docstring 'day after'
map global notes-journal-nav w ':notes-journal-open-rel "-1 week"<ret>' -docstring 'week before'
map global notes-journal-nav W ':notes-journal-open-rel "+1 week"<ret>' -docstring 'week after'
map global notes-journal-nav m ':notes-journal-open-rel "-1 month"<ret>' -docstring 'month before'
map global notes-journal-nav M ':notes-journal-open-rel "+1 month"<ret>' -docstring 'month after'
map global notes-journal-nav-last m ':notes-journal-open-rel "last monday"<ret>' -docstring 'monday'
map global notes-journal-nav-last t ':notes-journal-open-rel "last tuesday"<ret>' -docstring 'tuesday'
map global notes-journal-nav-last w ':notes-journal-open-rel "last wednesday"<ret>' -docstring 'wednesday'
map global notes-journal-nav-last h ':notes-journal-open-rel "last thursday"<ret>' -docstring 'thursday'
map global notes-journal-nav-last f ':notes-journal-open-rel "last friday"<ret>' -docstring 'friday'
map global notes-journal-nav-last T ':notes-journal-open-rel "last saturday"<ret>' -docstring 'saturday'
map global notes-journal-nav-last S ':notes-journal-open-rel "last sunday"<ret>' -docstring 'sunday'
map global notes-tasks-list a ":notes-tasks-list-all<ret>" -docstring 'list all tasks'
map global notes-tasks-list d ":notes-tasks-list-by-regex %opt{notes_sym_done}<ret>" -docstring 'list done tasks'
map global notes-tasks-list h ":notes-tasks-list-by-regex %opt{notes_sym_hold}<ret>" -docstring 'list hold tasks'
map global notes-tasks-list i ":notes-tasks-list-by-regex %opt{notes_sym_idea}<ret>" -docstring 'list ideas'
map global notes-tasks-list l ":notes-tasks-list-by-regex '\ :[^:]+:'<ret>" -docstring 'list tasks by labels'
map global notes-tasks-list n ":notes-tasks-list-by-regex %opt{notes_sym_wontdo}<ret>" -docstring 'list wontdo tasks'
map global notes-tasks-list q ":notes-tasks-list-by-regex %opt{notes_sym_question}<ret>" -docstring 'list questions'
map global notes-tasks-list r ":notes-tasks-list-by-regex %opt{notes_sym_review}<ret>" -docstring 'list reviews'
map global notes-tasks-list t ":notes-tasks-list-by-regex %opt{notes_sym_todo}<ret>" -docstring 'list todo tasks'
map global notes-tasks-list w ":notes-tasks-list-by-regex %opt{notes_sym_wip}<ret>" -docstring 'list wip tasks'
hook -group notes-tasks global WinCreate \*notes-tasks-list\* %{
map buffer normal '<ret>' ':notes-tasks-list-open<ret>'
add-highlighter window/ ref notes-tasks
add-highlighter window/ ref notes-tasks-list
}
hook -group notes-tasks global WinCreate .*\.md %{
add-highlighter window/ ref notes-tasks
map window notes-tasks d ":notes-task-switch-status %opt{notes_sym_done}<ret>" -docstring 'switch task to done'
map window notes-tasks h ":notes-task-switch-status %opt{notes_sym_hold}<ret>" -docstring 'switch task to hold'
map window notes-tasks i ":notes-task-switch-status %opt{notes_sym_idea}<ret>" -docstring 'switch task to idea'
map window notes-tasks n ":notes-task-switch-status %opt{notes_sym_wontdo}<ret>" -docstring 'switch task to wontdo'
map window notes-tasks q ":notes-task-switch-status %opt{notes_sym_question}<ret>" -docstring 'switch task to question'
map window notes-tasks <ret> ":notes-task-gh-open-issue<ret>" -docstring 'open GitHub issue'
map window notes-tasks r ":notes-task-switch-status %opt{notes_sym_review}<ret>" -docstring 'switch task to review'
map window notes-tasks t ":notes-task-switch-status %opt{notes_sym_todo}<ret>" -docstring 'switch task to todo'
map window notes-tasks w ":notes-task-switch-status %opt{notes_sym_wip}<ret>" -docstring 'switch task to wip'
}
~

View file

@ -95,7 +95,7 @@ bundle-noload kakoune-text-objects https://github.com/Delapouite/kakoune-text-ob
bundle smarttab.kak https://github.com/andreyorst/smarttab.kak %{
require-module smarttab
set-option global softtabstop 2
hook global BufCreate .* %{
hook global WinSetOption filetype=.* %{
editorconfig-load
autoconfigtab
}

View file

@ -1 +0,0 @@
/usr/share/kak/rc/detection/editorconfig.kak

View file

@ -1 +0,0 @@
/usr/share/kak/rc/filetype/just.kak

View file

@ -1,12 +1,14 @@
evaluate-commands %sh{ kak-tree-sitter -dks --init $kak_session }
evaluate-commands %sh{kak-popup init}
colorscheme ashen
require-module hop-kak
require-module fishr
require-module surround
require-module ficgrep
require-module byline
require-module spell
require-module title-bar
require-module notes
set-option global scrolloff 3,3
require-module ui-mode
@ -93,25 +95,16 @@ map -docstring 'case insensitive backward extend-search' global user '<a-?>' <a-
map -docstring 'Select to file end' global user N "Gj<a-L>L"
map -docstring 'Extend to file end' global user n "gj<a-l>l"
# Zathura pdf preview only for Typst files
hook global WinSetOption filetype=typst %{
define-command -docstring %{
Spawns a Zathura pdf preview and Typst watcher for the currently open Typst file
} typst %{
nop %sh{
{
"$kak_config/scripts/kak-typ-zathura.fish" -k -w "$kak_buffile" "$kak_client_pid"
} > /dev/null 2>&1 < /dev/null &
}
}
}
define-command -docstring "Create a scratch buffer" scratch %{
edit -scratch
}
alias global s scratch
define-command -params 1 -docstring "Set buffer filetype" filetype %{
set-option buffer filetype %arg{1}
}
define-command -docstring "New terminal in cwd" cwd-terminal %{
terminal fish
}
@ -156,12 +149,21 @@ define-command -override -hidden consume %{
}
}
define-command terminal-consume %{
terminal dash -c 'niri msg action consume-or-expel-window-left; exec fish'
}
alias global tc terminal-consume
define-command -docstring %{
Create a new client in vertial split
} newv %{
} new-consume %{
new consume
}
alias global nc new-consume
alias global n new
# jumplist
map -docstring 'jump forward' global normal <c-f> <c-i>
@ -169,3 +171,22 @@ map -docstring 'save to jumplist' global normal <c-v> <c-s>
# selection saving
map -docstring 'add selection' global normal Y <a-Z>a
define-command -docstring 'open popup shell' popup-shell %{
popup fish
}
alias global pp popup-shell
map -docstring 'popup shell' global user . ': popup-shell<ret>'
# hook -once global ClientCreate .* %{
# evaluate-commands %sh{
# if [ "$kak_buflist" != "*debug* *scratch*" ]; then
# echo "delete-buffer *scratch*"
# else
# echo "echo -debug dumping buffers"
# echo "echo -debug %val{buflist}"
# fi
# }
# }

View file

@ -0,0 +1 @@
/home/fic/dev/kak-lsp-diags/lsp-diags.py

132
.config/kak/scripts/lsp-diags_.py Executable file
View file

@ -0,0 +1,132 @@
#!/usr/bin/env python
# pyright: basic, reportUnusedCallResult=false
import atexit
import sys
import os
import tempfile
import signal
Position = tuple[int, int]
SpecList = list[tuple[Position, Position]]
diagnostics: SpecList = []
def parse_specs(data: str):
parsed: SpecList = []
for entry in data.strip().split():
if not entry or len(entry) < 9:
continue
range_part, _ = entry.split("|", 1)
start_str, end_str = range_part.split(",")
sl, sc = map(int, start_str.split("."))
el, ec = map(int, end_str.split("."))
parsed.append(((sl, sc), (el, ec)))
return parsed
def is_cursor_in_any(cursor: Position, diagnostics: SpecList) -> bool:
cl, cc = cursor
for (sl, sc), (el, ec) in diagnostics:
if cl < sl or cl > el:
continue
if sl == el:
if cl == sl and sc <= cc <= ec:
return True
elif cl == sl:
if cc >= sc:
return True
elif cl == el:
if cc <= ec:
return True
elif sl < cl < el:
return True
return False
def cleanup(inp: str, outp: str, dir: str):
# subprocess.run(["notify-send", "cleanup runs"])
try:
os.remove(inp)
os.remove(outp)
os.rmdir(dir)
except FileNotFoundError:
pass
def gen_kakoune_output(inp: str, outp: str) -> str:
return f"declare-option -hidden str diagpipe_in {inp}\ndeclare-option -hidden str diagpipe_out {outp}"
def daemonize(inp: str, outp: str, dir: str):
# fork and exit parent
if os.fork() > 0:
sys.exit(0)
# new session
os.setsid()
if os.fork() > 0:
# exit first child
sys.exit(0)
# redirect IO to /dev/null
with open("/dev/null", "rb", 0) as dn:
os.dup2(dn.fileno(), sys.stdin.fileno())
with open("/dev/null", "ab", 0) as dn:
os.dup2(dn.fileno(), sys.stdout.fileno())
os.dup2(dn.fileno(), sys.stderr.fileno())
_ = atexit.register(lambda: cleanup(inp, outp, dir))
def on_exit(*_):
# cleanup(inp, outp, dir)
sys.exit(0)
signal.signal(signal.SIGTERM, on_exit)
signal.signal(signal.SIGINT, on_exit)
def main():
# subprocess.run(["notify-send", "begin loop"])
# create unique directory and names
fifo_dir = tempfile.mkdtemp(prefix="diagpipe-")
in_path = os.path.join(fifo_dir, "in")
out_path = os.path.join(fifo_dir, "out")
# create fifos
os.mkfifo(in_path)
os.mkfifo(out_path)
output = gen_kakoune_output(in_path, out_path)
print(output)
sys.stdout.flush()
daemonize(in_path, out_path, fifo_dir)
with open(in_path, "r") as infile, open(out_path, "w") as outfile:
diagnostics: SpecList = []
while True:
line = infile.readline()
if not line:
continue
line = line.strip()
assert isinstance(line, str)
# # subprocess.run(["notify-send", f"Received command: {line}"])
if line.startswith("set "):
# subprocess.run(["notify-send", f"Received set: {line}"])
_, payload = line.split(" ", 1)
diagnostics = parse_specs(payload)
_ = outfile.write("ok\n")
outfile.flush()
elif line.startswith("query "):
_, pos = line.split(" ", 1)
l, c = map(int, pos.strip().split())
result = is_cursor_in_any((l, c), diagnostics)
_ = outfile.write("true\n" if result else "false\n")
outfile.flush()
elif line.startswith("exit"):
# subprocess.run(["notify-send", "exit received"])
sys.exit(0)
if __name__ == "__main__":
main()

View file

@ -2,14 +2,14 @@
"version": 2,
"data": {
"codebook": {
"version": "0.3.0",
"gitref": "refs/tags/v0.3.0",
"url": "https://github.com/blopker/codebook/releases/tag/v0.3.0"
"version": "0.3.2",
"gitref": "refs/tags/v0.3.2",
"url": "https://github.com/blopker/codebook/releases/tag/v0.3.2"
},
"iwe": {
"version": "iwe-v0.0.32",
"gitref": "refs/tags/iwe-v0.0.32",
"url": "https://github.com/iwe-org/iwe/releases/tag/iwe-v0.0.32"
"version": "iwe-v0.0.33",
"gitref": "refs/tags/iwe-v0.0.33",
"url": "https://github.com/iwe-org/iwe/releases/tag/iwe-v0.0.33"
},
"kak-tree-sitter": {
"version": "2.0.0",

View file

@ -2,14 +2,14 @@
"version": 2,
"data": {
"codebook": {
"version": "0.3.0",
"gitref": "refs/tags/v0.3.0",
"url": "https://github.com/blopker/codebook/releases/tag/v0.3.0"
"version": "0.3.2",
"gitref": "refs/tags/v0.3.2",
"url": "https://github.com/blopker/codebook/releases/tag/v0.3.2"
},
"iwe": {
"version": "iwe-v0.0.32",
"gitref": "refs/tags/iwe-v0.0.32",
"url": "https://github.com/iwe-org/iwe/releases/tag/iwe-v0.0.32"
"version": "iwe-v0.0.33",
"gitref": "refs/tags/iwe-v0.0.33",
"url": "https://github.com/iwe-org/iwe/releases/tag/iwe-v0.0.33"
},
"kak-tree-sitter": {
"version": "2.0.0",

View file

@ -7,9 +7,9 @@
"url": "https://github.com/blopker/codebook/releases/tag/v0.3.0"
},
"iwe": {
"version": "iwe-v0.0.31",
"gitref": "refs/tags/iwe-v0.0.31",
"url": "https://github.com/iwe-org/iwe/releases/tag/iwe-v0.0.31"
"version": "iwe-v0.0.33",
"gitref": "refs/tags/iwe-v0.0.33",
"url": "https://github.com/iwe-org/iwe/releases/tag/iwe-v0.0.33"
},
"kak-tree-sitter": {
"version": "2.0.0",

View file

@ -8,3 +8,7 @@ config_version: 2
settings:
content.javascript.clipboard:
https://github.com: access-paste
statusbar.show:
global: always
tabs.position:
global: top

View file

@ -22,8 +22,6 @@ c.completion.open_categories = [
"filesystem",
]
# c.hints.chars = "tnserigm"
# c.hints.chars = "tnseripldh"
c.hints.chars = "tnserigmao"
# dark mode
@ -36,14 +34,15 @@ c.colors.webpage.preferred_color_scheme = "dark"
# searches
c.url.searchengines["DEFAULT"] = "https://www.startpage.com/sp/search?query={}"
c.url.searchengines["!d"] = "https://duckduckgo.com/?q={}"
c.url.searchengines["!aw"] = "https://wiki.archlinux.org/?search={}"
c.url.searchengines["!g"] = (
c.url.searchengines["d"] = "https://duckduckgo.com/?q={}"
c.url.searchengines["aw"] = "https://wiki.archlinux.org/?search={}"
c.url.searchengines["g"] = (
"http://www.google.com/search?hl=en&source=hp&ie=ISO-8859-l&q={}"
)
c.url.searchengines["ap"] = "https://www.archlinux.org/packages/?sort=&q={}"
# with config.pattern("chatgpt.com") as p:
# p.bindings.commands["normal"]["<Escape>"] = "click-element css main"
c.url.searchengines["w"] = (
"https://en.wikipedia.org/w/index.php?title=Special:Search&search={}"
)
config.bind(
"<Shift-Escape>",
"mode-leave ;; jseval -q document.activeElement.blur()",
@ -58,6 +57,9 @@ config.bind(
sets = {
"normal": [
["tT", "config-cycle tabs.position top left"],
["sH", "config-cycle statusbar.show always never"],
["\\", "mode-enter passthrough"],
["m", "scroll left"],
["n", "scroll down"],
["e", "scroll up"],
@ -72,7 +74,12 @@ sets = {
["k", "quickmark-save"],
["J", "search-prev"],
["j", "search-next"],
["<Ctrl-/>", "hint links spawn --detach mpv {hint-url}"],
[
";/",
"hint links spawn --detach mpv --force-window --quiet --keep-open=yes --ytdl {hint-url}",
],
["<Ctrl-/>", "spawn --userscript view_in_mpv"],
# ["<Ctrl-?>", "hint links spawn --userscript view_in_mpv"],
["gm", "tab-focus 1"],
["gi", "tab-focus -1"],
["gN", "tab-move +"],
@ -140,6 +147,14 @@ ashen = {
"g_12": "#151515",
}
c.tabs.padding = {"top": 5, "bottom": 5, "left": 9, "right": 9}
# c.colors.statusbar.normal.bg = "#00000000"
# c.colors.statusbar.command.bg = "#00000000"
# c.colors.tabs.even.bg = "#00000000" # transparent tabs!!
# c.colors.tabs.odd.bg = "#00000000"
# c.colors.tabs.bar.bg = "#00000000"
# # colors
# c.colors.completion.fg = ashen["text"]
# c.colors.completion.category.fg = "#F2F2F2"

View file

@ -0,0 +1,64 @@
#!/usr/bin/env python3
import os
import html
import re
import sys
import xml.etree.ElementTree as ET
try:
import pyperclip
except ImportError:
try:
import pyclip as pyperclip
except ImportError:
PYPERCLIP = False
else:
PYPERCLIP = True
else:
PYPERCLIP = True
def parse_text_content(element):
# https://stackoverflow.com/a/35591507/15245191
magic = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" [
<!ENTITY nbsp ' '>
]>'''
root = ET.fromstring(magic + element)
text = ET.tostring(root, encoding="unicode", method="text")
text = html.unescape(text)
return text
def send_command_to_qute(command):
with open(os.environ.get("QUTE_FIFO"), "w") as f:
f.write(command)
def main():
delimiter = sys.argv[1] if len(sys.argv) > 1 else ";"
# For info on qute environment vairables, see
# https://github.com/qutebrowser/qutebrowser/blob/master/doc/userscripts.asciidoc
element = os.environ.get("QUTE_SELECTED_HTML")
code_text = parse_text_content(element)
re_remove_dollars = re.compile(r"^(\$ )", re.MULTILINE)
code_text = re.sub(re_remove_dollars, '', code_text)
if PYPERCLIP:
pyperclip.copy(code_text)
send_command_to_qute(
"message-info 'copied to clipboard: {info}{suffix}'".format(
info=code_text.splitlines()[0].replace("'", "\""),
suffix="..." if len(code_text.splitlines()) > 1 else ""
)
)
else:
# Qute's yank command won't copy accross multiple lines so we
# compromise by placing lines on a single line seperated by the
# specified delimiter
code_text = re.sub("(\n)+", delimiter, code_text)
code_text = code_text.replace("'", "\"")
send_command_to_qute("yank inline '{code}'\n".format(code=code_text))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,68 @@
#!/usr/bin/env python3
"""Qutebrowser userscript scraping the current web page for DOIs and downloading
corresponding bibtex information.
Set the environment variable 'QUTE_BIB_FILEPATH' to indicate the path to
download to. Otherwise, bibtex information is downloaded to '/tmp' and hence
deleted at reboot.
Installation: see qute://help/userscripts.html
Inspired by
https://ocefpaf.github.io/python4oceanographers/blog/2014/05/19/doi2bibtex/
"""
import os
import sys
import re
from collections import Counter
from urllib import parse as url_parse
from urllib import request as url_request
FIFO_PATH = os.getenv("QUTE_FIFO")
def message_fifo(message, level="warning"):
"""Send message to qutebrowser FIFO. The level must be one of 'info',
'warning' (default) or 'error'."""
with open(FIFO_PATH, "w") as fifo:
fifo.write("message-{} '{}'".format(level, message))
source = os.getenv("QUTE_TEXT")
with open(source) as f:
text = f.read()
# find DOIs on page using regex
dval = re.compile(r'(10\.(\d)+/([^(\s\>\"\<)])+)')
# https://stackoverflow.com/a/10324802/3865876, too strict
# dval = re.compile(r'\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])\S)+)\b')
dois = dval.findall(text)
dois = Counter(e[0] for e in dois)
try:
doi = dois.most_common(1)[0][0]
except IndexError:
message_fifo("No DOIs found on page")
sys.exit()
message_fifo("Found {} DOIs on page, selecting {}".format(len(dois), doi),
level="info")
# get bibtex data corresponding to DOI
url = "https://dx.doi.org/" + url_parse.quote(doi)
headers = dict(Accept='text/bibliography; style=bibtex')
request = url_request.Request(url, headers=headers)
response = url_request.urlopen(request)
status_code = response.getcode()
if status_code >= 400:
message_fifo("Request returned {}".format(status_code))
sys.exit()
# obtain content and format it
bibtex = response.read().decode("utf-8").strip()
bibtex = bibtex.replace(" ", "\n ", 1).\
replace("}, ", "},\n ").replace("}}", "}\n}")
# append to file
bib_filepath = os.getenv("QUTE_BIB_FILEPATH", "/tmp/qute.bib")
with open(bib_filepath, "a") as f:
f.write(bibtex + "\n\n")

View file

@ -0,0 +1,9 @@
#!/usr/bin/env bash
if [[ $1 -eq 'list' ]] && [[ -z $QUTE_COUNT ]];
then
PORTS="$(ss -nltp | tail -n +2 | awk '{print $4}' | awk -F: '{print $2}')"
QUTE_COUNT=$(echo "$PORTS" | dmenu )
fi
echo open -t localhost:${QUTE_COUNT:-8080} > $QUTE_FIFO

View file

@ -0,0 +1,308 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: Chris Braun (cryzed) <cryzed@googlemail.com>
#
# SPDX-License-Identifier: GPL-3.0-or-later
"""
Insert login information using Bitwarden CLI and a dmenu-compatible application
(e.g. dmenu, rofi -dmenu, ...).
"""
USAGE = """The domain of the site has to be in the name of the Bitwarden entry, for example: "github.com/cryzed" or
"websites/github.com". The login information is inserted by emulating key events using qutebrowser's fake-key command in this manner:
[USERNAME]<Tab>[PASSWORD], which is compatible with almost all login forms.
If enabled, with the `--totp` flag, it will also move the TOTP code to the
clipboard, much like the Firefox add-on.
You must log into Bitwarden CLI using `bw login` prior to use of this script.
The session key will be stored using keyctl for the number of seconds passed to
the --auto-lock option.
To use in qutebrowser, run: `spawn --userscript qute-bitwarden`
"""
EPILOG = """Dependencies: tldextract (Python 3 module), pyperclip (optional
Python module, used for TOTP codes), Bitwarden CLI (1.7.4 is known to work
but older versions may well also work)
WARNING: The login details are viewable as plaintext in qutebrowser's debug log
(qute://log) and might be shared if you decide to submit a crash report!"""
import argparse
import enum
import functools
import os
import shlex
import subprocess
import sys
import json
import tldextract
argument_parser = argparse.ArgumentParser(
description=__doc__,
usage=USAGE,
epilog=EPILOG,
)
argument_parser.add_argument('url', nargs='?', default=os.getenv('QUTE_URL'))
argument_parser.add_argument('--dmenu-invocation', '-d', default='rofi -dmenu -i -p Bitwarden',
help='Invocation used to execute a dmenu-provider')
argument_parser.add_argument('--password-prompt-invocation', '-p', default='rofi -dmenu -p "Master Password" -password -lines 0',
help='Invocation used to prompt the user for their Bitwarden password')
argument_parser.add_argument('--no-insert-mode', '-n', dest='insert_mode', action='store_false',
help="Don't automatically enter insert mode")
argument_parser.add_argument('--totp', '-t', action='store_true',
help="Copy TOTP key to clipboard")
argument_parser.add_argument('--io-encoding', '-i', default='UTF-8',
help='Encoding used to communicate with subprocesses')
argument_parser.add_argument('--merge-candidates', '-m', action='store_true',
help='Merge pass candidates for fully-qualified and registered domain name')
argument_parser.add_argument('--auto-lock', type=int, default=900,
help='Automatically lock the vault after this many seconds')
group = argument_parser.add_mutually_exclusive_group()
group.add_argument('--username-only', '-e',
action='store_true', help='Only insert username')
group.add_argument('--password-only', '-w',
action='store_true', help='Only insert password')
group.add_argument('--totp-only', '-T',
action='store_true', help='Only insert totp code')
stderr = functools.partial(print, file=sys.stderr)
class ExitCodes(enum.IntEnum):
SUCCESS = 0
FAILURE = 1
# 1 is automatically used if Python throws an exception
NO_PASS_CANDIDATES = 2
COULD_NOT_MATCH_USERNAME = 3
COULD_NOT_MATCH_PASSWORD = 4
def qute_command(command):
with open(os.environ['QUTE_FIFO'], 'w') as fifo:
fifo.write(command + '\n')
fifo.flush()
def ask_password(password_prompt_invocation):
process = subprocess.run(
shlex.split(password_prompt_invocation),
text=True,
stdout=subprocess.PIPE,
)
if process.returncode > 0:
raise Exception('Could not unlock vault')
master_pass = process.stdout.strip()
return subprocess.check_output(
['bw', 'unlock', '--raw', '--passwordenv', 'BW_MASTERPASS'],
env={**os.environ, 'BW_MASTERPASS': master_pass},
text=True,
).strip()
def get_session_key(auto_lock, password_prompt_invocation):
if auto_lock == 0:
subprocess.call(['keyctl', 'purge', 'user', 'bw_session'])
return ask_password(password_prompt_invocation)
else:
process = subprocess.run(
['keyctl', 'request', 'user', 'bw_session'],
text=True,
stdout=subprocess.PIPE,
)
key_id = process.stdout.strip()
if process.returncode > 0:
session = ask_password(password_prompt_invocation)
if not session:
raise Exception('Could not unlock vault')
key_id = subprocess.check_output(
['keyctl', 'add', 'user', 'bw_session', session, '@u'],
text=True,
).strip()
if auto_lock > 0:
subprocess.call(['keyctl', 'timeout', str(key_id), str(auto_lock)])
return subprocess.check_output(
['keyctl', 'pipe', str(key_id)],
text=True,
).strip()
def pass_(domain, encoding, auto_lock, password_prompt_invocation):
session_key = get_session_key(auto_lock, password_prompt_invocation)
process = subprocess.run(
['bw', 'list', 'items', '--nointeraction', '--session', session_key, '--url', domain],
capture_output=True,
)
err = process.stderr.decode(encoding).strip()
if err:
msg = 'Bitwarden CLI returned for {:s} - {:s}'.format(domain, err)
stderr(msg)
if "Vault is locked" in err:
stderr("Bitwarden Vault got locked, trying again with clean session")
return pass_(domain, encoding, 0, password_prompt_invocation)
if process.returncode:
return '[]'
out = process.stdout.decode(encoding).strip()
return out
def get_totp_code(selection_id, domain_name, encoding, auto_lock, password_prompt_invocation):
session_key = get_session_key(auto_lock, password_prompt_invocation)
process = subprocess.run(
['bw', 'get', 'totp', '--nointeraction', '--session', session_key, selection_id],
capture_output=True,
)
err = process.stderr.decode(encoding).strip()
if err:
# domain_name instead of selection_id to make it more user-friendly
msg = 'Bitwarden CLI returned for {:s} - {:s}'.format(domain_name, err)
stderr(msg)
if "Vault is locked" in err:
stderr("Bitwarden Vault got locked, trying again with clean session")
return get_totp_code(selection_id, domain_name, encoding, 0, password_prompt_invocation)
if process.returncode:
return '[]'
out = process.stdout.decode(encoding).strip()
return out
def dmenu(items, invocation, encoding):
command = shlex.split(invocation)
process = subprocess.run(command, input='\n'.join(
items).encode(encoding), stdout=subprocess.PIPE)
return process.stdout.decode(encoding).strip()
def fake_key_raw(text):
for character in text:
# Escape all characters by default, space requires special handling
sequence = '" "' if character == ' ' else r'\{}'.format(character)
qute_command('fake-key {}'.format(sequence))
def main(arguments):
if not arguments.url:
argument_parser.print_help()
return ExitCodes.FAILURE
extract_result = tldextract.extract(arguments.url)
# Try to find candidates using targets in the following order: fully-qualified domain name (includes subdomains),
# the registered domain name and finally: the IPv4 address if that's what
# the URL represents
candidates = []
for target in filter(
None,
[
extract_result.fqdn,
(
extract_result.top_domain_under_public_suffix
if hasattr(extract_result, "top_domain_under_public_suffix")
else extract_result.registered_domain
),
extract_result.subdomain + "." + extract_result.domain,
extract_result.domain,
extract_result.ipv4,
],
):
target_candidates = json.loads(
pass_(
target,
arguments.io_encoding,
arguments.auto_lock,
arguments.password_prompt_invocation,
)
)
if not target_candidates:
continue
candidates = candidates + target_candidates
if not arguments.merge_candidates:
break
else:
if not candidates:
stderr('No pass candidates for URL {!r} found!'.format(
arguments.url))
return ExitCodes.NO_PASS_CANDIDATES
if len(candidates) == 1:
selection = candidates.pop()
else:
choices = ['{:s} | {:s}'.format(c['name'], c['login']['username']) for c in candidates]
choice = dmenu(choices, arguments.dmenu_invocation, arguments.io_encoding)
choice_tokens = choice.split('|')
choice_name = choice_tokens[0].strip()
choice_username = choice_tokens[1].strip()
selection = next((c for (i, c) in enumerate(candidates)
if c['name'] == choice_name
and c['login']['username'] == choice_username),
None)
# Nothing was selected, simply return
if not selection:
return ExitCodes.SUCCESS
username = selection['login']['username']
password = selection['login']['password']
totp = selection['login']['totp']
if arguments.username_only:
fake_key_raw(username)
elif arguments.password_only:
fake_key_raw(password)
elif arguments.totp_only:
# No point in moving it to the clipboard in this case
fake_key_raw(
get_totp_code(
selection['id'],
selection['name'],
arguments.io_encoding,
arguments.auto_lock,
arguments.password_prompt_invocation,
)
)
else:
# Enter username and password using fake-key and <Tab> (which seems to work almost universally), then switch
# back into insert-mode, so the form can be directly submitted by
# hitting enter afterwards
fake_key_raw(username)
qute_command('fake-key <Tab>')
fake_key_raw(password)
if arguments.insert_mode:
qute_command('mode-enter insert')
# If it finds a TOTP code, it copies it to the clipboard,
# which is the same behavior as the Firefox add-on.
if not arguments.totp_only and totp and arguments.totp:
# The import is done here, to make pyperclip an optional dependency
import pyperclip
pyperclip.copy(
get_totp_code(
selection['id'],
selection['name'],
arguments.io_encoding,
arguments.auto_lock,
arguments.password_prompt_invocation,
)
)
return ExitCodes.SUCCESS
if __name__ == '__main__':
arguments = argument_parser.parse_args()
sys.exit(main(arguments))

View file

@ -0,0 +1,66 @@
#!/usr/bin/env python3
#
# Executes python-readability on current page and opens the summary as new tab.
#
# Depends on the python-readability package, or its fork:
#
# - https://github.com/buriy/python-readability
# - https://github.com/bookieio/breadability
#
# Usage:
# :spawn --userscript readability
#
import codecs, os
tmpfile = os.path.join(
os.environ.get('QUTE_DATA_DIR',
os.path.expanduser('~/.local/share/qutebrowser')),
'userscripts/readability.html')
if not os.path.exists(os.path.dirname(tmpfile)):
os.makedirs(os.path.dirname(tmpfile))
# Styling for dynamic window margin scaling and line height
HEADER = """
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>%s</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<style type="text/css">
body {
margin: 40px auto;
max-width: 650px;
line-height: 1.4;
padding: 0 10px;
}
h1, h2, h3 {
line-height: 1.2;
}
</style>
</head>
"""
with codecs.open(os.environ['QUTE_HTML'], 'r', 'utf-8') as source:
data = source.read()
try:
from breadability.readable import Article as reader
doc = reader(data, os.environ['QUTE_URL'])
title = doc._original_document.title
content = HEADER % title + doc.readable + "</html>"
except ImportError:
from readability import Document
doc = Document(data)
title = doc.title()
content = doc.summary().replace('<html>', HEADER % title)
# add a class to make styling the page easier
content = content.replace('<body>', '<body class="qute-readability">')
with codecs.open(tmpfile, 'w', 'utf-8') as target:
target.write(content.lstrip())
with open(os.environ['QUTE_FIFO'], 'w') as fifo:
fifo.write('open -t %s' % tmpfile)

View file

@ -0,0 +1,142 @@
#!/usr/bin/env bash
#
# Behavior:
# Userscript for qutebrowser which views the current web page in mpv using
# sensible mpv-flags. While viewing the page in MPV, all <video>, <embed>,
# and <object> tags in the original page are temporarily removed. Clicking on
# such a removed video restores the respective video.
#
# In order to use this script, just start it using `spawn --userscript` from
# qutebrowser. I recommend using an alias, e.g. put this in the
# [alias]-section of qutebrowser.conf:
#
# mpv = spawn --userscript /path/to/view_in_mpv
#
# Background:
# Most of my machines are too slow to play youtube videos using html5, but
# they work fine in mpv (and mpv has further advantages like video scaling,
# etc). Of course, I don't want the video to be played (or even to be
# downloaded) twice — in MPV and in qwebkit. So I often close the tab after
# opening it in mpv. However, I actually want to keep the rest of the page
# (comments and video suggestions), i.e. only the videos should disappear
# when mpv is started. And that's precisely what the present script does.
#
# Thorsten Wißmann, 2015 (thorsten` on Libera Chat)
# Any feedback is welcome!
set -e
if [ -z "$QUTE_FIFO" ] ; then
cat 1>&2 <<EOF
Error: $0 can not be run as a standalone script.
It is a qutebrowser userscript. In order to use it, call it using
'spawn --userscript' as described in qute://help/userscripts.html
EOF
exit 1
fi
msg() {
local cmd="$1"
shift
local msg="$*"
if [ -z "$QUTE_FIFO" ] ; then
echo "$cmd: $msg" >&2
else
echo "message-$cmd '${msg//\'/\\\'}'" >> "$QUTE_FIFO"
fi
}
MPV_COMMAND=${MPV_COMMAND:-mpv}
# Warning: spaces in single flags are not supported
MPV_FLAGS=${MPV_FLAGS:- --force-window --quiet --keep-open=yes --ytdl}
IFS=" " read -r -a video_command <<< "$MPV_COMMAND $MPV_FLAGS"
js() {
cat <<EOF
function descendantOfTagName(child, ancestorTagName) {
// tells whether child has some (proper) ancestor
// with the tag name ancestorTagName
while (child.parentNode != null) {
child = child.parentNode;
if (typeof child.tagName === 'undefined') break;
if (child.tagName.toUpperCase() == ancestorTagName.toUpperCase()) {
return true;
}
}
return false;
}
var App = {};
var all_videos = [];
all_videos.push.apply(all_videos, document.getElementsByTagName("video"));
all_videos.push.apply(all_videos, document.getElementsByTagName("object"));
all_videos.push.apply(all_videos, document.getElementsByTagName("embed"));
App.backup_videos = Array();
App.all_replacements = Array();
for (i = 0; i < all_videos.length; i++) {
var video = all_videos[i];
if (descendantOfTagName(video, "object")) {
// skip tags that are contained in an object, because we hide
// the object anyway.
continue;
}
var replacement = document.createElement("div");
replacement.innerHTML = "
<p style=\\"margin-bottom: 0.5em\\">
Opening page with:
<span style=\\"font-family: monospace;\\">${video_command[*]}</span>
</p>
<p>
In order to restore this particular video
<a style=\\"font-weight: bold;
color: white;
background: transparent;
cursor: pointer;
\\"
onClick=\\"restore_video(this, " + i + ");\\"
>click here</a>.
</p>
";
replacement.style.position = "relative";
replacement.style.zIndex = "100003000000";
replacement.style.fontSize = "1rem";
replacement.style.textAlign = "center";
replacement.style.verticalAlign = "middle";
replacement.style.height = "100%";
replacement.style.background = "#101010";
replacement.style.color = "white";
replacement.style.border = "4px dashed #545454";
replacement.style.padding = "2em";
replacement.style.margin = "auto";
App.all_replacements[i] = replacement;
App.backup_videos[i] = video;
video.parentNode.replaceChild(replacement, video);
}
function restore_video(obj, index) {
obj = App.all_replacements[index];
video = App.backup_videos[index];
obj.parentNode.replaceChild(video, obj);
}
/** force repainting the video, thanks to:
* http://web.archive.org/web/20151029064649/https://martinwolf.org/2014/06/10/force-repaint-of-an-element-with-javascript/
*/
var siteHeader = document.getElementById('header');
siteHeader.style.display='none';
siteHeader.offsetHeight; // no need to store this anywhere, the reference is enough
siteHeader.style.display='block';
EOF
}
printjs() {
js | sed 's,//.*$,,' | tr '\n' ' '
}
echo "jseval -q -w main $(printjs)" >> "$QUTE_FIFO"
msg info "Opening $QUTE_URL with mpv"
"${video_command[@]}" "$@" "$QUTE_URL"

View file

@ -1,4 +1,6 @@
set selection-clipboard clipboard
set synctex true
set synctex-editor-command "texlab inverse-search -i %{input} -l %{line}"
map <C-i> zoom in
map <C-o> zoom out
map N navigate next

View file

@ -15,18 +15,18 @@ indent_size = 4
[*.go]
indent_style = tab
[*md]
[*.md]
trim_trailing_whitespace = false
insert_final_newline = true
indent_style = space
indent_size = 2
[*yml]
[*.yml]
indent_style = space
indent_size = 2
[*typ]
[*.typ]
indent_style = space
indent_size = 2
[*fish]
[*.fish]
indent_style = space
indent_size = 4