diff --git a/.Xresources b/.Xresources index 524645e4..1a1fe6b6 100644 --- a/.Xresources +++ b/.Xresources @@ -1,19 +1,28 @@ ! Dracula Xresources palette *.foreground: #F8F8F2 *.background: #282A36 -*.color0: #000000 -*.color8: #4D4D4D -*.color1: #FF5555 -*.color9: #FF6E67 -*.color2: #50FA7B -*.color10: #5AF78E -*.color3: #F1FA8C -*.color11: #F4F99D -*.color4: #BD93F9 -*.color12: #CAA9FA -*.color5: #FF79C6 -*.color13: #FF92D0 -*.color6: #8BE9FD -*.color14: #9AEDFE -*.color7: #BFBFBF -*.color15: #E6E6E6 +*.text: #44475A +*.cursor: #F8F8F2 +*.color0: #000000 +*.color1: #FF5555 +*.color2: #50FA7B +*.color3: #F1FA8C +*.color4: #BD93F9 +*.color5: #FF79C6 +*.color6: #8BE9FD +*.color7: #BFBFBF +*.color8: #4D4D4D +*.color9: #FF6E67 +*.color10: #5AF78E +*.color11: #F4F99D +*.color12: #CAA9FA +*.color13: #FF92D0 +*.color14: #9AEDFE +*.color15: #E6E6E6 +*.font: "Hack:size=10:antialias=true:autohint=true" +*.termName: xterm-256color +*.shell: /usr/bin/zsh +*.tabspaces: 4 +*.borderpx: 2 + +Xft.dpi: 96 diff --git a/.config/dmenu/dmenu_run_with_aliases b/.config/dmenu/dmenu_run_with_aliases index 310b8a2a..ebfcdcc5 100755 --- a/.config/dmenu/dmenu_run_with_aliases +++ b/.config/dmenu/dmenu_run_with_aliases @@ -4,6 +4,14 @@ if [[ -f $HOME/.zsh_alias ]]; then source $HOME/.zsh_alias fi -command_to_run=$({ alias | awk '{split($0,alias,"="); print alias[1];}' ; dmenu_path ; } | sort | dmenu -i -fn Hack -nb "#282a36" -nf "#f8f8f2" -sb "#44475a" -sf "#f8f8f2" "$@") +fallback_font="Hack:size=10:antialias=true:autohint=true" +font="" +if [ -x $(command -v xgetres) ]; then + font=$(xgetres font || echo $fallback_font); +else + font=$fallback_font; +fi + +command_to_run=$({ alias | awk '{split($0,alias,"="); print alias[1];}' ; dmenu_path ; } | sort | dmenu -i -fn $font -nb "#282a36" -nf "#f8f8f2" -sb "#44475a" -sf "#f8f8f2" "$@") eval ${command_to_run} & diff --git a/.config/nvim b/.config/nvim index 4f982ea6..3974ed33 160000 --- a/.config/nvim +++ b/.config/nvim @@ -1 +1 @@ -Subproject commit 4f982ea624b0a6ab5c09cd5922c29d45bdc86cee +Subproject commit 3974ed3386fc2ff51caacf9e8b7318bb6f77a79e diff --git a/.config/polybar/config b/.config/polybar/config index 093d5c36..89ec3331 100644 --- a/.config/polybar/config +++ b/.config/polybar/config @@ -13,13 +13,14 @@ error = #ff5555 [bar/top] monitor = ${env:MONITOR:} -font-0 = Hack:pixelsize=10;2 +dpi = ${xrdb:Xft.dpi:-1} +font-0 = Hack:size=10;2 monitor-strict = false override-redirect = false bottom = false fixed-center = false width = 100% -height = 20 +height = 2% offset-x = 0% offset-y = 0% @@ -45,6 +46,7 @@ modules-left = bspwm modules-right = date sep xkeyboard sep cpu space temperature sep memory sep filesystem sep pulseaudio sep +tray-scale = 1.0 tray-position = right tray-padding = 0 tray-maxsize = 14 diff --git a/.config/sxhkd/sxhkdrc b/.config/sxhkd/sxhkdrc index 08bfca55..649dc558 100644 --- a/.config/sxhkd/sxhkdrc +++ b/.config/sxhkd/sxhkdrc @@ -117,13 +117,13 @@ alt + ctrl + {Left,Down,Up,Right} bspc node -v {-20 0,0 20,0 -20,20 0} alt + Return - alacritty + st # DMENU SCRIPTS # run program launcher alt + d - if [ -x $(command -v zsh) ]; then $HOME/.config/dmenu/dmenu_run_with_aliases; else dmenu_run -i -fn Hack -nb "#282a36" -nf "#f8f8f2" -sb "#44475a" -sf "#f8f8f2"; fi + if [ -x $(command -v zsh) ]; then $HOME/.config/dmenu/dmenu_run_with_aliases; else dmenu_run -i -fn "Hack:size=10:antialias=true:autohint=true" -nb "#282a36" -nf "#f8f8f2" -sb "#44475a" -sf "#f8f8f2"; fi alt + x $HOME/.config/dmenu/dmenu_bspwm_desktop_content goto diff --git a/.gitconfig b/.gitconfig index 50d80bb6..56f6befd 100644 --- a/.gitconfig +++ b/.gitconfig @@ -6,6 +6,7 @@ editor = nvim [push] default = simple + followTags = true [commit] gpgsign = true [gpg] diff --git a/.gitignore b/.gitignore index 1b254025..cf19e71c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ !/.config/ !/.gnupg/ +!/.weechat/ !/.ssh/ !/.zsh/ !/AUR/ diff --git a/.oh-my-zsh b/.oh-my-zsh index 62648d71..4ab273e1 160000 --- a/.oh-my-zsh +++ b/.oh-my-zsh @@ -1 +1 @@ -Subproject commit 62648d71bb05116287206d83181f9daa5a59ba67 +Subproject commit 4ab273e19ad1768163e662831b3418a2fc9b6eee diff --git a/.password-store b/.password-store index 46a9b286..051ce862 160000 --- a/.password-store +++ b/.password-store @@ -1 +1 @@ -Subproject commit 46a9b2868cebb2c4b1a52612cff3f3333fd0a0e5 +Subproject commit 051ce862af504b2cd5cf2b092e631ebb5de3497b diff --git a/.ssh/known_hosts b/.ssh/known_hosts index 3babe3cd..3ddef7e9 100644 --- a/.ssh/known_hosts +++ b/.ssh/known_hosts @@ -4,3 +4,4 @@ pc.dustvoice.de ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy 140.82.118.4 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== git.rwth-aachen.de,134.130.122.52 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIcyEfZ5DqwZFMd2XKFt3XDb07T0/qjdtOfnoXgOlUjBWK0BLbhA787VjyzoDrWrgNrb1/xEyTqGdP0hWRMiXMU= ssh.strato.de,81.169.145.126 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDazQi5TwecOL29s5HbSoAgLCu+YqKV9kqWlYRtwmaXVgR9fB/pFTf5Nnx7EfkZy4B/Ue2EWYdKOOQnAUpx4uUI= +aur.archlinux.org,95.216.144.15 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLMiLrP8pVi5BFX2i3vepSUnpedeiewE5XptnUnau+ZoeUOPkpoCgZZuYfpaIQfhhJJI5qgnjJmr4hyJbe/zxow= diff --git a/.tmux.conf b/.tmux.conf index 032f428b..b7e2200b 100644 --- a/.tmux.conf +++ b/.tmux.conf @@ -1,7 +1,15 @@ setw -g mode-keys vi - -bind r source-file ~/.tmux.conf - set -g mouse on set-option -g allow-rename off + +bind r source-file ~/.tmux.conf + +set-option escape-time 0 + +bind-key -T copy-mode-vi 'v' send -X begin-selection +bind-key -T copy-mode-vi 'y' send -X copy-selection-and-cancel +bind-key -T copy-mode-vi Escape send -X cancel + +bind-key -n C-p run "xclip -o | tmux load-buffer -" +bind-key -n C-y run "tmux show-buffer | xclip -i -sel p -f | xclip -i -sel c" diff --git a/.weechat/.gitignore b/.weechat/.gitignore new file mode 100644 index 00000000..651b5efe --- /dev/null +++ b/.weechat/.gitignore @@ -0,0 +1,35 @@ +/* +/*/ +!/.gitignore + +!/alias.conf +!/buflist.conf +!/charset.conf +!/exec.conf +!/fifo.conf +!/fset.conf +!/guile.conf +!/irc.conf +!/logger.conf +!/lua.conf +!/perl.conf +!/plugins.conf +!/python.conf +!/relay.conf +!/ruby.conf +!/script.conf +!/sec.conf +!/spell.conf +!/tcl.conf +!/trigger.conf +!/weechat.conf +!/xfer.conf + +!/guile/ +!/lua/ +!/perl/ +!/python/ +!/ruby/ +!/script/ +!/tcl/ +!/xfer/ diff --git a/.weechat/alias.conf b/.weechat/alias.conf new file mode 100644 index 00000000..0a02da3b --- /dev/null +++ b/.weechat/alias.conf @@ -0,0 +1,47 @@ +# +# weechat -- alias.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[cmd] +AAWAY = "allserv /away" +ANICK = "allserv /nick" +BEEP = "print -beep" +BYE = "quit" +C = "buffer clear" +CHAT = "dcc chat" +CL = "buffer clear" +CLOSE = "buffer close" +EXIT = "quit" +IG = "ignore" +J = "join" +K = "kick" +KB = "kickban" +LEAVE = "part" +M = "msg" +MSGBUF = "command -buffer $1 * /input send $2-" +MUB = "unban *" +N = "names" +Q = "query" +REDRAW = "window refresh" +SAY = "msg *" +SIGNOFF = "quit" +T = "topic" +UB = "unban" +UMODE = "mode $nick" +V = "command core version" +W = "who" +WC = "window close" +WI = "whois" +WII = "whois $1 $1" +WM = "window merge" +WW = "whowas" + +[completion] +MSGBUF = "%(buffers_plugins_names)" diff --git a/.weechat/buflist.conf b/.weechat/buflist.conf new file mode 100644 index 00000000..d285f892 --- /dev/null +++ b/.weechat/buflist.conf @@ -0,0 +1,39 @@ +# +# weechat -- buflist.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +add_newline = on +auto_scroll = 50 +display_conditions = "${buffer.hidden}==0" +enabled = on +mouse_jump_visited_buffer = off +mouse_move_buffer = on +mouse_wheel = on +nick_prefix = off +nick_prefix_empty = on +signals_refresh = "" +sort = "number,-active" + +[format] +buffer = "${format_number}${indent}${format_nick_prefix}${color_hotlist}${format_name}" +buffer_current = "${color:,blue}${format_buffer}" +hotlist = " ${color:green}(${hotlist}${color:green})" +hotlist_highlight = "${color:magenta}" +hotlist_low = "${color:white}" +hotlist_message = "${color:brown}" +hotlist_none = "${color:default}" +hotlist_private = "${color:green}" +hotlist_separator = "${color:default}," +indent = " " +lag = " ${color:green}[${color:brown}${lag}${color:green}]" +name = "${name}" +nick_prefix = "${color_nick_prefix}${nick_prefix}" +number = "${color:green}${number}${if:${number_displayed}?.: }" diff --git a/.weechat/charset.conf b/.weechat/charset.conf new file mode 100644 index 00000000..00d304cd --- /dev/null +++ b/.weechat/charset.conf @@ -0,0 +1,18 @@ +# +# weechat -- charset.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[default] +decode = "iso-8859-1" +encode = "" + +[decode] + +[encode] diff --git a/.weechat/exec.conf b/.weechat/exec.conf new file mode 100644 index 00000000..9e1b4f1e --- /dev/null +++ b/.weechat/exec.conf @@ -0,0 +1,19 @@ +# +# weechat -- exec.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[command] +default_options = "" +purge_delay = 0 +shell = "${env:SHELL}" + +[color] +flag_finished = lightred +flag_running = lightgreen diff --git a/.weechat/fifo.conf b/.weechat/fifo.conf new file mode 100644 index 00000000..904985df --- /dev/null +++ b/.weechat/fifo.conf @@ -0,0 +1,14 @@ +# +# weechat -- fifo.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[file] +enabled = on +path = "%h/weechat_fifo" diff --git a/.weechat/fset.conf b/.weechat/fset.conf new file mode 100644 index 00000000..668266c9 --- /dev/null +++ b/.weechat/fset.conf @@ -0,0 +1,95 @@ +# +# weechat -- fset.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +auto_unmark = off +condition_catch_set = "${count} >= 1" +export_help_default = on +format_number = 1 +marked_string = "*" +scroll_horizontal = 10 +show_plugins_desc = off +sort = "~name" +unmarked_string = " " +use_color_value = off +use_keys = on +use_mute = off + +[format] +export_help = "# ${description2}" +export_option = "/set ${name} ${quoted_value}" +export_option_null = "/unset ${name}" +option1 = "" +option2 = "${marked} ${name} ${type} ${value2}${newline} ${empty_name} ${_default_value}${color:darkgray} -- ${min}..${max}${newline} ${empty_name} ${description}" + +[color] +default_value = default +default_value_selected = white +description = default +description_selected = white +file = default +file_changed = brown +file_changed_selected = yellow +file_selected = white +help_default_value = white +help_description = default +help_name = white +help_quotes = darkgray +help_values = default +index = cyan +index_selected = lightcyan +line_marked_bg1 = default +line_marked_bg2 = default +line_selected_bg1 = blue +line_selected_bg2 = red +marked = brown +marked_selected = yellow +max = default +max_selected = white +min = default +min_selected = white +name = default +name_changed = brown +name_changed_selected = yellow +name_selected = white +option = default +option_changed = brown +option_changed_selected = yellow +option_selected = white +parent_name = default +parent_name_selected = white +parent_value = cyan +parent_value_selected = lightcyan +quotes = darkgray +quotes_changed = default +quotes_changed_selected = white +quotes_selected = default +section = default +section_changed = brown +section_changed_selected = yellow +section_selected = white +string_values = default +string_values_selected = white +title_count_options = cyan +title_current_option = lightcyan +title_filter = yellow +title_marked_options = lightgreen +title_sort = white +type = green +type_selected = lightgreen +unmarked = default +unmarked_selected = white +value = cyan +value_changed = brown +value_changed_selected = yellow +value_selected = lightcyan +value_undef = magenta +value_undef_selected = lightmagenta diff --git a/.weechat/guile.conf b/.weechat/guile.conf new file mode 100644 index 00000000..07a4910e --- /dev/null +++ b/.weechat/guile.conf @@ -0,0 +1,14 @@ +# +# weechat -- guile.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +check_license = off +eval_keep_context = on diff --git a/.weechat/irc.conf b/.weechat/irc.conf new file mode 100644 index 00000000..dce0eefc --- /dev/null +++ b/.weechat/irc.conf @@ -0,0 +1,203 @@ +# +# weechat -- irc.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +buffer_open_before_autojoin = on +buffer_open_before_join = off +buffer_switch_autojoin = on +buffer_switch_join = on +color_nicks_in_names = off +color_nicks_in_nicklist = off +color_nicks_in_server_messages = on +color_pv_nick_like_channel = on +ctcp_time_format = "%a, %d %b %Y %T %z" +display_away = local +display_ctcp_blocked = on +display_ctcp_reply = on +display_ctcp_unknown = on +display_host_join = on +display_host_join_local = on +display_host_quit = on +display_join_message = "329,332,333,366" +display_old_topic = on +display_pv_away_once = on +display_pv_back = on +display_pv_warning_address = off +highlight_channel = "$nick" +highlight_pv = "$nick" +highlight_server = "$nick" +highlight_tags_restrict = "irc_privmsg,irc_notice" +item_channel_modes_hide_args = "k" +item_display_server = buffer_plugin +item_nick_modes = on +item_nick_prefix = on +join_auto_add_chantype = off +msgbuffer_fallback = current +new_channel_position = none +new_pv_position = none +nick_completion_smart = speakers +nick_mode = prefix +nick_mode_empty = off +nicks_hide_password = "nickserv" +notice_as_pv = auto +notice_welcome_redirect = on +notice_welcome_tags = "" +notify_tags_ison = "notify_message" +notify_tags_whois = "notify_message" +part_closes_buffer = off +pv_buffer = independent +pv_tags = "notify_private" +raw_messages = 256 +server_buffer = merge_with_core +smart_filter = on +smart_filter_account = on +smart_filter_chghost = on +smart_filter_delay = 5 +smart_filter_join = on +smart_filter_join_unmask = 30 +smart_filter_mode = "+" +smart_filter_nick = on +smart_filter_quit = on +temporary_servers = off +topic_strip_colors = off + +[color] +input_nick = lightcyan +item_channel_modes = default +item_lag_counting = default +item_lag_finished = yellow +item_nick_modes = default +message_account = cyan +message_chghost = brown +message_join = green +message_kick = red +message_quit = red +mirc_remap = "1,-1:darkgray" +nick_prefixes = "y:lightred;q:lightred;a:lightcyan;o:lightgreen;h:lightmagenta;v:yellow;*:lightblue" +notice = green +reason_kick = default +reason_quit = default +topic_current = default +topic_new = white +topic_old = default + +[network] +autoreconnect_delay_growing = 2 +autoreconnect_delay_max = 600 +ban_mask_default = "*!$ident@$host" +colors_receive = on +colors_send = on +lag_check = 60 +lag_max = 1800 +lag_min_show = 500 +lag_reconnect = 300 +lag_refresh_interval = 1 +notify_check_ison = 1 +notify_check_whois = 5 +sasl_fail_unavailable = on +send_unknown_commands = off +whois_double_nick = off + +[msgbuffer] + +[ctcp] + +[ignore] + +[server_default] +addresses = "" +anti_flood_prio_high = 2 +anti_flood_prio_low = 2 +autoconnect = off +autojoin = "" +autoreconnect = on +autoreconnect_delay = 10 +autorejoin = off +autorejoin_delay = 30 +away_check = 0 +away_check_max_nicks = 25 +capabilities = "" +charset_message = message +command = "" +command_delay = 0 +connection_timeout = 60 +ipv6 = on +local_hostname = "" +msg_kick = "" +msg_part = "WeeChat ${info:version}" +msg_quit = "WeeChat ${info:version}" +nicks = "dustvoice,dustvoice1,dustvoice2,dustvoice3,dustvoice4" +nicks_alternate = on +notify = "" +password = "" +proxy = "" +realname = "" +sasl_fail = continue +sasl_key = "" +sasl_mechanism = plain +sasl_password = "" +sasl_timeout = 15 +sasl_username = "" +split_msg_max_length = 512 +ssl = off +ssl_cert = "" +ssl_dhkey_size = 2048 +ssl_fingerprint = "" +ssl_password = "" +ssl_priorities = "NORMAL:-VERS-SSL3.0" +ssl_verify = on +usermode = "" +username = "dustvoice" + +[server] +freenode.addresses = "irc.freenode.net" +freenode.proxy +freenode.ipv6 +freenode.ssl +freenode.ssl_cert +freenode.ssl_password +freenode.ssl_priorities +freenode.ssl_dhkey_size +freenode.ssl_fingerprint +freenode.ssl_verify +freenode.password +freenode.capabilities +freenode.sasl_mechanism +freenode.sasl_username +freenode.sasl_password +freenode.sasl_key +freenode.sasl_timeout +freenode.sasl_fail +freenode.autoconnect +freenode.autoreconnect +freenode.autoreconnect_delay +freenode.nicks +freenode.nicks_alternate +freenode.username +freenode.realname +freenode.local_hostname +freenode.usermode +freenode.command +freenode.command_delay +freenode.autojoin +freenode.autorejoin +freenode.autorejoin_delay +freenode.connection_timeout +freenode.anti_flood_prio_high +freenode.anti_flood_prio_low +freenode.away_check +freenode.away_check_max_nicks +freenode.msg_kick +freenode.msg_part +freenode.msg_quit +freenode.notify +freenode.split_msg_max_length +freenode.charset_message diff --git a/.weechat/logger.conf b/.weechat/logger.conf new file mode 100644 index 00000000..d0d3218d --- /dev/null +++ b/.weechat/logger.conf @@ -0,0 +1,36 @@ +# +# weechat -- logger.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +backlog = 20 +backlog_conditions = "" + +[color] +backlog_end = default +backlog_line = default + +[file] +auto_log = on +color_lines = off +flush_delay = 120 +fsync = off +info_lines = off +mask = "$plugin.$name.weechatlog" +name_lower_case = on +nick_prefix = "" +nick_suffix = "" +path = "%h/logs/" +replacement_char = "_" +time_format = "%Y-%m-%d %H:%M:%S" + +[level] + +[mask] diff --git a/.weechat/lua.conf b/.weechat/lua.conf new file mode 100644 index 00000000..fa4966b2 --- /dev/null +++ b/.weechat/lua.conf @@ -0,0 +1,14 @@ +# +# weechat -- lua.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +check_license = off +eval_keep_context = on diff --git a/.weechat/perl.conf b/.weechat/perl.conf new file mode 100644 index 00000000..31924b91 --- /dev/null +++ b/.weechat/perl.conf @@ -0,0 +1,14 @@ +# +# weechat -- perl.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +check_license = off +eval_keep_context = on diff --git a/.weechat/plugins.conf b/.weechat/plugins.conf new file mode 100644 index 00000000..b8a80bbb --- /dev/null +++ b/.weechat/plugins.conf @@ -0,0 +1,56 @@ +# +# weechat -- plugins.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[var] +python.vimode.copy_clipboard_cmd = "xclip -selection c" +python.vimode.imap_esc = "" +python.vimode.imap_esc_timeout = "1000" +python.vimode.line_number_prefix = "" +python.vimode.line_number_suffix = " " +python.vimode.mode_indicator_cmd_color = "white" +python.vimode.mode_indicator_cmd_color_bg = "cyan" +python.vimode.mode_indicator_insert_color = "white" +python.vimode.mode_indicator_insert_color_bg = "blue" +python.vimode.mode_indicator_normal_color = "white" +python.vimode.mode_indicator_normal_color_bg = "blue" +python.vimode.mode_indicator_prefix = "" +python.vimode.mode_indicator_replace_color = "white" +python.vimode.mode_indicator_replace_color_bg = "red" +python.vimode.mode_indicator_search_color = "white" +python.vimode.mode_indicator_search_color_bg = "magenta" +python.vimode.mode_indicator_suffix = "" +python.vimode.no_warn = "on" +python.vimode.paste_clipboard_cmd = "xclip -selection c -o" +python.vimode.search_vim = "on" +python.vimode.user_mappings = "" + +[desc] +python.vimode.copy_clipboard_cmd = "command used to copy to clipboard; must read input from stdin (default: "xclip -selection c")" +python.vimode.imap_esc = "use alternate mapping to enter Normal mode while in Insert mode; having it set to 'jk' is similar to `:imap jk ` in vim (default: "")" +python.vimode.imap_esc_timeout = "time in ms to wait for the imap_esc sequence to complete (default: "1000")" +python.vimode.line_number_prefix = "prefix for line numbers (default: "")" +python.vimode.line_number_suffix = "suffix for line numbers (default: " ")" +python.vimode.mode_indicator_cmd_color = "color for mode indicator in Command mode (default: "white")" +python.vimode.mode_indicator_cmd_color_bg = "background color for mode indicator in Command mode (default: "cyan")" +python.vimode.mode_indicator_insert_color = "color for mode indicator in Insert mode (default: "white")" +python.vimode.mode_indicator_insert_color_bg = "background color for mode indicator in Insert mode (default: "blue")" +python.vimode.mode_indicator_normal_color = "color for mode indicator in Normal mode (default: "white")" +python.vimode.mode_indicator_normal_color_bg = "background color for mode indicator in Normal mode (default: "gray")" +python.vimode.mode_indicator_prefix = "prefix for the bar item mode_indicator (default: "")" +python.vimode.mode_indicator_replace_color = "color for mode indicator in Replace mode (default: "white")" +python.vimode.mode_indicator_replace_color_bg = "background color for mode indicator in Replace mode (default: "red")" +python.vimode.mode_indicator_search_color = "color for mode indicator in Search mode (default: "white")" +python.vimode.mode_indicator_search_color_bg = "background color for mode indicator in Search mode (default: "magenta")" +python.vimode.mode_indicator_suffix = "suffix for the bar item mode_indicator (default: "")" +python.vimode.no_warn = "don't warn about problematic keybindings and tmux/screen (default: "off")" +python.vimode.paste_clipboard_cmd = "command used to paste clipboard; must output content to stdout (default: "xclip -selection c -o")" +python.vimode.search_vim = "allow n/N usage after searching (requires an extra to return to normal mode) (default: "off")" +python.vimode.user_mappings = "see the `:nmap` command in the README for more info; please do not modify this field manually unless you know what you're doing (default: "")" diff --git a/.weechat/python.conf b/.weechat/python.conf new file mode 100644 index 00000000..187b778d --- /dev/null +++ b/.weechat/python.conf @@ -0,0 +1,14 @@ +# +# weechat -- python.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +check_license = off +eval_keep_context = on diff --git a/.weechat/python/autoload/vimode.py b/.weechat/python/autoload/vimode.py new file mode 120000 index 00000000..c6303a5c --- /dev/null +++ b/.weechat/python/autoload/vimode.py @@ -0,0 +1 @@ +../vimode.py \ No newline at end of file diff --git a/.weechat/python/vimode.py b/.weechat/python/vimode.py new file mode 100644 index 00000000..873c5d74 --- /dev/null +++ b/.weechat/python/vimode.py @@ -0,0 +1,1882 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2014 Germain Z. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# +# Add vi/vim-like modes to WeeChat. +# + + +import csv +import json +import os +import re +import subprocess +try: + from StringIO import StringIO +except ImportError: + from io import StringIO +import time + +import weechat + + +# Script info. +# ============ + +SCRIPT_NAME = "vimode" +SCRIPT_AUTHOR = "GermainZ " +SCRIPT_VERSION = "0.8" +SCRIPT_LICENSE = "GPL3" +SCRIPT_DESC = ("Add vi/vim-like modes and keybindings to WeeChat.") + + +# Global variables. +# ================= + +# General. +# -------- + +# Halp! Halp! Halp! +GITHUB_BASE = "https://github.com/GermainZ/weechat-vimode/blob/master/" +README_URL = GITHUB_BASE + "README.md" +FAQ_KEYBINDINGS = GITHUB_BASE + "FAQ.md#problematic-key-bindings" +FAQ_ESC = GITHUB_BASE + "FAQ.md#esc-key-not-being-detected-instantly" + +# Holds the text of the tab-completions for the command-line mode. +cmd_compl_text = "" +# Holds the original text of the command-line mode, used for completion. +cmd_text_orig = None +# Index of current suggestion, used for completion. +cmd_compl_pos = 0 +# Used for command-line mode history. +cmd_history = [] +cmd_history_index = 0 +# Used to store the content of the input line when going into COMMAND mode. +input_line_backup = {} +# Mode we're in. One of INSERT, NORMAL, REPLACE, COMMAND or SEARCH. +# SEARCH is only used if search_vim is enabled. +mode = "INSERT" +# Holds normal commands (e.g. "dd"). +vi_buffer = "" +# See `cb_key_combo_default()`. +esc_pressed = 0 +# See `cb_key_pressed()`. +last_signal_time = 0 +# See `start_catching_keys()` for more info. +catching_keys_data = {'amount': 0} +# Used for ; and , to store the last f/F/t/T motion. +last_search_motion = {'motion': None, 'data': None} +# Used for undo history. +undo_history = {} +undo_history_index = {} +# Holds mode colors (loaded from vimode_settings). +mode_colors = {} + +# Script options. +vimode_settings = { + 'no_warn': ("off", ("don't warn about problematic keybindings and " + "tmux/screen")), + 'copy_clipboard_cmd': ("xclip -selection c", + ("command used to copy to clipboard; must read " + "input from stdin")), + 'paste_clipboard_cmd': ("xclip -selection c -o", + ("command used to paste clipboard; must output " + "content to stdout")), + 'imap_esc': ("", ("use alternate mapping to enter Normal mode while in " + "Insert mode; having it set to 'jk' is similar to " + "`:imap jk ` in vim")), + 'imap_esc_timeout': ("1000", ("time in ms to wait for the imap_esc " + "sequence to complete")), + 'search_vim': ("off", ("allow n/N usage after searching (requires an extra" + " to return to normal mode)")), + 'user_mappings': ("", ("see the `:nmap` command in the README for more " + "info; please do not modify this field manually " + "unless you know what you're doing")), + 'mode_indicator_prefix': ("", "prefix for the bar item mode_indicator"), + 'mode_indicator_suffix': ("", "suffix for the bar item mode_indicator"), + 'mode_indicator_normal_color': ("white", + "color for mode indicator in Normal mode"), + 'mode_indicator_normal_color_bg': ("gray", + ("background color for mode indicator " + "in Normal mode")), + 'mode_indicator_insert_color': ("white", + "color for mode indicator in Insert mode"), + 'mode_indicator_insert_color_bg': ("blue", + ("background color for mode indicator " + "in Insert mode")), + 'mode_indicator_replace_color': ("white", + "color for mode indicator in Replace mode"), + 'mode_indicator_replace_color_bg': ("red", + ("background color for mode indicator " + "in Replace mode")), + 'mode_indicator_cmd_color': ("white", + "color for mode indicator in Command mode"), + 'mode_indicator_cmd_color_bg': ("cyan", + ("background color for mode indicator in " + "Command mode")), + 'mode_indicator_search_color': ("white", + "color for mode indicator in Search mode"), + 'mode_indicator_search_color_bg': ("magenta", + ("background color for mode indicator " + "in Search mode")), + 'line_number_prefix': ("", "prefix for line numbers"), + 'line_number_suffix': (" ", "suffix for line numbers") +} + + +# Regex patterns. +# --------------- + +WHITESPACE = re.compile(r"\s") +IS_KEYWORD = re.compile(r"[a-zA-Z0-9_@À-ÿ]") +REGEX_MOTION_LOWERCASE_W = re.compile(r"\b\S|(?<=\s)\S") +REGEX_MOTION_UPPERCASE_W = re.compile(r"(?<=\s)\S") +REGEX_MOTION_UPPERCASE_E = re.compile(r"\S(?!\S)") +REGEX_MOTION_UPPERCASE_B = REGEX_MOTION_UPPERCASE_E +REGEX_MOTION_G_UPPERCASE_E = REGEX_MOTION_UPPERCASE_W +REGEX_MOTION_CARRET = re.compile(r"\S") +REGEX_INT = r"[0-9]" +REGEX_MAP_KEYS_1 = { + re.compile("<([^>]*-)Left>", re.IGNORECASE): '<\\1\x01[[D>', + re.compile("<([^>]*-)Right>", re.IGNORECASE): '<\\1\x01[[C>', + re.compile("<([^>]*-)Up>", re.IGNORECASE): '<\\1\x01[[A>', + re.compile("<([^>]*-)Down>", re.IGNORECASE): '<\\1\x01[[B>', + re.compile("", re.IGNORECASE): '\x01[[D', + re.compile("", re.IGNORECASE): '\x01[[C', + re.compile("", re.IGNORECASE): '\x01[[A', + re.compile("", re.IGNORECASE): '\x01[[B' +} +REGEX_MAP_KEYS_2 = { + re.compile(r"]*)>", re.IGNORECASE): '\x01\\1', + re.compile(r"]*)>", re.IGNORECASE): '\x01[\\1' +} + +# Regex used to detect problematic keybindings. +# For example: meta-wmeta-s is bound by default to ``/window swap``. +# If the user pressed Esc-w, WeeChat will detect it as meta-w and will not +# send any signal to `cb_key_combo_default()` just yet, since it's the +# beginning of a known key combo. +# Instead, `cb_key_combo_default()` will receive the Esc-ws signal, which +# becomes "ws" after removing the Esc part, and won't know how to handle it. +REGEX_PROBLEMATIC_KEYBINDINGS = re.compile(r"meta-\w(meta|ctrl)") + + +# Vi commands. +# ------------ + +def cmd_nmap(args): + """Add a user-defined key mapping. + + Some (but not all) vim-like key codes are supported to simplify things for + the user: , , , , and . + + See Also: + `cmd_unmap()`. + """ + args = args.strip() + if not args: + mappings = vimode_settings['user_mappings'] + if mappings: + weechat.prnt("", "User-defined key mappings:") + for key, mapping in mappings.items(): + weechat.prnt("", "{} -> {}".format(key, mapping)) + else: + weechat.prnt("", "nmap: no mapping found.") + elif not " " in args: + weechat.prnt("", "nmap syntax -> :nmap {lhs} {rhs}") + else: + key, mapping = args.split(" ", 1) + # First pass of replacements. We perform two passes as a simple way to + # avoid incorrect replacements due to dictionaries not being + # insertion-ordered prior to Python 3.7. + for regex, repl in REGEX_MAP_KEYS_1.items(): + key = regex.sub(repl, key) + mapping = regex.sub(repl, mapping) + # Second pass of replacements. + for regex, repl in REGEX_MAP_KEYS_2.items(): + key = regex.sub(repl, key) + mapping = regex.sub(repl, mapping) + mappings = vimode_settings['user_mappings'] + mappings[key] = mapping + weechat.config_set_plugin('user_mappings', json.dumps(mappings)) + vimode_settings['user_mappings'] = mappings + +def cmd_nunmap(args): + """Remove a user-defined key mapping. + + See Also: + `cmd_map()`. + """ + args = args.strip() + if not args: + weechat.prnt("", "nunmap syntax -> :unmap {lhs}") + else: + key = args + for regex, repl in REGEX_MAP_KEYS_1.items(): + key = regex.sub(repl, key) + for regex, repl in REGEX_MAP_KEYS_2.items(): + key = regex.sub(repl, key) + mappings = vimode_settings['user_mappings'] + if key in mappings: + del mappings[key] + weechat.config_set_plugin('user_mappings', json.dumps(mappings)) + vimode_settings['user_mappings'] = mappings + else: + weechat.prnt("", "nunmap: No such mapping") + +# See Also: `cb_exec_cmd()`. +VI_COMMAND_GROUPS = {('h', 'help'): "/help", + ('qa', 'qall', 'quita', 'quitall'): "/exit", + ('q', 'quit'): "/close", + ('w', 'write'): "/save", + ('bN', 'bNext', 'bp', 'bprevious'): "/buffer -1", + ('bn', 'bnext'): "/buffer +1", + ('bd', 'bdel', 'bdelete'): "/close", + ('b#',): "/input jump_last_buffer_displayed", + ('b', 'bu', 'buf', 'buffer'): "/buffer", + ('sp', 'split'): "/window splith", + ('vs', 'vsplit'): "/window splitv", + ('nm', 'nmap'): cmd_nmap, + ('nun', 'nunmap'): cmd_nunmap} + +VI_COMMANDS = dict() +for T, v in VI_COMMAND_GROUPS.items(): + VI_COMMANDS.update(dict.fromkeys(T, v)) + + +# Vi operators. +# ------------- + +# Each operator must have a corresponding function, called "operator_X" where +# X is the operator. For example: `operator_c()`. +VI_OPERATORS = ["c", "d", "y"] + + +# Vi motions. +# ----------- + +# Vi motions. Each motion must have a corresponding function, called +# "motion_X" where X is the motion (e.g. `motion_w()`). +# See Also: `SPECIAL_CHARS`. +VI_MOTIONS = ["w", "e", "b", "^", "$", "h", "l", "W", "E", "B", "f", "F", "t", + "T", "ge", "gE", "0"] + +# Special characters for motions. The corresponding function's name is +# converted before calling. For example, "^" will call `motion_carret` instead +# of `motion_^` (which isn't allowed because of illegal characters). +SPECIAL_CHARS = {'^': "carret", + '$': "dollar"} + + +# Methods for vi operators, motions and key bindings. +# =================================================== + +# Documented base examples: +# ------------------------- + +def operator_base(buf, input_line, pos1, pos2, overwrite): + """Operator method example. + + Args: + buf (str): pointer to the current WeeChat buffer. + input_line (str): the content of the input line. + pos1 (int): the starting position of the motion. + pos2 (int): the ending position of the motion. + overwrite (bool, optional): whether the character at the cursor's new + position should be overwritten or not (for inclusive motions). + Defaults to False. + + Notes: + Should be called "operator_X", where X is the operator, and defined in + `VI_OPERATORS`. + Must perform actions (e.g. modifying the input line) on its own, + using the WeeChat API. + + See Also: + For additional examples, see `operator_d()` and + `operator_y()`. + """ + # Get start and end positions. + start = min(pos1, pos2) + end = max(pos1, pos2) + # Print the text the operator should go over. + weechat.prnt("", "Selection: %s" % input_line[start:end]) + +def motion_base(input_line, cur, count): + """Motion method example. + + Args: + input_line (str): the content of the input line. + cur (int): the position of the cursor. + count (int): the amount of times to multiply or iterate the action. + + Returns: + A tuple containing three values: + int: the new position of the cursor. + bool: True if the motion is inclusive, False otherwise. + bool: True if the motion is catching, False otherwise. + See `start_catching_keys()` for more info on catching motions. + + Notes: + Should be called "motion_X", where X is the motion, and defined in + `VI_MOTIONS`. + Must not modify the input line directly. + + See Also: + For additional examples, see `motion_w()` (normal motion) and + `motion_f()` (catching motion). + """ + # Find (relative to cur) position of next number. + pos = get_pos(input_line, REGEX_INT, cur, True, count) + # Return the new (absolute) cursor position. + # This motion is exclusive, so overwrite is False. + return cur + pos, False + +def key_base(buf, input_line, cur, count): + """Key method example. + + Args: + buf (str): pointer to the current WeeChat buffer. + input_line (str): the content of the input line. + cur (int): the position of the cursor. + count (int): the amount of times to multiply or iterate the action. + + Notes: + Should be called `key_X`, where X represents the key(s), and defined + in `VI_KEYS`. + Must perform actions on its own (using the WeeChat API). + + See Also: + For additional examples, see `key_a()` (normal key) and + `key_r()` (catching key). + """ + # Key was pressed. Go to Insert mode (similar to "i"). + set_mode("INSERT") + + +# Operators: +# ---------- + +def operator_d(buf, input_line, pos1, pos2, overwrite=False): + """Delete text from `pos1` to `pos2` from the input line. + + If `overwrite` is set to True, the character at the cursor's new position + is removed as well (the motion is inclusive). + + See Also: + `operator_base()`. + """ + start = min(pos1, pos2) + end = max(pos1, pos2) + if overwrite: + end += 1 + input_line = list(input_line) + del input_line[start:end] + input_line = "".join(input_line) + weechat.buffer_set(buf, "input", input_line) + set_cur(buf, input_line, pos1) + +def operator_c(buf, input_line, pos1, pos2, overwrite=False): + """Delete text from `pos1` to `pos2` from the input and enter Insert mode. + + If `overwrite` is set to True, the character at the cursor's new position + is removed as well (the motion is inclusive.) + + See Also: + `operator_base()`. + """ + operator_d(buf, input_line, pos1, pos2, overwrite) + set_mode("INSERT") + +def operator_y(buf, input_line, pos1, pos2, _): + """Yank text from `pos1` to `pos2` from the input line. + + See Also: + `operator_base()`. + """ + start = min(pos1, pos2) + end = max(pos1, pos2) + cmd = vimode_settings['copy_clipboard_cmd'] + proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE) + proc.communicate(input=input_line[start:end].encode()) + + +# Motions: +# -------- + +def motion_0(input_line, cur, count): + """Go to the first character of the line. + + See Also; + `motion_base()`. + """ + return 0, False, False + +def motion_w(input_line, cur, count): + """Go `count` words forward and return position. + + See Also: + `motion_base()`. + """ + pos = get_pos(input_line, REGEX_MOTION_LOWERCASE_W, cur, True, count) + if pos == -1: + return len(input_line), False, False + return cur + pos, False, False + +def motion_W(input_line, cur, count): + """Go `count` WORDS forward and return position. + + See Also: + `motion_base()`. + """ + pos = get_pos(input_line, REGEX_MOTION_UPPERCASE_W, cur, True, count) + if pos == -1: + return len(input_line), False, False + return cur + pos, False, False + +def motion_e(input_line, cur, count): + """Go to the end of `count` words and return position. + + See Also: + `motion_base()`. + """ + for _ in range(max(1, count)): + found = False + pos = cur + for pos in range(cur + 1, len(input_line) - 1): + # Whitespace, keep going. + if WHITESPACE.match(input_line[pos]): + pass + # End of sequence made from 'iskeyword' characters only, + # or end of sequence made from non 'iskeyword' characters only. + elif ((IS_KEYWORD.match(input_line[pos]) and + (not IS_KEYWORD.match(input_line[pos + 1]) or + WHITESPACE.match(input_line[pos + 1]))) or + (not IS_KEYWORD.match(input_line[pos]) and + (IS_KEYWORD.match(input_line[pos + 1]) or + WHITESPACE.match(input_line[pos + 1])))): + found = True + cur = pos + break + # We're at the character before the last and we still found nothing. + # Go to the last character. + if not found: + cur = pos + 1 + return cur, True, False + +def motion_E(input_line, cur, count): + """Go to the end of `count` WORDS and return cusor position. + + See Also: + `motion_base()`. + """ + pos = get_pos(input_line, REGEX_MOTION_UPPERCASE_E, cur, True, count) + if pos == -1: + return len(input_line), False, False + return cur + pos, True, False + +def motion_b(input_line, cur, count): + """Go `count` words backwards and return position. + + See Also: + `motion_base()`. + """ + # "b" is just "e" on inverted data (e.g. "olleH" instead of "Hello"). + pos_inv = motion_e(input_line[::-1], len(input_line) - cur - 1, count)[0] + pos = len(input_line) - pos_inv - 1 + return pos, True, False + +def motion_B(input_line, cur, count): + """Go `count` WORDS backwards and return position. + + See Also: + `motion_base()`. + """ + new_cur = len(input_line) - cur + pos = get_pos(input_line[::-1], REGEX_MOTION_UPPERCASE_B, new_cur, + count=count) + if pos == -1: + return 0, False, False + pos = len(input_line) - (pos + new_cur + 1) + return pos, True, False + +def motion_ge(input_line, cur, count): + """Go to end of `count` words backwards and return position. + + See Also: + `motion_base()`. + """ + # "ge is just "w" on inverted data (e.g. "olleH" instead of "Hello"). + pos_inv = motion_w(input_line[::-1], len(input_line) - cur - 1, count)[0] + pos = len(input_line) - pos_inv - 1 + return pos, True, False + +def motion_gE(input_line, cur, count): + """Go to end of `count` WORDS backwards and return position. + + See Also: + `motion_base()`. + """ + new_cur = len(input_line) - cur - 1 + pos = get_pos(input_line[::-1], REGEX_MOTION_G_UPPERCASE_E, new_cur, + True, count) + if pos == -1: + return 0, False, False + pos = len(input_line) - (pos + new_cur + 1) + return pos, True, False + +def motion_h(input_line, cur, count): + """Go `count` characters to the left and return position. + + See Also: + `motion_base()`. + """ + return max(0, cur - max(count, 1)), False, False + +def motion_l(input_line, cur, count): + """Go `count` characters to the right and return position. + + See Also: + `motion_base()`. + """ + return cur + max(count, 1), False, False + +def motion_carret(input_line, cur, count): + """Go to first non-blank character of line and return position. + + See Also: + `motion_base()`. + """ + pos = get_pos(input_line, REGEX_MOTION_CARRET, 0) + return pos, False, False + +def motion_dollar(input_line, cur, count): + """Go to end of line and return position. + + See Also: + `motion_base()`. + """ + pos = len(input_line) + return pos, False, False + +def motion_f(input_line, cur, count): + """Go to `count`'th occurence of character and return position. + + See Also: + `motion_base()`. + """ + return start_catching_keys(1, "cb_motion_f", input_line, cur, count) + +def cb_motion_f(update_last=True): + """Callback for `motion_f()`. + + Args: + update_last (bool, optional): should `last_search_motion` be updated? + Set to False when calling from `key_semicolon()` or `key_comma()` + so that the last search motion isn't overwritten. + Defaults to True. + + See Also: + `start_catching_keys()`. + """ + global last_search_motion + pattern = catching_keys_data['keys'] + pos = get_pos(catching_keys_data['input_line'], re.escape(pattern), + catching_keys_data['cur'], True, + catching_keys_data['count']) + catching_keys_data['new_cur'] = max(0, pos) + catching_keys_data['cur'] + if update_last: + last_search_motion = {'motion': "f", 'data': pattern} + cb_key_combo_default(None, None, "") + +def motion_F(input_line, cur, count): + """Go to `count`'th occurence of char to the right and return position. + + See Also: + `motion_base()`. + """ + return start_catching_keys(1, "cb_motion_F", input_line, cur, count) + +def cb_motion_F(update_last=True): + """Callback for `motion_F()`. + + Args: + update_last (bool, optional): should `last_search_motion` be updated? + Set to False when calling from `key_semicolon()` or `key_comma()` + so that the last search motion isn't overwritten. + Defaults to True. + + See Also: + `start_catching_keys()`. + """ + global last_search_motion + pattern = catching_keys_data['keys'] + cur = len(catching_keys_data['input_line']) - catching_keys_data['cur'] + pos = get_pos(catching_keys_data['input_line'][::-1], + re.escape(pattern), + cur, + False, + catching_keys_data['count']) + catching_keys_data['new_cur'] = catching_keys_data['cur'] - max(0, pos + 1) + if update_last: + last_search_motion = {'motion': "F", 'data': pattern} + cb_key_combo_default(None, None, "") + +def motion_t(input_line, cur, count): + """Go to `count`'th occurence of char and return position. + + The position returned is the position of the character to the left of char. + + See Also: + `motion_base()`. + """ + return start_catching_keys(1, "cb_motion_t", input_line, cur, count) + +def cb_motion_t(update_last=True): + """Callback for `motion_t()`. + + Args: + update_last (bool, optional): should `last_search_motion` be updated? + Set to False when calling from `key_semicolon()` or `key_comma()` + so that the last search motion isn't overwritten. + Defaults to True. + + See Also: + `start_catching_keys()`. + """ + global last_search_motion + pattern = catching_keys_data['keys'] + pos = get_pos(catching_keys_data['input_line'], re.escape(pattern), + catching_keys_data['cur'] + 1, + True, catching_keys_data['count']) + pos += 1 + if pos > 0: + catching_keys_data['new_cur'] = pos + catching_keys_data['cur'] - 1 + else: + catching_keys_data['new_cur'] = catching_keys_data['cur'] + if update_last: + last_search_motion = {'motion': "t", 'data': pattern} + cb_key_combo_default(None, None, "") + +def motion_T(input_line, cur, count): + """Go to `count`'th occurence of char to the left and return position. + + The position returned is the position of the character to the right of + char. + + See Also: + `motion_base()`. + """ + return start_catching_keys(1, "cb_motion_T", input_line, cur, count) + +def cb_motion_T(update_last=True): + """Callback for `motion_T()`. + + Args: + update_last (bool, optional): should `last_search_motion` be updated? + Set to False when calling from `key_semicolon()` or `key_comma()` + so that the last search motion isn't overwritten. + Defaults to True. + + See Also: + `start_catching_keys()`. + """ + global last_search_motion + pattern = catching_keys_data['keys'] + pos = get_pos(catching_keys_data['input_line'][::-1], re.escape(pattern), + (len(catching_keys_data['input_line']) - + (catching_keys_data['cur'] + 1)) + 1, + True, catching_keys_data['count']) + pos += 1 + if pos > 0: + catching_keys_data['new_cur'] = catching_keys_data['cur'] - pos + 1 + else: + catching_keys_data['new_cur'] = catching_keys_data['cur'] + if update_last: + last_search_motion = {'motion': "T", 'data': pattern} + cb_key_combo_default(None, None, "") + + +# Keys: +# ----- + +def key_cc(buf, input_line, cur, count): + """Delete line and start Insert mode. + + See Also: + `key_base()`. + """ + weechat.command("", "/input delete_line") + set_mode("INSERT") + +def key_C(buf, input_line, cur, count): + """Delete from cursor to end of line and start Insert mode. + + See Also: + `key_base()`. + """ + weechat.command("", "/input delete_end_of_line") + set_mode("INSERT") + +def key_yy(buf, input_line, cur, count): + """Yank line. + + See Also: + `key_base()`. + """ + cmd = vimode_settings['copy_clipboard_cmd'] + proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE) + proc.communicate(input=input_line.encode()) + +def key_p(buf, input_line, cur, count): + """Paste text. + + See Also: + `key_base()`. + """ + cmd = vimode_settings['paste_clipboard_cmd'] + weechat.hook_process(cmd, 10 * 1000, "cb_key_p", weechat.current_buffer()) + +def cb_key_p(data, command, return_code, output, err): + """Callback for fetching clipboard text and pasting it.""" + buf = "" + this_buffer = data + if output != "": + buf += output.strip() + if return_code == 0: + my_input = weechat.buffer_get_string(this_buffer, "input") + pos = weechat.buffer_get_integer(this_buffer, "input_pos") + my_input = my_input[:pos] + buf + my_input[pos:] + pos += len(buf) + weechat.buffer_set(this_buffer, "input", my_input) + weechat.buffer_set(this_buffer, "input_pos", str(pos)) + return weechat.WEECHAT_RC_OK + +def key_i(buf, input_line, cur, count): + """Start Insert mode. + + See Also: + `key_base()`. + """ + set_mode("INSERT") + +def key_a(buf, input_line, cur, count): + """Move cursor one character to the right and start Insert mode. + + See Also: + `key_base()`. + """ + set_cur(buf, input_line, cur + 1, False) + set_mode("INSERT") + +def key_A(buf, input_line, cur, count): + """Move cursor to end of line and start Insert mode. + + See Also: + `key_base()`. + """ + set_cur(buf, input_line, len(input_line), False) + set_mode("INSERT") + +def key_I(buf, input_line, cur, count): + """Move cursor to first non-blank character and start Insert mode. + + See Also: + `key_base()`. + """ + pos, _, _ = motion_carret(input_line, cur, 0) + set_cur(buf, input_line, pos) + set_mode("INSERT") + +def key_G(buf, input_line, cur, count): + """Scroll to specified line or bottom of buffer. + + See Also: + `key_base()`. + """ + if count > 0: + # This is necessary to prevent weird scroll jumps. + weechat.command("", "/window scroll_top") + weechat.command("", "/window scroll %s" % (count - 1)) + else: + weechat.command("", "/window scroll_bottom") + +def key_r(buf, input_line, cur, count): + """Replace `count` characters under the cursor. + + See Also: + `key_base()`. + """ + start_catching_keys(1, "cb_key_r", input_line, cur, count, buf) + +def cb_key_r(): + """Callback for `key_r()`. + + See Also: + `start_catching_keys()`. + """ + global catching_keys_data + input_line = list(catching_keys_data['input_line']) + count = max(catching_keys_data['count'], 1) + cur = catching_keys_data['cur'] + if cur + count <= len(input_line): + for _ in range(count): + input_line[cur] = catching_keys_data['keys'] + cur += 1 + input_line = "".join(input_line) + weechat.buffer_set(catching_keys_data['buf'], "input", input_line) + set_cur(catching_keys_data['buf'], input_line, cur - 1) + catching_keys_data = {'amount': 0} + +def key_R(buf, input_line, cur, count): + """Start Replace mode. + + See Also: + `key_base()`. + """ + set_mode("REPLACE") + +def key_tilda(buf, input_line, cur, count): + """Switch the case of `count` characters under the cursor. + + See Also: + `key_base()`. + """ + input_line = list(input_line) + count = max(1, count) + while count and cur < len(input_line): + input_line[cur] = input_line[cur].swapcase() + count -= 1 + cur += 1 + input_line = "".join(input_line) + weechat.buffer_set(buf, "input", input_line) + set_cur(buf, input_line, cur) + +def key_alt_j(buf, input_line, cur, count): + """Go to WeeChat buffer. + + Called to preserve WeeChat's alt-j buffer switching. + + This is only called when alt-j is pressed after pressing Esc, because + \x01\x01j is received in key_combo_default which becomes \x01j after + removing the detected Esc key. + If Esc isn't the last pressed key, \x01j is directly received in + key_combo_default. + """ + start_catching_keys(2, "cb_key_alt_j", input_line, cur, count) + +def cb_key_alt_j(): + """Callback for `key_alt_j()`. + + See Also: + `start_catching_keys()`. + """ + global catching_keys_data + weechat.command("", "/buffer " + catching_keys_data['keys']) + catching_keys_data = {'amount': 0} + +def key_semicolon(buf, input_line, cur, count, swap=False): + """Repeat last f, t, F, T `count` times. + + Args: + swap (bool, optional): if True, the last motion will be repeated in the + opposite direction (e.g. "f" instead of "F"). Defaults to False. + + See Also: + `key_base()`. + """ + global catching_keys_data, vi_buffer + catching_keys_data = ({'amount': 0, + 'input_line': input_line, + 'cur': cur, + 'keys': last_search_motion['data'], + 'count': count, + 'new_cur': 0, + 'buf': buf}) + # Swap the motion's case if called from key_comma. + if swap: + motion = last_search_motion['motion'].swapcase() + else: + motion = last_search_motion['motion'] + func = "cb_motion_%s" % motion + vi_buffer = motion + globals()[func](False) + +def key_comma(buf, input_line, cur, count): + """Repeat last f, t, F, T in opposite direction `count` times. + + See Also: + `key_base()`. + """ + key_semicolon(buf, input_line, cur, count, True) + +def key_u(buf, input_line, cur, count): + """Undo change `count` times. + + See Also: + `key_base()`. + """ + buf = weechat.current_buffer() + if buf not in undo_history: + return + for _ in range(max(count, 1)): + if undo_history_index[buf] > -len(undo_history[buf]): + undo_history_index[buf] -= 1 + input_line = undo_history[buf][undo_history_index[buf]] + weechat.buffer_set(buf, "input", input_line) + else: + break + +def key_ctrl_r(buf, input_line, cur, count): + """Redo change `count` times. + + See Also: + `key_base()`. + """ + if buf not in undo_history: + return + for _ in range(max(count, 1)): + if undo_history_index[buf] < -1: + undo_history_index[buf] += 1 + input_line = undo_history[buf][undo_history_index[buf]] + weechat.buffer_set(buf, "input", input_line) + else: + break + + +# Vi key bindings. +# ================ + +# String values will be executed as normal WeeChat commands. +# For functions, see `key_base()` for reference. +VI_KEYS = {'j': "/window scroll_down", + 'k': "/window scroll_up", + 'G': key_G, + 'gg': "/window scroll_top", + 'x': "/input delete_next_char", + 'X': "/input delete_previous_char", + 'dd': "/input delete_line", + 'D': "/input delete_end_of_line", + 'cc': key_cc, + 'C': key_C, + 'i': key_i, + 'a': key_a, + 'A': key_A, + 'I': key_I, + 'yy': key_yy, + 'p': key_p, + 'gt': "/buffer -1", + 'K': "/buffer -1", + 'gT': "/buffer +1", + 'J': "/buffer +1", + 'r': key_r, + 'R': key_R, + '~': key_tilda, + 'nt': "/bar scroll nicklist * -100%", + 'nT': "/bar scroll nicklist * +100%", + '\x01[[A': "/input history_previous", + '\x01[[B': "/input history_next", + '\x01[[C': "/input move_next_char", + '\x01[[D': "/input move_previous_char", + '\x01[[H': "/input move_beginning_of_line", + '\x01[[F': "/input move_end_of_line", + '\x01[[5~': "/window page_up", + '\x01[[6~': "/window page_down", + '\x01[[3~': "/input delete_next_char", + '\x01[[2~': key_i, + '\x01M': "/input return", + '\x01?': "/input move_previous_char", + ' ': "/input move_next_char", + '\x01[j': key_alt_j, + '\x01[1': "/buffer *1", + '\x01[2': "/buffer *2", + '\x01[3': "/buffer *3", + '\x01[4': "/buffer *4", + '\x01[5': "/buffer *5", + '\x01[6': "/buffer *6", + '\x01[7': "/buffer *7", + '\x01[8': "/buffer *8", + '\x01[9': "/buffer *9", + '\x01[0': "/buffer *10", + '\x01^': "/input jump_last_buffer_displayed", + '\x01D': "/window page_down", + '\x01U': "/window page_up", + '\x01Wh': "/window left", + '\x01Wj': "/window down", + '\x01Wk': "/window up", + '\x01Wl': "/window right", + '\x01W=': "/window balance", + '\x01Wx': "/window swap", + '\x01Ws': "/window splith", + '\x01Wv': "/window splitv", + '\x01Wq': "/window merge", + ';': key_semicolon, + ',': key_comma, + 'u': key_u, + '\x01R': key_ctrl_r} + +# Add alt-j bindings. +for i in range(10, 99): + VI_KEYS['\x01[j%s' % i] = "/buffer %s" % i + + +# Key handling. +# ============= + +def cb_key_pressed(data, signal, signal_data): + """Detect potential Esc presses. + + Alt and Esc are detected as the same key in most terminals. The difference + is that Alt signal is sent just before the other pressed key's signal. + We therefore use a timeout (50ms) to detect whether Alt or Esc was pressed. + """ + global last_signal_time + last_signal_time = time.time() + if signal_data == "\x01[": + # In 50ms, check if any other keys were pressed. If not, it's Esc! + weechat.hook_timer(50, 0, 1, "cb_check_esc", + "{:f}".format(last_signal_time)) + return weechat.WEECHAT_RC_OK + +def cb_check_esc(data, remaining_calls): + """Check if the Esc key was pressed and change the mode accordingly.""" + global esc_pressed, vi_buffer, catching_keys_data + # Not perfect, would be better to use direct comparison (==) but that only + # works for py2 and not for py3. + if abs(last_signal_time - float(data)) <= 0.000001: + esc_pressed += 1 + if mode == "SEARCH": + weechat.command("", "/input search_stop_here") + set_mode("NORMAL") + # Cancel any current partial commands. + vi_buffer = "" + catching_keys_data = {'amount': 0} + weechat.bar_item_update("vi_buffer") + return weechat.WEECHAT_RC_OK + +def cb_key_combo_default(data, signal, signal_data): + """Eat and handle key events when in Normal mode, if needed. + + The key_combo_default signal is sent when a key combo is pressed. For + example, alt-k will send the "\x01[k" signal. + + Esc is handled a bit differently to avoid delays, see `cb_key_pressed()`. + """ + global esc_pressed, vi_buffer, cmd_compl_text, cmd_text_orig, \ + cmd_compl_pos, cmd_history_index + + # If Esc was pressed, strip the Esc part from the pressed keys. + # Example: user presses Esc followed by i. This is detected as "\x01[i", + # but we only want to handle "i". + keys = signal_data + if esc_pressed or esc_pressed == -2: + if keys.startswith("\x01[" * esc_pressed): + # Multiples of 3 seem to "cancel" themselves, + # e.g. Esc-Esc-Esc-Alt-j-11 is detected as "\x01[\x01[\x01" + # followed by "\x01[j11" (two different signals). + if signal_data == "\x01[" * 3: + esc_pressed = -1 # `cb_check_esc()` will increment it to 0. + else: + esc_pressed = 0 + # This can happen if a valid combination is started but interrupted + # with Esc, such as Ctrl-W→Esc→w which would send two signals: + # "\x01W\x01[" then "\x01W\x01[w". + # In that case, we still need to handle the next signal ("\x01W\x01[w") + # so we use the special value "-2". + else: + esc_pressed = -2 + keys = keys.split("\x01[")[-1] # Remove the "Esc" part(s). + # Ctrl-Space. + elif keys == "\x01@": + set_mode("NORMAL") + return weechat.WEECHAT_RC_OK_EAT + + # Clear the undo history for this buffer on . + if keys == "\x01M": + buf = weechat.current_buffer() + clear_undo_history(buf) + + # Detect imap_esc presses if any. + if mode == "INSERT": + imap_esc = vimode_settings['imap_esc'] + if not imap_esc: + return weechat.WEECHAT_RC_OK + if (imap_esc.startswith(vi_buffer) and + imap_esc[len(vi_buffer):len(vi_buffer)+1] == keys): + vi_buffer += keys + weechat.bar_item_update("vi_buffer") + weechat.hook_timer(int(vimode_settings['imap_esc_timeout']), 0, 1, + "cb_check_imap_esc", vi_buffer) + elif (vi_buffer and imap_esc.startswith(vi_buffer) and + imap_esc[len(vi_buffer):len(vi_buffer)+1] != keys): + vi_buffer = "" + weechat.bar_item_update("vi_buffer") + # imap_esc sequence detected -- remove the sequence keys from the + # Weechat input bar and enter Normal mode. + if imap_esc == vi_buffer: + buf = weechat.current_buffer() + input_line = weechat.buffer_get_string(buf, "input") + cur = weechat.buffer_get_integer(buf, "input_pos") + input_line = (input_line[:cur-len(imap_esc)+1] + + input_line[cur:]) + weechat.buffer_set(buf, "input", input_line) + set_cur(buf, input_line, cur-len(imap_esc)+1, False) + set_mode("NORMAL") + vi_buffer = "" + weechat.bar_item_update("vi_buffer") + return weechat.WEECHAT_RC_OK_EAT + return weechat.WEECHAT_RC_OK + + # We're in Replace mode — allow "normal" key presses (e.g. "a") and + # overwrite the next character with them, but let the other key presses + # pass normally (e.g. backspace, arrow keys, etc). + if mode == "REPLACE": + if len(keys) == 1: + weechat.command("", "/input delete_next_char") + elif keys == "\x01?": + weechat.command("", "/input move_previous_char") + return weechat.WEECHAT_RC_OK_EAT + return weechat.WEECHAT_RC_OK + + # We're catching keys! Only "normal" key presses interest us (e.g. "a"), + # not complex ones (e.g. backspace). + if len(keys) == 1 and catching_keys_data['amount']: + catching_keys_data['keys'] += keys + catching_keys_data['amount'] -= 1 + # Done catching keys, execute the callback. + if catching_keys_data['amount'] == 0: + globals()[catching_keys_data['callback']]() + vi_buffer = "" + weechat.bar_item_update("vi_buffer") + return weechat.WEECHAT_RC_OK_EAT + + # We're in command-line mode. + if mode == "COMMAND": + buf = weechat.current_buffer() + cmd_text = weechat.buffer_get_string(buf, "input") + weechat.hook_timer(1, 0, 1, "cb_check_cmd_mode", "") + # Return key. + if keys == "\x01M": + weechat.hook_timer(1, 0, 1, "cb_exec_cmd", cmd_text) + if len(cmd_text) > 1 and (not cmd_history or + cmd_history[-1] != cmd_text): + cmd_history.append(cmd_text) + cmd_history_index = 0 + set_mode("NORMAL") + buf = weechat.current_buffer() + input_line = input_line_backup[buf]['input_line'] + weechat.buffer_set(buf, "input", input_line) + set_cur(buf, input_line, input_line_backup[buf]['cur'], False) + # Up arrow. + elif keys == "\x01[[A": + if cmd_history_index > -len(cmd_history): + cmd_history_index -= 1 + cmd_text = cmd_history[cmd_history_index] + weechat.buffer_set(buf, "input", cmd_text) + set_cur(buf, cmd_text, len(cmd_text), False) + # Down arrow. + elif keys == "\x01[[B": + if cmd_history_index < -1: + cmd_history_index += 1 + cmd_text = cmd_history[cmd_history_index] + else: + cmd_history_index = 0 + cmd_text = ":" + weechat.buffer_set(buf, "input", cmd_text) + set_cur(buf, cmd_text, len(cmd_text), False) + # Tab key. No completion when searching ("/"). + elif keys == "\x01I" and cmd_text[0] == ":": + if cmd_text_orig is None: + input_ = list(cmd_text) + del input_[0] + cmd_text_orig = "".join(input_) + cmd_compl_list = [] + for cmd in VI_COMMANDS.keys(): + if cmd.startswith(cmd_text_orig): + cmd_compl_list.append(cmd) + if cmd_compl_list: + curr_suggestion = cmd_compl_list[cmd_compl_pos] + cmd_text = ":%s" % curr_suggestion + cmd_compl_list[cmd_compl_pos] = weechat.string_eval_expression( + "${color:bold}%s${color:-bold}" % curr_suggestion, + {}, {}, {}) + cmd_compl_text = ", ".join(cmd_compl_list) + cmd_compl_pos = (cmd_compl_pos + 1) % len(cmd_compl_list) + weechat.buffer_set(buf, "input", cmd_text) + set_cur(buf, cmd_text, len(cmd_text), False) + # Input. + else: + cmd_compl_text = "" + cmd_text_orig = None + cmd_compl_pos = 0 + weechat.bar_item_update("cmd_completion") + if keys in ["\x01M", "\x01[[A", "\x01[[B"]: + cmd_compl_text = "" + return weechat.WEECHAT_RC_OK_EAT + else: + return weechat.WEECHAT_RC_OK + # Enter command mode. + elif keys in [":", "/"]: + if keys == "/": + weechat.command("", "/input search_text_here") + if not weechat.config_string_to_boolean( + vimode_settings['search_vim']): + return weechat.WEECHAT_RC_OK + else: + buf = weechat.current_buffer() + cur = weechat.buffer_get_integer(buf, "input_pos") + input_line = weechat.buffer_get_string(buf, "input") + input_line_backup[buf] = {'input_line': input_line, 'cur': cur} + input_line = ":" + weechat.buffer_set(buf, "input", input_line) + set_cur(buf, input_line, 1, False) + set_mode("COMMAND") + cmd_compl_text = "" + cmd_text_orig = None + cmd_compl_pos = 0 + return weechat.WEECHAT_RC_OK_EAT + + # Add key to the buffer. + vi_buffer += keys + weechat.bar_item_update("vi_buffer") + if not vi_buffer: + return weechat.WEECHAT_RC_OK + + # Check if the keys have a (partial or full) match. If so, also get the + # keys without the count. (These are the actual keys we should handle.) + # After that, `vi_buffer` is only used for display purposes — only + # `vi_keys` is checked for all the handling. + # If no matches are found, the keys buffer is cleared. + matched, vi_keys, count = get_keys_and_count(vi_buffer) + if not matched: + vi_buffer = "" + return weechat.WEECHAT_RC_OK_EAT + # Check if it's a command (user defined key mapped to a :cmd). + if vi_keys.startswith(":"): + weechat.hook_timer(1, 0, 1, "cb_exec_cmd", "{} {}".format(vi_keys, + count)) + vi_buffer = "" + return weechat.WEECHAT_RC_OK_EAT + # It's a WeeChat command (user defined key mapped to a /cmd). + if vi_keys.startswith("/"): + weechat.command("", vi_keys) + vi_buffer = "" + return weechat.WEECHAT_RC_OK_EAT + + buf = weechat.current_buffer() + input_line = weechat.buffer_get_string(buf, "input") + cur = weechat.buffer_get_integer(buf, "input_pos") + + # It's a default mapping. If the corresponding value is a string, we assume + # it's a WeeChat command. Otherwise, it's a method we'll call. + if vi_keys in VI_KEYS: + if vi_keys not in ['u', '\x01R']: + add_undo_history(buf, input_line) + if isinstance(VI_KEYS[vi_keys], str): + for _ in range(max(count, 1)): + # This is to avoid crashing WeeChat on script reloads/unloads, + # because no hooks must still be running when a script is + # reloaded or unloaded. + if (VI_KEYS[vi_keys] == "/input return" and + input_line.startswith("/script ")): + return weechat.WEECHAT_RC_OK + weechat.command("", VI_KEYS[vi_keys]) + current_cur = weechat.buffer_get_integer(buf, "input_pos") + set_cur(buf, input_line, current_cur) + else: + VI_KEYS[vi_keys](buf, input_line, cur, count) + # It's a motion (e.g. "w") — call `motion_X()` where X is the motion, then + # set the cursor's position to what that function returned. + elif vi_keys in VI_MOTIONS: + if vi_keys in SPECIAL_CHARS: + func = "motion_%s" % SPECIAL_CHARS[vi_keys] + else: + func = "motion_%s" % vi_keys + end, _, _ = globals()[func](input_line, cur, count) + set_cur(buf, input_line, end) + # It's an operator + motion (e.g. "dw") — call `motion_X()` (where X is + # the motion), then we call `operator_Y()` (where Y is the operator) + # with the position `motion_X()` returned. `operator_Y()` should then + # handle changing the input line. + elif (len(vi_keys) > 1 and + vi_keys[0] in VI_OPERATORS and + vi_keys[1:] in VI_MOTIONS): + add_undo_history(buf, input_line) + if vi_keys[1:] in SPECIAL_CHARS: + func = "motion_%s" % SPECIAL_CHARS[vi_keys[1:]] + else: + func = "motion_%s" % vi_keys[1:] + pos, overwrite, catching = globals()[func](input_line, cur, count) + # If it's a catching motion, we don't want to call the operator just + # yet -- this code will run again when the motion is complete, at which + # point we will. + if not catching: + oper = "operator_%s" % vi_keys[0] + globals()[oper](buf, input_line, cur, pos, overwrite) + # The combo isn't completed yet (e.g. just "d"). + else: + return weechat.WEECHAT_RC_OK_EAT + + # We've already handled the key combo, so clear the keys buffer. + if not catching_keys_data['amount']: + vi_buffer = "" + weechat.bar_item_update("vi_buffer") + return weechat.WEECHAT_RC_OK_EAT + +def cb_check_imap_esc(data, remaining_calls): + """Clear the imap_esc sequence after some time if nothing was pressed.""" + global vi_buffer + if vi_buffer == data: + vi_buffer = "" + weechat.bar_item_update("vi_buffer") + return weechat.WEECHAT_RC_OK + +def cb_key_combo_search(data, signal, signal_data): + """Handle keys while search mode is active (if search_vim is enabled).""" + if not weechat.config_string_to_boolean(vimode_settings['search_vim']): + return weechat.WEECHAT_RC_OK + if mode == "COMMAND": + if signal_data == "\x01M": + set_mode("SEARCH") + return weechat.WEECHAT_RC_OK_EAT + elif mode == "SEARCH": + if signal_data == "\x01M": + set_mode("NORMAL") + else: + if signal_data == "n": + weechat.command("", "/input search_next") + elif signal_data == "N": + weechat.command("", "/input search_previous") + # Start a new search. + elif signal_data == "/": + weechat.command("", "/input search_stop_here") + set_mode("NORMAL") + weechat.command("", "/input search_text_here") + return weechat.WEECHAT_RC_OK_EAT + return weechat.WEECHAT_RC_OK + +# Callbacks. +# ========== + +# Bar items. +# ---------- + +def cb_vi_buffer(data, item, window): + """Return the content of the vi buffer (pressed keys on hold).""" + return vi_buffer + +def cb_cmd_completion(data, item, window): + """Return the text of the command line.""" + return cmd_compl_text + +def cb_mode_indicator(data, item, window): + """Return the current mode (INSERT/NORMAL/REPLACE/...).""" + return "{}{}{}{}{}".format( + weechat.color(mode_colors[mode]), + vimode_settings['mode_indicator_prefix'], mode, + vimode_settings['mode_indicator_suffix'], weechat.color("reset")) + +def cb_line_numbers(data, item, window): + """Fill the line numbers bar item.""" + bar_height = weechat.window_get_integer(window, "win_chat_height") + content = "" + for i in range(1, bar_height + 1): + content += "{}{}{}\n".format(vimode_settings['line_number_prefix'], i, + vimode_settings['line_number_suffix']) + return content + +# Callbacks for the line numbers bar. +# ................................... + +def cb_update_line_numbers(data, signal, signal_data): + """Call `cb_timer_update_line_numbers()` when switching buffers. + + A timer is required because the bar item is refreshed before the new buffer + is actually displayed, so ``win_chat_height`` would refer to the old + buffer. Using a timer refreshes the item after the new buffer is displayed. + """ + weechat.hook_timer(10, 0, 1, "cb_timer_update_line_numbers", "") + return weechat.WEECHAT_RC_OK + +def cb_timer_update_line_numbers(data, remaining_calls): + """Update the line numbers bar item.""" + weechat.bar_item_update("line_numbers") + return weechat.WEECHAT_RC_OK + + +# Config. +# ------- + +def cb_config(data, option, value): + """Script option changed, update our copy.""" + option_name = option.split(".")[-1] + if option_name in vimode_settings: + vimode_settings[option_name] = value + if option_name == 'user_mappings': + load_user_mappings() + if "_color" in option_name: + load_mode_colors() + return weechat.WEECHAT_RC_OK + +def load_mode_colors(): + mode_colors.update({ + 'NORMAL': "{},{}".format( + vimode_settings['mode_indicator_normal_color'], + vimode_settings['mode_indicator_normal_color_bg']), + 'INSERT': "{},{}".format( + vimode_settings['mode_indicator_insert_color'], + vimode_settings['mode_indicator_insert_color_bg']), + 'REPLACE': "{},{}".format( + vimode_settings['mode_indicator_replace_color'], + vimode_settings['mode_indicator_replace_color_bg']), + 'COMMAND': "{},{}".format( + vimode_settings['mode_indicator_cmd_color'], + vimode_settings['mode_indicator_cmd_color_bg']), + 'SEARCH': "{},{}".format( + vimode_settings['mode_indicator_search_color'], + vimode_settings['mode_indicator_search_color_bg']) + }) + +def load_user_mappings(): + """Load user-defined mappings.""" + mappings = {} + if vimode_settings['user_mappings']: + mappings.update(json.loads(vimode_settings['user_mappings'])) + vimode_settings['user_mappings'] = mappings + + +# Command-line execution. +# ----------------------- + +def cb_exec_cmd(data, remaining_calls): + """Translate and execute our custom commands to WeeChat command.""" + # Process the entered command. + data = list(data) + del data[0] + data = "".join(data) + # s/foo/bar command. + if data.startswith("s/"): + cmd = data + parsed_cmd = next(csv.reader(StringIO(cmd), delimiter="/", + escapechar="\\")) + pattern = re.escape(parsed_cmd[1]) + repl = parsed_cmd[2] + repl = re.sub(r"([^\\])&", r"\1" + pattern, repl) + flag = None + if len(parsed_cmd) == 4: + flag = parsed_cmd[3] + count = 1 + if flag == "g": + count = 0 + buf = weechat.current_buffer() + input_line = weechat.buffer_get_string(buf, "input") + input_line = re.sub(pattern, repl, input_line, count) + weechat.buffer_set(buf, "input", input_line) + # Shell command. + elif data.startswith("!"): + weechat.command("", "/exec -buffer shell %s" % data[1:]) + # Commands like `:22`. This should start cursor mode (``/cursor``) and take + # us to the relevant line. + elif data.isdigit(): + line_number = int(data) + hdata_window = weechat.hdata_get("window") + window = weechat.current_window() + x = weechat.hdata_integer(hdata_window, window, "win_chat_x") + y = (weechat.hdata_integer(hdata_window, window, "win_chat_y") + + (line_number - 1)) + weechat.command("", "/cursor go {},{}".format(x, y)) + # Check againt defined commands. + elif data: + raw_data = data + data = data.split(" ", 1) + cmd = data[0] + args = "" + if len(data) == 2: + args = data[1] + if cmd in VI_COMMANDS: + if isinstance(VI_COMMANDS[cmd], str): + weechat.command("", "%s %s" % (VI_COMMANDS[cmd], args)) + else: + VI_COMMANDS[cmd](args) + else: + # Check for commands not sepearated by space (e.g. "b2") + for i in range(1, len(raw_data)): + tmp_cmd = raw_data[:i] + tmp_args = raw_data[i:] + if tmp_cmd in VI_COMMANDS and tmp_args.isdigit(): + weechat.command("", "%s %s" % (VI_COMMANDS[tmp_cmd], + tmp_args)) + return weechat.WEECHAT_RC_OK + # No vi commands found, run the command as WeeChat command + weechat.command("", "/{} {}".format(cmd, args)) + return weechat.WEECHAT_RC_OK + +def cb_vimode_go_to_normal(data, buf, args): + set_mode("NORMAL") + return weechat.WEECHAT_RC_OK + +# Script commands. +# ---------------- + +def cb_vimode_cmd(data, buf, args): + """Handle script commands (``/vimode ``).""" + # ``/vimode`` or ``/vimode help`` + if not args or args == "help": + weechat.prnt("", "[vimode.py] %s" % README_URL) + # ``/vimode bind_keys`` or ``/vimode bind_keys --list`` + elif args.startswith("bind_keys"): + infolist = weechat.infolist_get("key", "", "default") + weechat.infolist_reset_item_cursor(infolist) + commands = ["/key unbind ctrl-W", + "/key bind ctrl-W /input delete_previous_word", + "/key bind ctrl-^ /input jump_last_buffer_displayed", + "/key bind ctrl-Wh /window left", + "/key bind ctrl-Wj /window down", + "/key bind ctrl-Wk /window up", + "/key bind ctrl-Wl /window right", + "/key bind ctrl-W= /window balance", + "/key bind ctrl-Wx /window swap", + "/key bind ctrl-Ws /window splith", + "/key bind ctrl-Wv /window splitv", + "/key bind ctrl-Wq /window merge"] + while weechat.infolist_next(infolist): + key = weechat.infolist_string(infolist, "key") + if re.match(REGEX_PROBLEMATIC_KEYBINDINGS, key): + commands.append("/key unbind %s" % key) + if args == "bind_keys": + weechat.prnt("", "Running commands:") + for command in commands: + weechat.command("", command) + weechat.prnt("", "Done.") + elif args == "bind_keys --list": + weechat.prnt("", "Listing commands we'll run:") + for command in commands: + weechat.prnt("", " %s" % command) + weechat.prnt("", "Done.") + return weechat.WEECHAT_RC_OK + + +# Helpers. +# ======== + +# Motions/keys helpers. +# --------------------- + +def get_pos(data, regex, cur, ignore_cur=False, count=0): + """Return the position of `regex` match in `data`, starting at `cur`. + + Args: + data (str): the data to search in. + regex (pattern): regex pattern to search for. + cur (int): where to start the search. + ignore_cur (bool, optional): should the first match be ignored if it's + also the character at `cur`? + Defaults to False. + count (int, optional): the index of the match to return. Defaults to 0. + + Returns: + int: position of the match. -1 if no matches are found. + """ + # List of the *positions* of the found patterns. + matches = [m.start() for m in re.finditer(regex, data[cur:])] + pos = -1 + if count: + if len(matches) > count - 1: + if ignore_cur and matches[0] == 0: + if len(matches) > count: + pos = matches[count] + else: + pos = matches[count - 1] + elif matches: + if ignore_cur and matches[0] == 0: + if len(matches) > 1: + pos = matches[1] + else: + pos = matches[0] + return pos + +def set_cur(buf, input_line, pos, cap=True): + """Set the cursor's position. + + Args: + buf (str): pointer to the current WeeChat buffer. + input_line (str): the content of the input line. + pos (int): the position to set the cursor to. + cap (bool, optional): if True, the `pos` will shortened to the length + of `input_line` if it's too long. Defaults to True. + """ + if cap: + pos = min(pos, len(input_line) - 1) + weechat.buffer_set(buf, "input_pos", str(pos)) + +def start_catching_keys(amount, callback, input_line, cur, count, buf=None): + """Start catching keys. Used for special commands (e.g. "f", "r"). + + amount (int): amount of keys to catch. + callback (str): name of method to call once all keys are caught. + input_line (str): input line's content. + cur (int): cursor's position. + count (int): count, e.g. "2" for "2fs". + buf (str, optional): pointer to the current WeeChat buffer. + Defaults to None. + + `catching_keys_data` is a dict with the above arguments, as well as: + keys (str): pressed keys will be added under this key. + new_cur (int): the new cursor's position, set in the callback. + + When catching keys is active, normal pressed keys (e.g. "a" but not arrows) + will get added to `catching_keys_data` under the key "keys", and will not + be handled any further. + Once all keys are caught, the method defined in the "callback" key is + called, and can use the data in `catching_keys_data` to perform its action. + """ + global catching_keys_data + if "new_cur" in catching_keys_data: + new_cur = catching_keys_data['new_cur'] + catching_keys_data = {'amount': 0} + return new_cur, True, False + catching_keys_data = ({'amount': amount, + 'callback': callback, + 'input_line': input_line, + 'cur': cur, + 'keys': "", + 'count': count, + 'new_cur': 0, + 'buf': buf}) + return cur, False, True + +def get_keys_and_count(combo): + """Check if `combo` is a valid combo and extract keys/counts if so. + + Args: + combo (str): pressed keys combo. + + Returns: + matched (bool): True if the combo has a (partial or full) match, False + otherwise. + combo (str): `combo` with the count removed. These are the actual keys + we should handle. User mappings are also expanded. + count (int): count for `combo`. + """ + # Look for a potential match (e.g. "d" might become "dw" or "dd" so we + # accept it, but "d9" is invalid). + matched = False + # Digits are allowed at the beginning (counts or "0"). + count = 0 + if combo.isdigit(): + matched = True + elif combo and combo[0].isdigit(): + count = "" + for char in combo: + if char.isdigit(): + count += char + else: + break + combo = combo.replace(count, "", 1) + count = int(count) + # It's a user defined key. Expand it. + if combo in vimode_settings['user_mappings']: + combo = vimode_settings['user_mappings'][combo] + # It's a WeeChat command. + if not matched and combo.startswith("/"): + matched = True + # Check against defined keys. + if not matched: + for key in VI_KEYS: + if key.startswith(combo): + matched = True + break + # Check against defined motions. + if not matched: + for motion in VI_MOTIONS: + if motion.startswith(combo): + matched = True + break + # Check against defined operators + motions. + if not matched: + for operator in VI_OPERATORS: + if combo.startswith(operator): + # Check for counts before the motion (but after the operator). + vi_keys_no_op = combo[len(operator):] + # There's no motion yet. + if vi_keys_no_op.isdigit(): + matched = True + break + # Get the motion count, then multiply the operator count by + # it, similar to vim's behavior. + elif vi_keys_no_op and vi_keys_no_op[0].isdigit(): + motion_count = "" + for char in vi_keys_no_op: + if char.isdigit(): + motion_count += char + else: + break + # Remove counts from `vi_keys_no_op`. + combo = combo.replace(motion_count, "", 1) + motion_count = int(motion_count) + count = max(count, 1) * motion_count + # Check against defined motions. + for motion in VI_MOTIONS: + if motion.startswith(combo[1:]): + matched = True + break + return matched, combo, count + + +# Other helpers. +# -------------- + +def set_mode(arg): + """Set the current mode and update the bar mode indicator.""" + global mode + buf = weechat.current_buffer() + input_line = weechat.buffer_get_string(buf, "input") + if mode == "INSERT" and arg == "NORMAL": + add_undo_history(buf, input_line) + mode = arg + # If we're going to Normal mode, the cursor must move one character to the + # left. + if mode == "NORMAL": + cur = weechat.buffer_get_integer(buf, "input_pos") + set_cur(buf, input_line, cur - 1, False) + weechat.bar_item_update("mode_indicator") + +def cb_check_cmd_mode(data, remaining_calls): + """Exit command mode if user erases the leading ':' character.""" + buf = weechat.current_buffer() + cmd_text = weechat.buffer_get_string(buf, "input") + if not cmd_text: + set_mode("NORMAL") + return weechat.WEECHAT_RC_OK + +def add_undo_history(buf, input_line): + """Add an item to the per-buffer undo history.""" + if buf in undo_history: + if not undo_history[buf] or undo_history[buf][-1] != input_line: + undo_history[buf].append(input_line) + undo_history_index[buf] = -1 + else: + undo_history[buf] = ['', input_line] + undo_history_index[buf] = -1 + +def clear_undo_history(buf): + """Clear the undo history for a given buffer.""" + undo_history[buf] = [''] + undo_history_index[buf] = -1 + +def print_warning(text): + """Print warning, in red, to the current buffer.""" + weechat.prnt("", ("%s[vimode.py] %s" % (weechat.color("red"), text))) + +def check_warnings(): + """Warn the user about problematic key bindings and tmux/screen.""" + user_warned = False + # Warn the user about problematic key bindings that may conflict with + # vimode. + # The solution is to remove these key bindings, but that's up to the user. + infolist = weechat.infolist_get("key", "", "default") + problematic_keybindings = [] + while weechat.infolist_next(infolist): + key = weechat.infolist_string(infolist, "key") + command = weechat.infolist_string(infolist, "command") + if re.match(REGEX_PROBLEMATIC_KEYBINDINGS, key): + problematic_keybindings.append("%s -> %s" % (key, command)) + if problematic_keybindings: + user_warned = True + print_warning("Problematic keybindings detected:") + for keybinding in problematic_keybindings: + print_warning(" %s" % keybinding) + print_warning("These keybindings may conflict with vimode.") + print_warning("You can remove problematic key bindings and add" + " recommended ones by using /vimode bind_keys, or only" + " list them with /vimode bind_keys --list") + print_warning("For help, see: %s" % FAQ_KEYBINDINGS) + del problematic_keybindings + # Warn tmux/screen users about possible Esc detection delays. + if "STY" in os.environ or "TMUX" in os.environ: + if user_warned: + weechat.prnt("", "") + user_warned = True + print_warning("tmux/screen users, see: %s" % FAQ_ESC) + if (user_warned and not + weechat.config_string_to_boolean(vimode_settings['no_warn'])): + if user_warned: + weechat.prnt("", "") + print_warning("To force disable warnings, you can set" + " plugins.var.python.vimode.no_warn to 'on'") + + +# Main script. +# ============ + +if __name__ == "__main__": + weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, + SCRIPT_LICENSE, SCRIPT_DESC, "", "") + # Warn the user if he's using an unsupported WeeChat version. + VERSION = weechat.info_get("version_number", "") + if int(VERSION) < 0x01000000: + print_warning("Please upgrade to WeeChat ≥ 1.0.0. Previous versions" + " are not supported.") + # Set up script options. + for option, value in list(vimode_settings.items()): + if weechat.config_is_set_plugin(option): + vimode_settings[option] = weechat.config_get_plugin(option) + else: + weechat.config_set_plugin(option, value[0]) + vimode_settings[option] = value[0] + weechat.config_set_desc_plugin(option, + "%s (default: \"%s\")" % (value[1], + value[0])) + load_user_mappings() + load_mode_colors() + # Warn the user about possible problems if necessary. + if not weechat.config_string_to_boolean(vimode_settings['no_warn']): + check_warnings() + # Create bar items and setup hooks. + weechat.bar_item_new("mode_indicator", "cb_mode_indicator", "") + weechat.bar_item_new("cmd_completion", "cb_cmd_completion", "") + weechat.bar_item_new("vi_buffer", "cb_vi_buffer", "") + weechat.bar_item_new("line_numbers", "cb_line_numbers", "") + if int(VERSION) >= 0x02090000: + weechat.bar_new("vi_line_numbers", "on", "0", "window", "", "left", + "vertical", "vertical", "0", "0", "default", "default", + "default", "default", "0", "line_numbers") + else: + weechat.bar_new("vi_line_numbers", "on", "0", "window", "", "left", + "vertical", "vertical", "0", "0", "default", "default", + "default", "0", "line_numbers") + weechat.hook_config("plugins.var.python.%s.*" % SCRIPT_NAME, "cb_config", + "") + weechat.hook_signal("key_pressed", "cb_key_pressed", "") + weechat.hook_signal("key_combo_default", "cb_key_combo_default", "") + weechat.hook_signal("key_combo_search", "cb_key_combo_search", "") + weechat.hook_signal("buffer_switch", "cb_update_line_numbers", "") + weechat.hook_command("vimode", SCRIPT_DESC, "[help | bind_keys [--list]]", + " help: show help\n" + "bind_keys: unbind problematic keys, and bind" + " recommended keys to use in WeeChat\n" + " --list: only list changes", + "help || bind_keys |--list", + "cb_vimode_cmd", "") + weechat.hook_command("vimode_go_to_normal", + ("This command can be used for key bindings to go to " + "normal mode."), + "", "", "", "cb_vimode_go_to_normal", "") + # Remove obsolete bar. + vi_cmd_bar = weechat.bar_search("vi_cmd") + weechat.bar_remove(vi_cmd_bar) diff --git a/.weechat/relay.conf b/.weechat/relay.conf new file mode 100644 index 00000000..341b8112 --- /dev/null +++ b/.weechat/relay.conf @@ -0,0 +1,59 @@ +# +# weechat -- relay.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +auto_open_buffer = on +raw_messages = 256 + +[color] +client = cyan +status_active = lightblue +status_auth_failed = lightred +status_connecting = yellow +status_disconnected = lightred +status_waiting_auth = brown +text = default +text_bg = default +text_selected = white + +[network] +allow_empty_password = off +allowed_ips = "" +auth_timeout = 60 +bind_address = "" +clients_purge_delay = 0 +compression_level = 6 +ipv6 = on +max_clients = 5 +nonce_size = 16 +password = "" +password_hash_algo = "*" +password_hash_iterations = 100000 +ssl_cert_key = "%h/ssl/relay.pem" +ssl_priorities = "NORMAL:-VERS-SSL3.0" +totp_secret = "" +totp_window = 0 +websocket_allowed_origins = "" + +[irc] +backlog_max_minutes = 1440 +backlog_max_number = 256 +backlog_since_last_disconnect = on +backlog_since_last_message = off +backlog_tags = "irc_privmsg" +backlog_time_format = "[%H:%M] " + +[weechat] +commands = "" + +[port] + +[path] diff --git a/.weechat/ruby.conf b/.weechat/ruby.conf new file mode 100644 index 00000000..f6de7fbf --- /dev/null +++ b/.weechat/ruby.conf @@ -0,0 +1,14 @@ +# +# weechat -- ruby.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +check_license = off +eval_keep_context = on diff --git a/.weechat/script.conf b/.weechat/script.conf new file mode 100644 index 00000000..121f1891 --- /dev/null +++ b/.weechat/script.conf @@ -0,0 +1,56 @@ +# +# weechat -- script.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +columns = "%s %n %V %v %u | %d | %t" +diff_color = on +diff_command = "auto" +display_source = on +quiet_actions = on +sort = "i,p,n" +translate_description = on +use_keys = on + +[color] +status_autoloaded = cyan +status_held = white +status_installed = lightcyan +status_obsolete = lightmagenta +status_popular = yellow +status_running = lightgreen +status_unknown = lightred +text = default +text_bg = default +text_bg_selected = red +text_date = default +text_date_selected = white +text_delimiters = default +text_description = default +text_description_selected = white +text_extension = default +text_extension_selected = white +text_name = cyan +text_name_selected = lightcyan +text_selected = white +text_tags = brown +text_tags_selected = yellow +text_version = magenta +text_version_loaded = default +text_version_loaded_selected = white +text_version_selected = lightmagenta + +[scripts] +autoload = on +cache_expire = 1440 +download_timeout = 30 +hold = "" +path = "%h/script" +url = "https://weechat.org/files/plugins.xml.gz" diff --git a/.weechat/script/plugins.xml.gz b/.weechat/script/plugins.xml.gz new file mode 100644 index 00000000..7521e691 Binary files /dev/null and b/.weechat/script/plugins.xml.gz differ diff --git a/.weechat/sec.conf b/.weechat/sec.conf new file mode 100644 index 00000000..8c60d034 --- /dev/null +++ b/.weechat/sec.conf @@ -0,0 +1,18 @@ +# +# weechat -- sec.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[crypt] +cipher = aes256 +hash_algo = sha256 +passphrase_file = "" +salt = on + +[data] diff --git a/.weechat/spell.conf b/.weechat/spell.conf new file mode 100644 index 00000000..f65348de --- /dev/null +++ b/.weechat/spell.conf @@ -0,0 +1,33 @@ +# +# weechat -- spell.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[color] +misspelled = lightred +suggestion = default +suggestion_delimiter_dict = cyan +suggestion_delimiter_word = cyan + +[check] +commands = "away,command,cycle,kick,kickban,me,msg,notice,part,query,quit,topic" +default_dict = "" +during_search = off +enabled = off +real_time = off +suggestions = -1 +word_min_length = 2 + +[dict] + +[look] +suggestion_delimiter_dict = " / " +suggestion_delimiter_word = "," + +[option] diff --git a/.weechat/tcl.conf b/.weechat/tcl.conf new file mode 100644 index 00000000..4c0e3896 --- /dev/null +++ b/.weechat/tcl.conf @@ -0,0 +1,14 @@ +# +# weechat -- tcl.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +check_license = off +eval_keep_context = on diff --git a/.weechat/trigger.conf b/.weechat/trigger.conf new file mode 100644 index 00000000..24246667 --- /dev/null +++ b/.weechat/trigger.conf @@ -0,0 +1,67 @@ +# +# weechat -- trigger.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +enabled = on +monitor_strip_colors = off + +[color] +flag_command = lightgreen +flag_conditions = yellow +flag_post_action = lightblue +flag_regex = lightcyan +flag_return_code = lightmagenta +regex = white +replace = cyan +trigger = green +trigger_disabled = red + +[trigger] +beep.arguments = "" +beep.command = "/print -beep" +beep.conditions = "${tg_displayed} && (${tg_highlight} || ${tg_msg_pv})" +beep.enabled = on +beep.hook = print +beep.post_action = none +beep.regex = "" +beep.return_code = ok +cmd_pass.arguments = "5000|input_text_display;5000|history_add;5000|irc_command_auth" +cmd_pass.command = "" +cmd_pass.conditions = "" +cmd_pass.enabled = on +cmd_pass.hook = modifier +cmd_pass.post_action = none +cmd_pass.regex = "==^((/(msg|m|quote) +(-server +[^ ]+ +)?nickserv +(id|identify|set +password|ghost +[^ ]+|release +[^ ]+|regain +[^ ]+|recover +[^ ]+) +)|/oper +[^ ]+ +|/quote +pass +|/set +[^ ]*password[^ ]* +|/secure +(passphrase|decrypt|set +[^ ]+) +)(.*)==${re:1}${hide:*,${re:+}}" +cmd_pass.return_code = ok +cmd_pass_register.arguments = "5000|input_text_display;5000|history_add;5000|irc_command_auth" +cmd_pass_register.command = "" +cmd_pass_register.conditions = "" +cmd_pass_register.enabled = on +cmd_pass_register.hook = modifier +cmd_pass_register.post_action = none +cmd_pass_register.regex = "==^(/(msg|m|quote) +nickserv +register +)([^ ]+)(.*)==${re:1}${hide:*,${re:3}}${re:4}" +cmd_pass_register.return_code = ok +msg_auth.arguments = "5000|irc_message_auth" +msg_auth.command = "" +msg_auth.conditions = "" +msg_auth.enabled = on +msg_auth.hook = modifier +msg_auth.post_action = none +msg_auth.regex = "==^(.*(id|identify|set +password|register|ghost +[^ ]+|release +[^ ]+|regain +[^ ]+|recover +[^ ]+) +)(.*)==${re:1}${hide:*,${re:+}}" +msg_auth.return_code = ok +server_pass.arguments = "5000|input_text_display;5000|history_add" +server_pass.command = "" +server_pass.conditions = "" +server_pass.enabled = on +server_pass.hook = modifier +server_pass.post_action = none +server_pass.regex = "==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5}" +server_pass.return_code = ok diff --git a/.weechat/weechat.conf b/.weechat/weechat.conf new file mode 100644 index 00000000..15d80295 --- /dev/null +++ b/.weechat/weechat.conf @@ -0,0 +1,685 @@ +# +# weechat -- weechat.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[debug] + +[startup] +command_after_plugins = "" +command_before_plugins = "" +display_logo = on +display_version = on +sys_rlimit = "" + +[look] +align_end_of_lines = message +align_multiline_words = on +bar_more_down = "++" +bar_more_left = "<<" +bar_more_right = ">>" +bar_more_up = "--" +bare_display_exit_on_input = on +bare_display_time_format = "%H:%M" +buffer_auto_renumber = on +buffer_notify_default = all +buffer_position = end +buffer_search_case_sensitive = off +buffer_search_force_default = off +buffer_search_regex = off +buffer_search_where = prefix_message +buffer_time_format = "%H:%M:%S" +buffer_time_same = "" +color_basic_force_bold = off +color_inactive_buffer = on +color_inactive_message = on +color_inactive_prefix = on +color_inactive_prefix_buffer = on +color_inactive_time = off +color_inactive_window = on +color_nick_offline = off +color_pairs_auto_reset = 5 +color_real_white = off +command_chars = "" +command_incomplete = off +confirm_quit = off +confirm_upgrade = off +day_change = on +day_change_message_1date = "-- %a, %d %b %Y --" +day_change_message_2dates = "-- %%a, %%d %%b %%Y (%a, %d %b %Y) --" +eat_newline_glitch = off +emphasized_attributes = "" +highlight = "" +highlight_regex = "" +highlight_tags = "" +hotlist_add_conditions = "${away} || ${buffer.num_displayed} == 0 || ${info:relay_client_count,weechat,connected} > 0" +hotlist_buffer_separator = ", " +hotlist_count_max = 2 +hotlist_count_min_msg = 2 +hotlist_names_count = 3 +hotlist_names_length = 0 +hotlist_names_level = 12 +hotlist_names_merged_buffers = off +hotlist_prefix = "H: " +hotlist_remove = merged +hotlist_short_names = on +hotlist_sort = group_time_asc +hotlist_suffix = "" +hotlist_unique_numbers = on +input_cursor_scroll = 20 +input_share = none +input_share_overwrite = off +input_undo_max = 32 +item_away_message = on +item_buffer_filter = "*" +item_buffer_zoom = "!" +item_mouse_status = "M" +item_time_format = "%H:%M" +jump_current_to_previous_buffer = on +jump_previous_buffer_when_closing = on +jump_smart_back_to_buffer = on +key_bind_safe = on +key_grab_delay = 800 +mouse = off +mouse_timer_delay = 100 +nick_color_force = "" +nick_color_hash = djb2 +nick_color_hash_salt = "" +nick_color_stop_chars = "_|[" +nick_prefix = "" +nick_suffix = "" +paste_auto_add_newline = on +paste_bracketed = on +paste_bracketed_timer_delay = 10 +paste_max_lines = 1 +prefix_action = " *" +prefix_align = right +prefix_align_max = 0 +prefix_align_min = 0 +prefix_align_more = "+" +prefix_align_more_after = on +prefix_buffer_align = right +prefix_buffer_align_max = 0 +prefix_buffer_align_more = "+" +prefix_buffer_align_more_after = on +prefix_error = "=!=" +prefix_join = "-->" +prefix_network = "--" +prefix_quit = "<--" +prefix_same_nick = "" +prefix_same_nick_middle = "" +prefix_suffix = "|" +quote_nick_prefix = "<" +quote_nick_suffix = ">" +quote_time_format = "%H:%M:%S" +read_marker = line +read_marker_always_show = off +read_marker_string = "- " +save_config_on_exit = on +save_config_with_fsync = off +save_layout_on_exit = none +scroll_amount = 3 +scroll_bottom_after_switch = off +scroll_page_percent = 100 +search_text_not_found_alert = on +separator_horizontal = "-" +separator_vertical = "" +tab_width = 1 +time_format = "%a, %d %b %Y %T" +window_auto_zoom = off +window_separator_horizontal = on +window_separator_vertical = on +window_title = "" +word_chars_highlight = "!\u00A0,-,_,|,alnum" +word_chars_input = "!\u00A0,-,_,|,alnum" + +[palette] + +[color] +bar_more = lightmagenta +chat = default +chat_bg = default +chat_buffer = white +chat_channel = white +chat_day_change = cyan +chat_delimiters = green +chat_highlight = yellow +chat_highlight_bg = magenta +chat_host = cyan +chat_inactive_buffer = default +chat_inactive_window = default +chat_nick = lightcyan +chat_nick_colors = "cyan,magenta,green,brown,lightblue,default,lightcyan,lightmagenta,lightgreen,blue" +chat_nick_offline = default +chat_nick_offline_highlight = default +chat_nick_offline_highlight_bg = blue +chat_nick_other = cyan +chat_nick_prefix = green +chat_nick_self = white +chat_nick_suffix = green +chat_prefix_action = white +chat_prefix_buffer = brown +chat_prefix_buffer_inactive_buffer = default +chat_prefix_error = yellow +chat_prefix_join = lightgreen +chat_prefix_more = lightmagenta +chat_prefix_network = magenta +chat_prefix_quit = lightred +chat_prefix_suffix = green +chat_read_marker = magenta +chat_read_marker_bg = default +chat_server = brown +chat_tags = red +chat_text_found = yellow +chat_text_found_bg = lightmagenta +chat_time = default +chat_time_delimiters = brown +chat_value = cyan +chat_value_null = blue +emphasized = yellow +emphasized_bg = magenta +input_actions = lightgreen +input_text_not_found = red +item_away = yellow +nicklist_away = cyan +nicklist_group = green +separator = blue +status_count_highlight = magenta +status_count_msg = brown +status_count_other = default +status_count_private = green +status_data_highlight = lightmagenta +status_data_msg = yellow +status_data_other = default +status_data_private = lightgreen +status_filter = green +status_more = yellow +status_mouse = green +status_name = white +status_name_ssl = lightgreen +status_nicklist_count = default +status_number = yellow +status_time = default + +[completion] +base_word_until_cursor = on +command_inline = on +default_template = "%(nicks)|%(irc_channels)" +nick_add_space = on +nick_case_sensitive = off +nick_completer = ": " +nick_first_only = off +nick_ignore_chars = "[]`_-^" +partial_completion_alert = on +partial_completion_command = off +partial_completion_command_arg = off +partial_completion_count = on +partial_completion_other = off +partial_completion_templates = "config_options" + +[history] +display_default = 5 +max_buffer_lines_minutes = 0 +max_buffer_lines_number = 4096 +max_commands = 100 +max_visited_buffers = 50 + +[proxy] + +[network] +connection_timeout = 60 +gnutls_ca_file = "/etc/ssl/certs/ca-certificates.crt" +gnutls_handshake_timeout = 30 +proxy_curl = "" + +[plugin] +autoload = "*" +debug = off +extension = ".so,.dll" +path = "%h/plugins" +save_config_on_unload = on + +[bar] +buflist.color_bg = default +buflist.color_bg_inactive = default +buflist.color_delim = default +buflist.color_fg = default +buflist.conditions = "" +buflist.filling_left_right = vertical +buflist.filling_top_bottom = columns_vertical +buflist.hidden = off +buflist.items = "buflist" +buflist.position = left +buflist.priority = 0 +buflist.separator = on +buflist.size = 0 +buflist.size_max = 0 +buflist.type = root +fset.color_bg = default +fset.color_bg_inactive = default +fset.color_delim = cyan +fset.color_fg = default +fset.conditions = "${buffer.full_name} == fset.fset" +fset.filling_left_right = vertical +fset.filling_top_bottom = horizontal +fset.hidden = off +fset.items = "fset" +fset.position = top +fset.priority = 0 +fset.separator = on +fset.size = 3 +fset.size_max = 3 +fset.type = window +input.color_bg = default +input.color_bg_inactive = default +input.color_delim = cyan +input.color_fg = default +input.conditions = "" +input.filling_left_right = vertical +input.filling_top_bottom = horizontal +input.hidden = off +input.items = "mode_indicator+[input_prompt]+(away),[input_search],[input_paste],input_text,[vi_buffer]" +input.position = bottom +input.priority = 1000 +input.separator = off +input.size = 1 +input.size_max = 0 +input.type = window +nicklist.color_bg = default +nicklist.color_bg_inactive = default +nicklist.color_delim = cyan +nicklist.color_fg = default +nicklist.conditions = "${nicklist}" +nicklist.filling_left_right = vertical +nicklist.filling_top_bottom = columns_vertical +nicklist.hidden = off +nicklist.items = "buffer_nicklist" +nicklist.position = right +nicklist.priority = 200 +nicklist.separator = on +nicklist.size = 0 +nicklist.size_max = 0 +nicklist.type = window +status.color_bg = blue +status.color_bg_inactive = default +status.color_delim = cyan +status.color_fg = default +status.conditions = "" +status.filling_left_right = vertical +status.filling_top_bottom = horizontal +status.hidden = off +status.items = "[time],[buffer_last_number],[buffer_plugin],buffer_number+:+buffer_name+(buffer_modes)+{buffer_nicklist_count}+buffer_zoom+buffer_filter,scroll,[lag],[hotlist],completion,cmd_completion" +status.position = bottom +status.priority = 500 +status.separator = off +status.size = 1 +status.size_max = 0 +status.type = window +title.color_bg = blue +title.color_bg_inactive = default +title.color_delim = cyan +title.color_fg = default +title.conditions = "" +title.filling_left_right = vertical +title.filling_top_bottom = horizontal +title.hidden = off +title.items = "buffer_title" +title.position = top +title.priority = 500 +title.separator = off +title.size = 1 +title.size_max = 0 +title.type = window +vi_line_numbers.color_bg = default +vi_line_numbers.color_bg_inactive = default +vi_line_numbers.color_delim = default +vi_line_numbers.color_fg = default +vi_line_numbers.conditions = "" +vi_line_numbers.filling_left_right = vertical +vi_line_numbers.filling_top_bottom = vertical +vi_line_numbers.hidden = on +vi_line_numbers.items = "line_numbers" +vi_line_numbers.position = left +vi_line_numbers.priority = 0 +vi_line_numbers.separator = off +vi_line_numbers.size = 0 +vi_line_numbers.size_max = 0 +vi_line_numbers.type = window + +[layout] + +[notify] + +[filter] + +[key] +ctrl-? = "/input delete_previous_char" +ctrl-A = "/input move_beginning_of_line" +ctrl-B = "/input move_previous_char" +ctrl-C_ = "/input insert \x1F" +ctrl-Cb = "/input insert \x02" +ctrl-Cc = "/input insert \x03" +ctrl-Ci = "/input insert \x1D" +ctrl-Co = "/input insert \x0F" +ctrl-Cv = "/input insert \x16" +ctrl-D = "/input delete_next_char" +ctrl-E = "/input move_end_of_line" +ctrl-F = "/input move_next_char" +ctrl-H = "/input delete_previous_char" +ctrl-I = "/input complete_next" +ctrl-J = "/input return" +ctrl-K = "/input delete_end_of_line" +ctrl-L = "/window refresh" +ctrl-M = "/input return" +ctrl-N = "/buffer +1" +ctrl-P = "/buffer -1" +ctrl-R = "/input search_text_here" +ctrl-Sctrl-U = "/input set_unread" +ctrl-T = "/input transpose_chars" +ctrl-U = "/input delete_beginning_of_line" +ctrl-W = "/input delete_previous_word" +ctrl-W= = "/window balance" +ctrl-Wh = "/window left" +ctrl-Wj = "/window down" +ctrl-Wk = "/window up" +ctrl-Wl = "/window right" +ctrl-Wq = "/window merge" +ctrl-Ws = "/window splith" +ctrl-Wv = "/window splitv" +ctrl-Wx = "/window swap" +ctrl-X = "/input switch_active_buffer" +ctrl-Y = "/input clipboard_paste" +meta-meta-OP = "/bar scroll buflist * b" +meta-meta-OQ = "/bar scroll buflist * e" +meta-meta2-11~ = "/bar scroll buflist * b" +meta-meta2-12~ = "/bar scroll buflist * e" +meta-meta2-1~ = "/window scroll_top" +meta-meta2-23~ = "/bar scroll nicklist * b" +meta-meta2-24~ = "/bar scroll nicklist * e" +meta-meta2-4~ = "/window scroll_bottom" +meta-meta2-5~ = "/window scroll_up" +meta-meta2-6~ = "/window scroll_down" +meta-meta2-7~ = "/window scroll_top" +meta-meta2-8~ = "/window scroll_bottom" +meta-meta2-A = "/buffer -1" +meta-meta2-B = "/buffer +1" +meta-meta2-C = "/buffer +1" +meta-meta2-D = "/buffer -1" +meta-- = "/filter toggle @" +meta-/ = "/input jump_last_buffer_displayed" +meta-0 = "/buffer *10" +meta-1 = "/buffer *1" +meta-2 = "/buffer *2" +meta-3 = "/buffer *3" +meta-4 = "/buffer *4" +meta-5 = "/buffer *5" +meta-6 = "/buffer *6" +meta-7 = "/buffer *7" +meta-8 = "/buffer *8" +meta-9 = "/buffer *9" +meta-< = "/input jump_previously_visited_buffer" +meta-= = "/filter toggle" +meta-> = "/input jump_next_visited_buffer" +meta-B = "/buflist toggle" +meta-OA = "/input history_global_previous" +meta-OB = "/input history_global_next" +meta-OC = "/input move_next_word" +meta-OD = "/input move_previous_word" +meta-OF = "/input move_end_of_line" +meta-OH = "/input move_beginning_of_line" +meta-OP = "/bar scroll buflist * -100%" +meta-OQ = "/bar scroll buflist * +100%" +meta-Oa = "/input history_global_previous" +meta-Ob = "/input history_global_next" +meta-Oc = "/input move_next_word" +meta-Od = "/input move_previous_word" +meta2-11^ = "/bar scroll buflist * -100%" +meta2-11~ = "/bar scroll buflist * -100%" +meta2-12^ = "/bar scroll buflist * +100%" +meta2-12~ = "/bar scroll buflist * +100%" +meta2-15~ = "/buffer -1" +meta2-17~ = "/buffer +1" +meta2-18~ = "/window -1" +meta2-19~ = "/window +1" +meta2-1;3A = "/buffer -1" +meta2-1;3B = "/buffer +1" +meta2-1;3C = "/buffer +1" +meta2-1;3D = "/buffer -1" +meta2-1;3F = "/window scroll_bottom" +meta2-1;3H = "/window scroll_top" +meta2-1;3P = "/bar scroll buflist * b" +meta2-1;3Q = "/bar scroll buflist * e" +meta2-1;5A = "/input history_global_previous" +meta2-1;5B = "/input history_global_next" +meta2-1;5C = "/input move_next_word" +meta2-1;5D = "/input move_previous_word" +meta2-1;5P = "/bar scroll buflist * -100%" +meta2-1;5Q = "/bar scroll buflist * +100%" +meta2-1~ = "/input move_beginning_of_line" +meta2-200~ = "/input paste_start" +meta2-201~ = "/input paste_stop" +meta2-20~ = "/bar scroll title * -30%" +meta2-21~ = "/bar scroll title * +30%" +meta2-23;3~ = "/bar scroll nicklist * b" +meta2-23;5~ = "/bar scroll nicklist * -100%" +meta2-23^ = "/bar scroll nicklist * -100%" +meta2-23~ = "/bar scroll nicklist * -100%" +meta2-24;3~ = "/bar scroll nicklist * e" +meta2-24;5~ = "/bar scroll nicklist * +100%" +meta2-24^ = "/bar scroll nicklist * +100%" +meta2-24~ = "/bar scroll nicklist * +100%" +meta2-3~ = "/input delete_next_char" +meta2-4~ = "/input move_end_of_line" +meta2-5;3~ = "/window scroll_up" +meta2-5~ = "/window page_up" +meta2-6;3~ = "/window scroll_down" +meta2-6~ = "/window page_down" +meta2-7~ = "/input move_beginning_of_line" +meta2-8~ = "/input move_end_of_line" +meta2-A = "/input history_previous" +meta2-B = "/input history_next" +meta2-C = "/input move_next_char" +meta2-D = "/input move_previous_char" +meta2-F = "/input move_end_of_line" +meta2-G = "/window page_down" +meta2-H = "/input move_beginning_of_line" +meta2-I = "/window page_up" +meta2-Z = "/input complete_previous" +meta2-[E = "/buffer -1" +meta-_ = "/input redo" +meta-a = "/input jump_smart" +meta-b = "/input move_previous_word" +meta-d = "/input delete_next_word" +meta-f = "/input move_next_word" +meta-h = "/input hotlist_clear" +meta-j01 = "/buffer *1" +meta-j02 = "/buffer *2" +meta-j03 = "/buffer *3" +meta-j04 = "/buffer *4" +meta-j05 = "/buffer *5" +meta-j06 = "/buffer *6" +meta-j07 = "/buffer *7" +meta-j08 = "/buffer *8" +meta-j09 = "/buffer *9" +meta-j10 = "/buffer *10" +meta-j11 = "/buffer *11" +meta-j12 = "/buffer *12" +meta-j13 = "/buffer *13" +meta-j14 = "/buffer *14" +meta-j15 = "/buffer *15" +meta-j16 = "/buffer *16" +meta-j17 = "/buffer *17" +meta-j18 = "/buffer *18" +meta-j19 = "/buffer *19" +meta-j20 = "/buffer *20" +meta-j21 = "/buffer *21" +meta-j22 = "/buffer *22" +meta-j23 = "/buffer *23" +meta-j24 = "/buffer *24" +meta-j25 = "/buffer *25" +meta-j26 = "/buffer *26" +meta-j27 = "/buffer *27" +meta-j28 = "/buffer *28" +meta-j29 = "/buffer *29" +meta-j30 = "/buffer *30" +meta-j31 = "/buffer *31" +meta-j32 = "/buffer *32" +meta-j33 = "/buffer *33" +meta-j34 = "/buffer *34" +meta-j35 = "/buffer *35" +meta-j36 = "/buffer *36" +meta-j37 = "/buffer *37" +meta-j38 = "/buffer *38" +meta-j39 = "/buffer *39" +meta-j40 = "/buffer *40" +meta-j41 = "/buffer *41" +meta-j42 = "/buffer *42" +meta-j43 = "/buffer *43" +meta-j44 = "/buffer *44" +meta-j45 = "/buffer *45" +meta-j46 = "/buffer *46" +meta-j47 = "/buffer *47" +meta-j48 = "/buffer *48" +meta-j49 = "/buffer *49" +meta-j50 = "/buffer *50" +meta-j51 = "/buffer *51" +meta-j52 = "/buffer *52" +meta-j53 = "/buffer *53" +meta-j54 = "/buffer *54" +meta-j55 = "/buffer *55" +meta-j56 = "/buffer *56" +meta-j57 = "/buffer *57" +meta-j58 = "/buffer *58" +meta-j59 = "/buffer *59" +meta-j60 = "/buffer *60" +meta-j61 = "/buffer *61" +meta-j62 = "/buffer *62" +meta-j63 = "/buffer *63" +meta-j64 = "/buffer *64" +meta-j65 = "/buffer *65" +meta-j66 = "/buffer *66" +meta-j67 = "/buffer *67" +meta-j68 = "/buffer *68" +meta-j69 = "/buffer *69" +meta-j70 = "/buffer *70" +meta-j71 = "/buffer *71" +meta-j72 = "/buffer *72" +meta-j73 = "/buffer *73" +meta-j74 = "/buffer *74" +meta-j75 = "/buffer *75" +meta-j76 = "/buffer *76" +meta-j77 = "/buffer *77" +meta-j78 = "/buffer *78" +meta-j79 = "/buffer *79" +meta-j80 = "/buffer *80" +meta-j81 = "/buffer *81" +meta-j82 = "/buffer *82" +meta-j83 = "/buffer *83" +meta-j84 = "/buffer *84" +meta-j85 = "/buffer *85" +meta-j86 = "/buffer *86" +meta-j87 = "/buffer *87" +meta-j88 = "/buffer *88" +meta-j89 = "/buffer *89" +meta-j90 = "/buffer *90" +meta-j91 = "/buffer *91" +meta-j92 = "/buffer *92" +meta-j93 = "/buffer *93" +meta-j94 = "/buffer *94" +meta-j95 = "/buffer *95" +meta-j96 = "/buffer *96" +meta-j97 = "/buffer *97" +meta-j98 = "/buffer *98" +meta-j99 = "/buffer *99" +meta-k = "/input grab_key_command" +meta-l = "/window bare" +meta-m = "/mute mouse toggle" +meta-n = "/window scroll_next_highlight" +meta-p = "/window scroll_previous_highlight" +meta-r = "/input delete_line" +meta-s = "/mute spell toggle" +meta-u = "/window scroll_unread" +meta-x = "/input zoom_merged_buffer" +meta-z = "/window zoom" +ctrl-^ = "/input jump_last_buffer_displayed" +ctrl-_ = "/input undo" + +[key_search] +ctrl-I = "/input search_switch_where" +ctrl-J = "/input search_stop_here" +ctrl-M = "/input search_stop_here" +ctrl-Q = "/input search_stop" +ctrl-R = "/input search_switch_regex" +meta2-A = "/input search_previous" +meta2-B = "/input search_next" +meta-c = "/input search_switch_case" + +[key_cursor] +ctrl-J = "/cursor stop" +ctrl-M = "/cursor stop" +meta-meta2-A = "/cursor move area_up" +meta-meta2-B = "/cursor move area_down" +meta-meta2-C = "/cursor move area_right" +meta-meta2-D = "/cursor move area_left" +meta2-1;3A = "/cursor move area_up" +meta2-1;3B = "/cursor move area_down" +meta2-1;3C = "/cursor move area_right" +meta2-1;3D = "/cursor move area_left" +meta2-A = "/cursor move up" +meta2-B = "/cursor move down" +meta2-C = "/cursor move right" +meta2-D = "/cursor move left" +@item(buffer_nicklist):K = "/window ${_window_number};/kickban ${nick}" +@item(buffer_nicklist):b = "/window ${_window_number};/ban ${nick}" +@item(buffer_nicklist):k = "/window ${_window_number};/kick ${nick}" +@item(buffer_nicklist):q = "/window ${_window_number};/query ${nick};/cursor stop" +@item(buffer_nicklist):w = "/window ${_window_number};/whois ${nick}" +@chat:Q = "hsignal:chat_quote_time_prefix_message;/cursor stop" +@chat:m = "hsignal:chat_quote_message;/cursor stop" +@chat:q = "hsignal:chat_quote_prefix_message;/cursor stop" + +[key_mouse] +@bar(buflist):ctrl-wheeldown = "hsignal:buflist_mouse" +@bar(buflist):ctrl-wheelup = "hsignal:buflist_mouse" +@bar(input):button2 = "/input grab_mouse_area" +@bar(nicklist):button1-gesture-down = "/bar scroll nicklist ${_window_number} +100%" +@bar(nicklist):button1-gesture-down-long = "/bar scroll nicklist ${_window_number} e" +@bar(nicklist):button1-gesture-up = "/bar scroll nicklist ${_window_number} -100%" +@bar(nicklist):button1-gesture-up-long = "/bar scroll nicklist ${_window_number} b" +@chat(fset.fset):button1 = "/window ${_window_number};/fset -go ${_chat_line_y}" +@chat(fset.fset):button2* = "hsignal:fset_mouse" +@chat(fset.fset):wheeldown = "/fset -down 5" +@chat(fset.fset):wheelup = "/fset -up 5" +@chat(script.scripts):button1 = "/window ${_window_number};/script go ${_chat_line_y}" +@chat(script.scripts):button2 = "/window ${_window_number};/script go ${_chat_line_y};/script installremove -q ${script_name_with_extension}" +@chat(script.scripts):wheeldown = "/script down 5" +@chat(script.scripts):wheelup = "/script up 5" +@item(buffer_nicklist):button1 = "/window ${_window_number};/query ${nick}" +@item(buffer_nicklist):button1-gesture-left = "/window ${_window_number};/kick ${nick}" +@item(buffer_nicklist):button1-gesture-left-long = "/window ${_window_number};/kickban ${nick}" +@item(buffer_nicklist):button2 = "/window ${_window_number};/whois ${nick}" +@item(buffer_nicklist):button2-gesture-left = "/window ${_window_number};/ban ${nick}" +@item(buflist):button1* = "hsignal:buflist_mouse" +@item(buflist):button2* = "hsignal:buflist_mouse" +@item(buflist2):button1* = "hsignal:buflist_mouse" +@item(buflist2):button2* = "hsignal:buflist_mouse" +@item(buflist3):button1* = "hsignal:buflist_mouse" +@item(buflist3):button2* = "hsignal:buflist_mouse" +@bar:wheeldown = "/bar scroll ${_bar_name} ${_window_number} +20%" +@bar:wheelup = "/bar scroll ${_bar_name} ${_window_number} -20%" +@chat:button1 = "/window ${_window_number}" +@chat:button1-gesture-left = "/window ${_window_number};/buffer -1" +@chat:button1-gesture-left-long = "/window ${_window_number};/buffer 1" +@chat:button1-gesture-right = "/window ${_window_number};/buffer +1" +@chat:button1-gesture-right-long = "/window ${_window_number};/input jump_last_buffer" +@chat:ctrl-wheeldown = "/window scroll_horiz -window ${_window_number} +10%" +@chat:ctrl-wheelup = "/window scroll_horiz -window ${_window_number} -10%" +@chat:wheeldown = "/window scroll_down -window ${_window_number}" +@chat:wheelup = "/window scroll_up -window ${_window_number}" +@*:button3 = "/cursor go ${_x},${_y}" diff --git a/.weechat/xfer.conf b/.weechat/xfer.conf new file mode 100644 index 00000000..551316ff --- /dev/null +++ b/.weechat/xfer.conf @@ -0,0 +1,49 @@ +# +# weechat -- xfer.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +auto_open_buffer = on +progress_bar_size = 20 +pv_tags = "notify_private" + +[color] +status_aborted = lightred +status_active = lightblue +status_connecting = yellow +status_done = lightgreen +status_failed = lightred +status_waiting = lightcyan +text = default +text_bg = default +text_selected = white + +[network] +blocksize = 65536 +fast_send = on +own_ip = "" +port_range = "" +send_ack = on +speed_limit_recv = 0 +speed_limit_send = 0 +timeout = 300 + +[file] +auto_accept_chats = off +auto_accept_files = off +auto_accept_nicks = "" +auto_check_crc32 = off +auto_rename = on +auto_resume = on +convert_spaces = on +download_path = "%h/xfer" +download_temporary_suffix = ".part" +upload_path = "~" +use_nick_in_filename = on diff --git a/.xinitrc b/.xinitrc index d93703ce..8303c9b2 100644 --- a/.xinitrc +++ b/.xinitrc @@ -1,4 +1,25 @@ #!/bin/sh +userresources=$HOME/.Xresources +usermodmap=$HOME/.Xmodmap +sysresources=/etc/X11/xinit/.Xresources +sysmodmap=/etc/X11/xinit/.Xmodmap + +if [ -f $sysresources ]; then + xrdb -merge $sysresources +fi + +if [ -f $sysmodmap ]; then + xmodmap $sysmodmap +fi + +if [ -f $userresources ]; then + xrdb -merge $userresources +fi + +if [ -f $usermodmap ]; then + xmodmap $usermodmap +fi + if [ -d /etc/X11/xinit/xinitrc.d ] ; then for f in /etc/X11/xinit/xinitrc.d/?*.sh ; do @@ -8,7 +29,7 @@ if [ -d /etc/X11/xinit/xinitrc.d ] ; then fi setxkbmap "us,us" ",intl" "grp:shifts_toggle" -[ -f ~/.Xmodmap ] && xmodmap ~/.Xmodmap +xset m 0 0 mkdir -p $HOME/.local/share/bspwm exec bspwm >$HOME/.local/share/bspwm/output.log 2>$HOME/.local/share/bspwm/error.log diff --git a/.zsh/plugins/zsh-completions b/.zsh/plugins/zsh-completions index 3b247d30..c6621bb6 160000 --- a/.zsh/plugins/zsh-completions +++ b/.zsh/plugins/zsh-completions @@ -1 +1 @@ -Subproject commit 3b247d3071b8f1b723f288aec10e91758a109045 +Subproject commit c6621bb692928333b76e2a593c66b49020389ab1 diff --git a/.zsh/plugins/zsh-syntax-highlighting b/.zsh/plugins/zsh-syntax-highlighting index fb929edc..2d60a47c 160000 --- a/.zsh/plugins/zsh-syntax-highlighting +++ b/.zsh/plugins/zsh-syntax-highlighting @@ -1 +1 @@ -Subproject commit fb929edc30192407a9298aad64f55ca1b19a464e +Subproject commit 2d60a47cc407117815a1d7b331ef226aa400a344 diff --git a/.zshenv b/.zshenv index 5001fb87..5a35f103 100644 --- a/.zshenv +++ b/.zshenv @@ -38,8 +38,7 @@ export GPG_TTY=$(tty) export TERMINAL='alacritty' -export JUCE_PATH='~/JUCE' -export FRUT_PATH='~/FRUT' +export JUCE_PATH="$HOME/JUCE" export CXXFLAGS='-std=c++14' @@ -51,7 +50,7 @@ export WINIT_X11_SCALE_FACTOR=1 alias layout='xkblayout-state print "%s %v"' alias picom-default='picom -bgc --backend glx --unredir-if-possible-delay 1000 --vsync' -alias screenkey-obs='screenkey --no-systray -t 2 -p fixed -s small -g 960x36+960+4 --key-mode composed --bak-mode full --mods-mode normal --scr 0 -f hack' +alias screenkey-obs='screenkey --no-systray -t 2 -p fixed -s small -g 960x88+960+4 --key-mode composed --bak-mode full --mods-mode normal -f Hack --font-color "#f8f8f2" --bg-color "#44475a" --opacity "1.0"' alias tmate-obs='tmate -k tmk-et35fx5m9ca7cxot4jjwksmaoy -r dustvoice' alias xfce-polkit='/usr/lib/xfce-polkit/xfce-polkit' alias davinci-resolve='/opt/resolve/bin/resolve'