├── samples └── c │ ├── .gitignore │ ├── src │ └── main.c │ ├── .clang-tidy │ ├── Makefile │ └── .clang-format ├── home ├── .inputrc ├── .gitconfig ├── .bash_profile ├── .xprofile ├── .bashrc └── .gdbinit ├── helix ├── languages.toml └── config.toml ├── dunst ├── icons │ ├── bell.svg │ ├── message.svg │ └── alert-triangle.svg └── dunstrc ├── st ├── patches │ ├── st-scrollback-mouse-0.9.2.diff │ └── st-scrollback-ringbuffer-0.9.2.diff └── config.def.h ├── .packages └── dwm └── config.def.h /samples/c/.gitignore: -------------------------------------------------------------------------------- 1 | .helix/ 2 | .cache/ 3 | build/ 4 | compile_commands.json 5 | -------------------------------------------------------------------------------- /home/.inputrc: -------------------------------------------------------------------------------- 1 | set colored-completion-prefix on 2 | set colored-stats on 3 | set completion-ignore-case on 4 | set show-all-if-ambiguous on 5 | -------------------------------------------------------------------------------- /helix/languages.toml: -------------------------------------------------------------------------------- 1 | [language-server.clangd] 2 | command = "clangd" 3 | args = ["--background-index", "--header-insertion=never", "--clang-tidy"] 4 | -------------------------------------------------------------------------------- /samples/c/src/main.c: -------------------------------------------------------------------------------- 1 | #include "just.h" 2 | 3 | int 4 | main(int argc, char* argv[]) { 5 | (void)argc; 6 | (void)argv; 7 | 8 | return EXIT_SUCCESS; 9 | } 10 | -------------------------------------------------------------------------------- /home/.gitconfig: -------------------------------------------------------------------------------- 1 | [user] 2 | email = fartdraft@gmail.com 3 | name = pithecantrope 4 | 5 | [init] 6 | defaultBranch = main 7 | 8 | [core] 9 | pager = delta 10 | 11 | [interactive] 12 | diffFilter = delta --color-only 13 | 14 | [delta] 15 | navigate = true 16 | dark = true 17 | syntax-theme = gruvbox-dark 18 | 19 | [merge] 20 | conflictstyle = zdiff3 21 | 22 | [diff] 23 | colorMoved = default 24 | 25 | -------------------------------------------------------------------------------- /dunst/icons/bell.svg: -------------------------------------------------------------------------------- 1 | 7 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /home/.bash_profile: -------------------------------------------------------------------------------- 1 | # 2 | # ~/.bash_profile 3 | # 4 | 5 | [[ -f ~/.bashrc ]] && . ~/.bashrc 6 | 7 | export EDITOR=helix 8 | export BROWSER=firefox 9 | export HISTSIZE=4096 10 | export HISTFILESIZE=4096 11 | export HISTCONTROL=erasedups 12 | export COLORTERM=truecolor 13 | export GTK_THEME=Adwaita:dark 14 | export QT_STYLE_OVERRIDE=Adwaita-Dark 15 | export LS_COLORS="$(vivid generate gruvbox-dark)" 16 | export BAT_THEME="gruvbox-dark" 17 | export MANPAGER="sh -c 'awk '\''{ gsub(/\x1B\[[0-9;]*m/, \"\", \$0); gsub(/.\x08/, \"\", \$0); print }'\'' | bat -p -lman'" 18 | man 2 select 19 | -------------------------------------------------------------------------------- /dunst/icons/message.svg: -------------------------------------------------------------------------------- 1 | 7 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /home/.xprofile: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | { 4 | while true; do 5 | time=$(date '+%H:%M') 6 | battery=$(cat /sys/class/power_supply/BAT0/capacity 2>/dev/null || echo '?') 7 | if [ "$battery" -lt 25 ] 2>/dev/null; then 8 | notify-send -u critical 'Low Battery' 9 | fi 10 | todo=$(rg -F '[ ]' ~/projects/TODO -m1 | sed 's/^\[ \] //' || echo 'None') 11 | xsetroot -name "TODO: '${todo}' | BAT: ${battery}% | ${time}" 12 | sleep 33s 13 | done 14 | } & 15 | unclutter --start-hidden -b 16 | dunst & 17 | 18 | st & 19 | firefox & 20 | 21 | exec dwm 22 | -------------------------------------------------------------------------------- /dunst/icons/alert-triangle.svg: -------------------------------------------------------------------------------- 1 | 7 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /samples/c/.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: > 2 | performance-*, 3 | misc-*, 4 | android-cloexec-*, 5 | readability-duplicate-include, 6 | readability-misleading-indentation, 7 | bugprone-assert-side-effect, 8 | bugprone-macro-repeated-side-effects, 9 | bugprone-infinite-loop, 10 | bugprone-macro-parentheses, 11 | bugprone-posix-return, 12 | bugprone-reserved-identifier, 13 | bugprone-signal-handler, 14 | bugprone-signed-char-misuse, 15 | bugprone-sizeof-expression, 16 | bugprone-branch-clone, 17 | -clang-analyzer-security.insecureAPI.*, 18 | -misc-no-recursion, 19 | 20 | WarningsAsErrors: '*' 21 | 22 | ExtraArgs: [-std=c17] 23 | -------------------------------------------------------------------------------- /dunst/dunstrc: -------------------------------------------------------------------------------- 1 | [global] 2 | # Gruvbox-dark colorscheme 3 | offset = (0, 20) # Just under 'WM_NAME' 4 | frame_color = "#928374" 5 | font = Adwaita Mono 11 6 | enable_recursive_icon_lookup = false 7 | icon_path = ~/projects/dotfiles/dunst/icons 8 | 9 | [urgency_low] 10 | background = "#458588" 11 | foreground = "#d5c4a1" 12 | timeout = 10 13 | default_icon = message 14 | 15 | [urgency_normal] 16 | background = "#689d6a" 17 | foreground = "#ebdbb2" 18 | timeout = 30 19 | default_icon = bell 20 | 21 | [urgency_critical] 22 | background = "#b16286" 23 | foreground = "#fbf1c7" 24 | timeout = 0 25 | default_icon = alert-triangle 26 | -------------------------------------------------------------------------------- /helix/config.toml: -------------------------------------------------------------------------------- 1 | theme = "sunset" 2 | 3 | [editor] 4 | gutters = ["diagnostics", "spacer", "diff"] 5 | true-color = true 6 | bufferline = "always" 7 | auto-format = false 8 | popup-border = "all" 9 | jump-label-alphabet = "jfkdls;aurieowpqnvmcxz" 10 | trim-final-newlines = true 11 | trim-trailing-whitespace = true 12 | 13 | [keys.normal] 14 | "X" = "extend_line_above" 15 | "C-c" = ["save_selection", "extend_to_line_bounds", "yank_to_primary_clipboard", 16 | "paste_primary_clipboard_before", "jump_backward"] 17 | 18 | [keys.insert] 19 | "C-c" = ["normal_mode", "save_selection", "extend_to_line_bounds", "yank_to_primary_clipboard", 20 | "paste_primary_clipboard_before", "jump_backward", "insert_mode"] 21 | 22 | [keys.select] 23 | "C-c" = ["yank_to_primary_clipboard", "paste_primary_clipboard_before"] 24 | -------------------------------------------------------------------------------- /st/patches/st-scrollback-mouse-0.9.2.diff: -------------------------------------------------------------------------------- 1 | From 6b7e7e6c5c44dd6347ad49691b80d808c1b0cb77 Mon Sep 17 00:00:00 2001 2 | From: Jernej Jakob 3 | Date: Mon, 1 Jul 2024 14:00:02 +0200 4 | Subject: [PATCH] [st][patch] Update st-scrollback-mouse for 0.9.2 5 | 6 | --- 7 | config.def.h | 2 ++ 8 | 1 file changed, 2 insertions(+) 9 | 10 | diff --git a/config.def.h b/config.def.h 11 | index 8b25d40..d259675 100644 12 | --- a/config.def.h 13 | +++ b/config.def.h 14 | @@ -176,6 +176,8 @@ static uint forcemousemod = ShiftMask; 15 | */ 16 | static MouseShortcut mshortcuts[] = { 17 | /* mask button function argument release */ 18 | + { ShiftMask, Button4, kscrollup, {.i = 1} }, 19 | + { ShiftMask, Button5, kscrolldown, {.i = 1} }, 20 | { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, 21 | { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, 22 | { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, 23 | -- 24 | 2.44.2 25 | 26 | -------------------------------------------------------------------------------- /home/.bashrc: -------------------------------------------------------------------------------- 1 | # 2 | # ~/.bashrc 3 | # 4 | 5 | # If not running interactively, don't do anything 6 | [[ $- != *i* ]] && return 7 | 8 | PS1='\[\e[3;33m\]\w \[\e[1;32m\]>\[\e[0m\] ' 9 | alias e=helix 10 | 11 | alias ls='eza --group-directories-first --icons --git-ignore' 12 | alias lt='eza --group-directories-first --icons --git-ignore --tree --level=3' 13 | alias la='eza --group-directories-first --icons --all' 14 | alias ll='eza --group-directories-first --icons --git-ignore --long --header --color-scale --binary --total-size --git' 15 | # --{modified, changed, accessed, created} 16 | 17 | cd() { 18 | builtin cd "$@" && la 19 | } 20 | 21 | man() { 22 | command man "$@" 2>/dev/null || "$@" --help 2>&1 | bat --plain --language=help 23 | } 24 | 25 | alias c='xclip -selection clipboard' 26 | alias pb='curl -F "file=@-" 0x0.st' 27 | 28 | alias fp='fzf --preview "bat --color=always --style=numbers --line-range=:500 {}"' 29 | eval "$(fzf --bash)" # Ctrl-T, Ctrl-R, Alt-C and helix ** 30 | 31 | alias pomowork='sleep 1m && notify-send -u low "Pomodoro" "You have earned a rest"' 32 | alias pomobreak='sleep 1m && notify-send -u normal "Pomodoro" "Get back to work"' 33 | -------------------------------------------------------------------------------- /home/.gdbinit: -------------------------------------------------------------------------------- 1 | # set disassembly-flavor intel 2 | # set width unlimited 3 | # set height unlimited 4 | # set pagination off 5 | # set verbose off 6 | 7 | set debuginfod enabled off 8 | set confirm off 9 | set disassembly-flavor intel 10 | set history save on 11 | set history filename ~/.gdb_history 12 | # set history size 100000 13 | # set history remove-duplicates 10 14 | set host-charset UTF-8 15 | set target-charset UTF-8 16 | set target-wide-charset UTF-8 17 | 18 | set print pretty on 19 | set print object on 20 | set print static-members on 21 | set print vtbl on 22 | 23 | set print demangle on 24 | set demangle-style gnu-v3 25 | set print sevenbit-strings off 26 | 27 | 28 | # Essential .gdbinit configuration 29 | set confirm off 30 | set pagination off 31 | set history save on 32 | set history filename ~/.gdb_history 33 | 34 | # Better display 35 | set print pretty on 36 | set print object on 37 | set print static-members on 38 | set print vtbl on 39 | set print array on 40 | set print array-indexes on 41 | 42 | # Stop at first instruction 43 | set startup-with-shell off 44 | 45 | # Common shortcuts 46 | define x 47 | examine/8x $arg0 48 | end 49 | 50 | define xx 51 | examine/16x $arg0 52 | end 53 | 54 | define d 55 | examine/8dw $arg0 56 | end 57 | 58 | define dd 59 | examine/16dw $arg0 60 | end 61 | 62 | # Enhanced backtrace 63 | define bt 64 | backtrace 65 | frame 66 | end 67 | 68 | # Common hook 69 | define hook-quit 70 | set confirm on 71 | end 72 | 73 | # TUI mode improvements 74 | tui enable 75 | set tui border-kind ascii 76 | set tui tab-width 4 77 | 78 | # Source code context 79 | set listsize 20 80 | set disassembly-flavor intel 81 | 82 | 83 | 84 | break abort # Catch abort() calls 85 | break __assert_fail # Catch failed assertions 86 | break exit # Catch normal exits 87 | break _exit # Catch immediate exits 88 | -------------------------------------------------------------------------------- /.packages: -------------------------------------------------------------------------------- 1 | # To install packages, run: 2 | # sed 's/ *#.*//; /^$/d' .packages | sudo pacman -S --needed - 3 | # Software with a leading '#' must be installed manually. 4 | # A) 5 | # B) 6 | bat # Modern `cat` 7 | brightnessctl # Brightness control 8 | btop # Resources monitor 9 | # C) 10 | #chatterino2-bin # Chat client 'yay -S chatterino2-bin' 11 | # D) 12 | dmenu # Dynamic menu 13 | dunst # Notification daemon 14 | #dwm # Window manager `git clone https://git.suckless.org/dwm` 15 | # E) 16 | easyeffects # Audio enhancer 17 | eza # Modern `ls` 18 | # F) 19 | fastfetch # System information 20 | fd # Modern `find` 21 | firefox # Web browser 22 | firefox-tridactyl # Vim-like interface 23 | fzf # Fuzzy finder 24 | # G) 25 | git # Version control 26 | git-delta # `git` pager 27 | glow # CLI markdown 28 | gnome-themes-extra # Dark mode 29 | # H) 30 | helix # Text editor 31 | # I) 32 | # J) 33 | # K) 34 | keyd # Key remapper 35 | # L) 36 | libreoffice-still-ru # Office suite 37 | ly # Display manager 38 | # M) 39 | maim # Screenshot maker 40 | mpv # Media player 41 | # N) 42 | # O) 43 | obs-studio # Live streaming 44 | openssh # Remote connection 45 | ouch # Compression decompression 46 | # P) 47 | pacman-contrib # Cache cleaner 48 | #pinta # Paint program 'yay -S pinta' 49 | python-qrcode # QR code 50 | # Q) 51 | # R) 52 | reflector # Mirror manager 53 | ripgrep # Modern `grep` 54 | # S) 55 | #st # Suckless terminal `git clone https://git.suckless.org/st` 56 | # T) 57 | tlp # Battery life 58 | tokei # Code counter 59 | ttf-cascadia-mono-nerd # Terminal font 60 | # U) 61 | unclutter # Cursor hider 62 | # V) 63 | vivid # `LS_COLORS` generator 64 | # W) 65 | wireless-regdb # Regulatory database 66 | # X) 67 | xclip # X11 Clipboard 68 | xorg # Window system 69 | # Y) 70 | #yay # AUR helper `sudo pacman -S --needed git base-devel && git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si` 71 | yt-dlp # Video downloader 72 | # Z) 73 | -------------------------------------------------------------------------------- /samples/c/Makefile: -------------------------------------------------------------------------------- 1 | MAKEFLAGS += -j$(nproc) 2 | PROJECT_NAME := bin 3 | LDFLAGS := 4 | ARGS ?= 5 | 6 | BUILD_DIR := build 7 | SRC_DIR := src 8 | CONFIG ?= DEV 9 | CC := gcc 10 | CPPFLAGS := -MMD -MP 11 | 12 | TARGET_DIR := $(BUILD_DIR)/$(CONFIG) 13 | TARGET := $(TARGET_DIR)/$(PROJECT_NAME)-$(CONFIG) 14 | 15 | CFLAGS_RELEASE := -O3 -flto=auto -DNDEBUG 16 | CFLAGS_DEBUG := -O0 -ggdb3 17 | CFLAGS_PROFILE := -O2 -fno-inline -fno-omit-frame-pointer -g3 18 | CFLAGS_DEV := -std=c17 -O0 -g3 -Werror -Wall -Wextra -Wpedantic -fsanitize=address,undefined \ 19 | -Wcast-qual -Wconversion -Wdouble-promotion -Wfloat-equal -Winline -Wlogical-op \ 20 | -Wold-style-definition -Wshadow -Wswitch-default -Wswitch-enum -Wundef 21 | CFLAGS := $(CFLAGS_$(CONFIG)) 22 | 23 | SRCS := $(wildcard $(SRC_DIR)/*.c) 24 | OBJS := $(SRCS:$(SRC_DIR)/%.c=$(TARGET_DIR)/%.o) 25 | DEPS := $(OBJS:.o=.d) 26 | 27 | .SILENT: 28 | .PHONY: all release _release debug _debug perf _perf leak _leak cache _cache call _call mem _mem run spell clean db 29 | 30 | all: $(TARGET) 31 | 32 | $(TARGET_DIR): 33 | mkdir -p $@ 34 | 35 | $(TARGET): $(OBJS) 36 | $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) 37 | 38 | $(TARGET_DIR)/%.o: $(SRC_DIR)/%.c | $(TARGET_DIR) 39 | $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 40 | 41 | release: 42 | $(MAKE) -s CONFIG=RELEASE 43 | $(MAKE) -s CONFIG=RELEASE _release 44 | 45 | _release: 46 | $(TARGET) $(ARGS) 47 | 48 | debug: 49 | $(MAKE) -s CONFIG=DEBUG 50 | $(MAKE) -s CONFIG=DEBUG _debug 51 | 52 | _debug: 53 | gdb -q -ex 'break main' --tui --args $(TARGET) $(ARGS) 54 | 55 | perf: 56 | $(MAKE) -s CONFIG=PROFILE 57 | $(MAKE) -s CONFIG=PROFILE _perf 58 | 59 | _perf: 60 | perf record -g --freq=max -o $(TARGET_DIR)/perf.data $(TARGET) $(ARGS) 61 | perf script -i $(TARGET_DIR)/perf.data | stackcollapse-perf.pl | flamegraph.pl > $(TARGET_DIR)/flamegraph.svg 62 | $(BROWSER) $(TARGET_DIR)/flamegraph.svg 63 | 64 | leak: 65 | $(MAKE) -s CONFIG=DEBUG 66 | $(MAKE) -s CONFIG=DEBUG _leak 67 | 68 | _leak: 69 | valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --track-origins=yes --log-file=$(TARGET_DIR)/leak.txt $(TARGET) $(ARGS) 70 | $(EDITOR) $(TARGET_DIR)/leak.txt 71 | 72 | cache: 73 | $(MAKE) -s CONFIG=PROFILE 74 | $(MAKE) -s CONFIG=PROFILE _cache 75 | 76 | _cache: 77 | valgrind -q --tool=cachegrind --cachegrind-out-file=$(TARGET_DIR)/cache.out $(TARGET) $(ARGS) 78 | cg_annotate $(TARGET_DIR)/cache.out > $(TARGET_DIR)/cache.txt 79 | $(EDITOR) $(TARGET_DIR)/cache.txt 80 | 81 | call: 82 | $(MAKE) -s CONFIG=PROFILE 83 | $(MAKE) -s CONFIG=PROFILE _call 84 | 85 | _call: 86 | valgrind -q --tool=callgrind --callgrind-out-file=$(TARGET_DIR)/call.out $(TARGET) $(ARGS) 87 | callgrind_annotate $(TARGET_DIR)/call.out > $(TARGET_DIR)/call.txt 88 | $(EDITOR) $(TARGET_DIR)/call.txt 89 | 90 | mem: 91 | $(MAKE) -s CONFIG=PROFILE 92 | $(MAKE) -s CONFIG=PROFILE _mem 93 | 94 | _mem: 95 | valgrind -q --tool=massif --massif-out-file=$(TARGET_DIR)/mem.out $(TARGET) $(ARGS) 96 | ms_print $(TARGET_DIR)/mem.out > $(TARGET_DIR)/mem.txt 97 | $(EDITOR) $(TARGET_DIR)/mem.txt 98 | 99 | run: $(TARGET) 100 | $^ $(ARGS) 101 | 102 | spell: 103 | codespell $(SRC_DIR) 104 | 105 | clean: 106 | rm -rf $(BUILD_DIR) 107 | 108 | db: clean 109 | bear -- make 110 | 111 | -include $(DEPS) 112 | -------------------------------------------------------------------------------- /samples/c/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: -2 3 | AlignAfterOpenBracket: Align 4 | AlignArrayOfStructures: None 5 | AlignConsecutiveMacros: 6 | Enabled: true 7 | AcrossEmptyLines: true 8 | AcrossComments: true 9 | AlignConsecutiveAssignments: None 10 | AlignConsecutiveBitFields: 11 | Enabled: true 12 | AcrossEmptyLines: true 13 | AcrossComments: true 14 | AlignConsecutiveDeclarations: None 15 | AlignEscapedNewlines: Right 16 | AlignOperands: Align 17 | SortIncludes: true 18 | InsertBraces: true # Control statements must have curly brackets 19 | AlignTrailingComments: true 20 | AllowAllArgumentsOnNextLine: true 21 | AllowAllParametersOfDeclarationOnNextLine: true 22 | AllowShortEnumsOnASingleLine: true 23 | AllowShortBlocksOnASingleLine: Empty 24 | AllowShortCaseLabelsOnASingleLine: true 25 | AllowShortFunctionsOnASingleLine: All 26 | AllowShortLambdasOnASingleLine: All 27 | AllowShortIfStatementsOnASingleLine: Never 28 | AllowShortLoopsOnASingleLine: false 29 | AlwaysBreakAfterDefinitionReturnType: None 30 | AlwaysBreakAfterReturnType: AllDefinitions 31 | AlwaysBreakBeforeMultilineStrings: false 32 | AlwaysBreakTemplateDeclarations: Yes 33 | AttributeMacros: 34 | - __capability 35 | BinPackArguments: true 36 | BinPackParameters: true 37 | BraceWrapping: 38 | AfterCaseLabel: false 39 | AfterClass: false 40 | AfterControlStatement: Never 41 | AfterEnum: false 42 | AfterFunction: false 43 | AfterNamespace: false 44 | AfterObjCDeclaration: false 45 | AfterStruct: false 46 | AfterUnion: false 47 | AfterExternBlock: false 48 | BeforeCatch: false 49 | BeforeElse: false 50 | BeforeLambdaBody: false 51 | BeforeWhile: false 52 | IndentBraces: false 53 | SplitEmptyFunction: true 54 | SplitEmptyRecord: true 55 | SplitEmptyNamespace: true 56 | BreakBeforeBinaryOperators: NonAssignment 57 | BreakBeforeConceptDeclarations: true 58 | BreakBeforeBraces: Attach 59 | BreakBeforeInheritanceComma: false 60 | BreakInheritanceList: BeforeColon 61 | BreakBeforeTernaryOperators: true 62 | BreakConstructorInitializersBeforeComma: false 63 | BreakConstructorInitializers: BeforeColon 64 | BreakAfterJavaFieldAnnotations: false 65 | BreakStringLiterals: true 66 | ColumnLimit: 100 67 | CommentPragmas: "^ IWYU pragma:" 68 | QualifierAlignment: Leave 69 | CompactNamespaces: false 70 | ConstructorInitializerIndentWidth: 8 71 | ContinuationIndentWidth: 8 72 | Cpp11BracedListStyle: true 73 | DeriveLineEnding: true 74 | DerivePointerAlignment: false 75 | DisableFormat: false 76 | EmptyLineAfterAccessModifier: Never 77 | EmptyLineBeforeAccessModifier: LogicalBlock 78 | ExperimentalAutoDetectBinPacking: false 79 | PackConstructorInitializers: BinPack 80 | BasedOnStyle: "" 81 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 82 | AllowAllConstructorInitializersOnNextLine: true 83 | FixNamespaceComments: true 84 | ForEachMacros: 85 | - foreach 86 | - Q_FOREACH 87 | - BOOST_FOREACH 88 | IfMacros: 89 | - KJ_IF_MAYBE 90 | IncludeBlocks: Preserve 91 | IncludeCategories: 92 | - Regex: "^<(.*)>" 93 | Priority: 0 94 | - Regex: '^"(.*)"' 95 | Priority: 1 96 | - Regex: "(.*)" 97 | Priority: 2 98 | IncludeIsMainRegex: "(Test)?$" 99 | IncludeIsMainSourceRegex: "" 100 | IndentAccessModifiers: false 101 | IndentCaseLabels: true 102 | IndentCaseBlocks: false 103 | IndentGotoLabels: true 104 | IndentPPDirectives: None 105 | IndentExternBlock: AfterExternBlock 106 | IndentRequires: true 107 | IndentWidth: 8 108 | IndentWrappedFunctionNames: false 109 | InsertTrailingCommas: None 110 | JavaScriptQuotes: Leave 111 | JavaScriptWrapImports: true 112 | KeepEmptyLinesAtTheStartOfBlocks: true 113 | LambdaBodyIndentation: Signature 114 | MacroBlockBegin: "" 115 | MacroBlockEnd: "" 116 | MaxEmptyLinesToKeep: 1 117 | NamespaceIndentation: None 118 | ObjCBinPackProtocolList: Auto 119 | ObjCBlockIndentWidth: 2 120 | ObjCBreakBeforeNestedBlockParam: true 121 | ObjCSpaceAfterProperty: false 122 | ObjCSpaceBeforeProtocolList: true 123 | PenaltyBreakAssignment: 2 124 | PenaltyBreakBeforeFirstCallParameter: 19 125 | PenaltyBreakComment: 300 126 | PenaltyBreakFirstLessLess: 100 127 | PenaltyBreakOpenParenthesis: 0 128 | PenaltyBreakString: 1000 129 | PenaltyBreakTemplateDeclaration: 10 130 | PenaltyExcessCharacter: 1000000 131 | PenaltyReturnTypeOnItsOwnLine: 60 132 | PenaltyIndentedWhitespace: 0 133 | PointerAlignment: Left 134 | PPIndentWidth: -1 135 | ReferenceAlignment: Pointer 136 | ReflowComments: false 137 | RemoveBracesLLVM: false 138 | SeparateDefinitionBlocks: Always 139 | ShortNamespaceLines: 1 140 | SortJavaStaticImport: Before 141 | SortUsingDeclarations: true 142 | SpaceAfterCStyleCast: false 143 | SpaceAfterLogicalNot: false 144 | SpaceAfterTemplateKeyword: true 145 | SpaceBeforeAssignmentOperators: true 146 | SpaceBeforeCaseColon: false 147 | SpaceBeforeParens: ControlStatements 148 | SpaceBeforeParensOptions: 149 | AfterControlStatements: true 150 | AfterForeachMacros: true 151 | AfterFunctionDefinitionName: false 152 | AfterFunctionDeclarationName: false 153 | AfterIfMacros: true 154 | AfterOverloadedOperator: false 155 | BeforeNonEmptyParentheses: false 156 | SpaceAroundPointerQualifiers: Default 157 | SpaceBeforeRangeBasedForLoopColon: true 158 | SpaceInEmptyBlock: false 159 | SpaceInEmptyParentheses: false 160 | SpacesBeforeTrailingComments: 1 161 | SpacesInAngles: Never 162 | SpacesInConditionalStatement: false 163 | SpacesInContainerLiterals: true 164 | SpacesInCStyleCastParentheses: false 165 | SpacesInLineCommentPrefix: 166 | Minimum: 1 167 | Maximum: -1 168 | SpacesInParentheses: false 169 | SpacesInSquareBrackets: false 170 | SpaceBeforeSquareBrackets: false 171 | BitFieldColonSpacing: Both 172 | Standard: Latest 173 | StatementAttributeLikeMacros: 174 | - Q_EMIT 175 | StatementMacros: 176 | - Q_UNUSED 177 | - QT_REQUIRE_VERSION 178 | TabWidth: 8 179 | UseCRLF: false 180 | UseTab: Never 181 | WhitespaceSensitiveMacros: 182 | - STRINGIZE 183 | - PP_STRINGIZE 184 | - BOOST_PP_STRINGIZE 185 | - NS_SWIFT_NAME 186 | - CF_SWIFT_NAME 187 | SpaceBeforeCpp11BracedList: false 188 | SpaceBeforeCtorInitializerColon: true 189 | SpaceBeforeInheritanceColon: true 190 | --- 191 | -------------------------------------------------------------------------------- /dwm/config.def.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | 3 | /* appearance */ 4 | static const unsigned int borderpx = 2; /* border pixel of windows */ 5 | static const unsigned int snap = 32; /* snap pixel */ 6 | static const int showbar = 1; /* 0 means no bar */ 7 | static const int topbar = 1; /* 0 means bottom bar */ 8 | static const char *fonts[] = { "monospace:size=11" }; 9 | static const char dmenufont[] = "monospace:size=11"; 10 | static const char col_gray1[] = "#222222"; 11 | static const char col_gray2[] = "#444444"; 12 | static const char col_gray3[] = "#bbbbbb"; 13 | static const char col_gray4[] = "#eeeeee"; 14 | static const char col_cyan[] = "#005577"; 15 | static const char *colors[][3] = { 16 | /* fg bg border */ 17 | [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, 18 | [SchemeSel] = { col_gray4, col_cyan, col_cyan }, 19 | }; 20 | 21 | /* tagging */ 22 | static const char *tags[] = { "1", "2", "3", "4" }; 23 | 24 | static const Rule rules[] = { 25 | /* xprop(1): 26 | * WM_CLASS(STRING) = instance, class 27 | * WM_NAME(STRING) = title 28 | */ 29 | /* class instance title tags mask isfloating monitor */ 30 | { "libreoffice", NULL, NULL, 1 << 1, 0, -1 }, 31 | { "pinta" , NULL, NULL, 1 << 1, 0, -1 }, 32 | { "firefox", NULL, NULL, 1 << 2, 0, -1 }, 33 | { "obs", NULL, NULL, 1 << 3, 0, -1 }, 34 | }; 35 | 36 | /* layout(s) */ 37 | static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ 38 | static const int nmaster = 1; /* number of clients in master area */ 39 | static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ 40 | static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ 41 | static const int refreshrate = 120; /* refresh rate (per second) for client move/resize */ 42 | 43 | static const Layout layouts[] = { 44 | /* symbol arrange function */ 45 | { "[]=", tile }, /* first entry is default */ 46 | { "><>", NULL }, /* no layout function means floating behavior */ 47 | { "[M]", monocle }, 48 | }; 49 | 50 | /* key definitions */ 51 | #define MODKEY Mod4Mask 52 | #define TAGKEYS(KEY,TAG) \ 53 | { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ 54 | { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ 55 | { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ 56 | { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, 57 | 58 | /* helper for spawning shell commands in the pre dwm-5.0 fashion */ 59 | #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } 60 | 61 | /* commands */ 62 | static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ 63 | static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; 64 | static const char *termcmd[] = { "st", NULL }; 65 | 66 | static const char *screen_dec[] = { "brightnessctl", "-q", "set", "10%-", NULL }; 67 | static const char *screen_inc[] = { "brightnessctl", "-q", "set", "10%+", NULL }; 68 | static const char *keyboard_dec[] = { "brightnessctl", "-d", "*::kbd_backlight", "set", "1-", NULL }; 69 | static const char *keyboard_inc[] = { "brightnessctl", "-d", "*::kbd_backlight", "set", "1+", NULL }; 70 | static const char *volume_dec[] = { "wpctl", "set-volume", "@DEFAULT_SINK@", "10%-", NULL }; 71 | static const char *volume_inc[] = { "wpctl", "set-volume", "@DEFAULT_SINK@", "10%+", NULL }; 72 | static const char *volume_mute[] = { "wpctl", "set-mute", "@DEFAULT_SINK@", "toggle", NULL }; 73 | static const char *screenshot_active[] = { "sh", "-c", "maim -u $HOME/Downloads/$(date +%s).png", NULL }; 74 | static const char *screenshot_region[] = { "sh", "-c", "maim -u -s $HOME/Downloads/$(date +%s).png", NULL }; 75 | 76 | static const Key keys[] = { 77 | /* modifier key function argument */ 78 | { MODKEY, XK_a, spawn, {.v = dmenucmd } }, 79 | { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, 80 | { MODKEY, XK_Left, spawn, {.v = screen_dec} }, 81 | { MODKEY, XK_Right, spawn, {.v = screen_inc} }, 82 | { MODKEY|ShiftMask, XK_Left, spawn, {.v = keyboard_dec} }, 83 | { MODKEY|ShiftMask, XK_Right, spawn, {.v = keyboard_inc} }, 84 | { MODKEY, XK_Down, spawn, {.v = volume_dec} }, 85 | { MODKEY, XK_Up, spawn, {.v = volume_inc} }, 86 | { MODKEY, XK_v, spawn, {.v = volume_mute} }, 87 | { MODKEY, XK_s, spawn, {.v = screenshot_active} }, 88 | { MODKEY|ShiftMask, XK_s, spawn, {.v = screenshot_region} }, 89 | { MODKEY, XK_b, togglebar, {0} }, 90 | { MODKEY, XK_j, focusstack, {.i = +1 } }, 91 | { MODKEY, XK_k, focusstack, {.i = -1 } }, 92 | { MODKEY, XK_e, incnmaster, {.i = +1 } }, 93 | { MODKEY, XK_d, incnmaster, {.i = -1 } }, 94 | { MODKEY, XK_h, setmfact, {.f = -0.05} }, 95 | { MODKEY, XK_l, setmfact, {.f = +0.05} }, 96 | { MODKEY, XK_Return, zoom, {0} }, 97 | { MODKEY, XK_Tab, view, {0} }, 98 | { MODKEY|ShiftMask, XK_c, killclient, {0} }, 99 | { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, 100 | { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, 101 | { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, 102 | { MODKEY, XK_space, setlayout, {0} }, 103 | { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, 104 | { MODKEY, XK_0, view, {.ui = ~0 } }, 105 | { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, 106 | { MODKEY, XK_comma, focusmon, {.i = -1 } }, 107 | { MODKEY, XK_period, focusmon, {.i = +1 } }, 108 | { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, 109 | { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, 110 | TAGKEYS( XK_u, 0) 111 | TAGKEYS( XK_i, 1) 112 | TAGKEYS( XK_o, 2) 113 | TAGKEYS( XK_p, 3) 114 | { MODKEY|ShiftMask, XK_q, quit, {0} }, 115 | }; 116 | 117 | /* button definitions */ 118 | /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ 119 | static const Button buttons[] = { 120 | /* click event mask button function argument */ 121 | { ClkLtSymbol, 0, Button1, setlayout, {0} }, 122 | { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, 123 | { ClkWinTitle, 0, Button2, zoom, {0} }, 124 | { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, 125 | { ClkClientWin, MODKEY, Button1, movemouse, {0} }, 126 | { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, 127 | { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, 128 | { ClkTagBar, 0, Button1, view, {0} }, 129 | { ClkTagBar, 0, Button3, toggleview, {0} }, 130 | { ClkTagBar, MODKEY, Button1, tag, {0} }, 131 | { ClkTagBar, MODKEY, Button3, toggletag, {0} }, 132 | }; 133 | 134 | -------------------------------------------------------------------------------- /st/patches/st-scrollback-ringbuffer-0.9.2.diff: -------------------------------------------------------------------------------- 1 | commit 0663bdf11a409961da5b1120741a69814da8ce65 2 | Author: Timo Röhling 3 | Date: Tue Nov 23 19:45:33 2021 +0100 4 | 5 | Terminal scrollback with ring buffer 6 | 7 | This patch adds a ring buffer for scrollback to the terminal. The 8 | advantage of using a ring buffer is that the common case, scrolling with 9 | no static screen content, can be achieved very efficiently by 10 | incrementing and decrementing the starting line (modulo buffer size). 11 | 12 | The scrollback buffer is limited to HISTSIZE lines in order to bound 13 | memory usage. As the lines are allocated on demand, it is possible to 14 | implement unlimited scrollback with few changes. If the terminal is 15 | reset, the scroll back buffer is reset, too. 16 | 17 | diff --git a/config.def.h b/config.def.h 18 | index 2cd740a..8b25d40 100644 19 | --- a/config.def.h 20 | +++ b/config.def.h 21 | @@ -201,6 +201,8 @@ static Shortcut shortcuts[] = { 22 | { TERMMOD, XK_Y, selpaste, {.i = 0} }, 23 | { ShiftMask, XK_Insert, selpaste, {.i = 0} }, 24 | { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, 25 | + { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, 26 | + { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, 27 | }; 28 | 29 | /* 30 | diff --git a/st.c b/st.c 31 | index b9f66e7..d9b163e 100644 32 | --- a/st.c 33 | +++ b/st.c 34 | @@ -43,6 +43,10 @@ 35 | #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) 36 | #define ISDELIM(u) (u && wcschr(worddelimiters, u)) 37 | 38 | +#define TSCREEN term.screen[IS_SET(MODE_ALTSCREEN)] 39 | +#define TLINEOFFSET(y) (((y) + TSCREEN.cur - TSCREEN.off + TSCREEN.size) % TSCREEN.size) 40 | +#define TLINE(y) (TSCREEN.buffer[TLINEOFFSET(y)]) 41 | + 42 | enum term_mode { 43 | MODE_WRAP = 1 << 0, 44 | MODE_INSERT = 1 << 1, 45 | @@ -109,12 +113,21 @@ typedef struct { 46 | int alt; 47 | } Selection; 48 | 49 | +/* Screen lines */ 50 | +typedef struct { 51 | + Line* buffer; /* ring buffer */ 52 | + int size; /* size of buffer */ 53 | + int cur; /* start of active screen */ 54 | + int off; /* scrollback line offset */ 55 | + TCursor sc; /* saved cursor */ 56 | +} LineBuffer; 57 | + 58 | /* Internal representation of the screen */ 59 | typedef struct { 60 | int row; /* nb row */ 61 | int col; /* nb col */ 62 | - Line *line; /* screen */ 63 | - Line *alt; /* alternate screen */ 64 | + LineBuffer screen[2]; /* screen and alternate screen */ 65 | + int linelen; /* allocated line length */ 66 | int *dirty; /* dirtyness of lines */ 67 | TCursor c; /* cursor */ 68 | int ocx; /* old cursor col */ 69 | @@ -203,6 +216,8 @@ static void tdeftran(char); 70 | static void tstrsequence(uchar); 71 | 72 | static void drawregion(int, int, int, int); 73 | +static void clearline(Line, Glyph, int, int); 74 | +static Line ensureline(Line); 75 | 76 | static void selnormalize(void); 77 | static void selscroll(int, int); 78 | @@ -408,11 +423,12 @@ int 79 | tlinelen(int y) 80 | { 81 | int i = term.col; 82 | + Line line = TLINE(y); 83 | 84 | - if (term.line[y][i - 1].mode & ATTR_WRAP) 85 | + if (line[i - 1].mode & ATTR_WRAP) 86 | return i; 87 | 88 | - while (i > 0 && term.line[y][i - 1].u == ' ') 89 | + while (i > 0 && line[i - 1].u == ' ') 90 | --i; 91 | 92 | return i; 93 | @@ -521,7 +537,7 @@ selsnap(int *x, int *y, int direction) 94 | * Snap around if the word wraps around at the end or 95 | * beginning of a line. 96 | */ 97 | - prevgp = &term.line[*y][*x]; 98 | + prevgp = &TLINE(*y)[*x]; 99 | prevdelim = ISDELIM(prevgp->u); 100 | for (;;) { 101 | newx = *x + direction; 102 | @@ -536,14 +552,14 @@ selsnap(int *x, int *y, int direction) 103 | yt = *y, xt = *x; 104 | else 105 | yt = newy, xt = newx; 106 | - if (!(term.line[yt][xt].mode & ATTR_WRAP)) 107 | + if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) 108 | break; 109 | } 110 | 111 | if (newx >= tlinelen(newy)) 112 | break; 113 | 114 | - gp = &term.line[newy][newx]; 115 | + gp = &TLINE(newy)[newx]; 116 | delim = ISDELIM(gp->u); 117 | if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim 118 | || (delim && gp->u != prevgp->u))) 119 | @@ -564,14 +580,14 @@ selsnap(int *x, int *y, int direction) 120 | *x = (direction < 0) ? 0 : term.col - 1; 121 | if (direction < 0) { 122 | for (; *y > 0; *y += direction) { 123 | - if (!(term.line[*y-1][term.col-1].mode 124 | + if (!(TLINE(*y-1)[term.col-1].mode 125 | & ATTR_WRAP)) { 126 | break; 127 | } 128 | } 129 | } else if (direction > 0) { 130 | for (; *y < term.row-1; *y += direction) { 131 | - if (!(term.line[*y][term.col-1].mode 132 | + if (!(TLINE(*y)[term.col-1].mode 133 | & ATTR_WRAP)) { 134 | break; 135 | } 136 | @@ -602,13 +618,13 @@ getsel(void) 137 | } 138 | 139 | if (sel.type == SEL_RECTANGULAR) { 140 | - gp = &term.line[y][sel.nb.x]; 141 | + gp = &TLINE(y)[sel.nb.x]; 142 | lastx = sel.ne.x; 143 | } else { 144 | - gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; 145 | + gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; 146 | lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; 147 | } 148 | - last = &term.line[y][MIN(lastx, linelen-1)]; 149 | + last = &TLINE(y)[MIN(lastx, linelen-1)]; 150 | while (last >= gp && last->u == ' ') 151 | --last; 152 | 153 | @@ -949,12 +965,15 @@ int 154 | tattrset(int attr) 155 | { 156 | int i, j; 157 | + int y = TLINEOFFSET(0); 158 | 159 | for (i = 0; i < term.row-1; i++) { 160 | + Line line = TSCREEN.buffer[y]; 161 | for (j = 0; j < term.col-1; j++) { 162 | - if (term.line[i][j].mode & attr) 163 | + if (line[j].mode & attr) 164 | return 1; 165 | } 166 | + y = (y+1) % TSCREEN.size; 167 | } 168 | 169 | return 0; 170 | @@ -976,14 +995,17 @@ void 171 | tsetdirtattr(int attr) 172 | { 173 | int i, j; 174 | + int y = TLINEOFFSET(0); 175 | 176 | for (i = 0; i < term.row-1; i++) { 177 | + Line line = TSCREEN.buffer[y]; 178 | for (j = 0; j < term.col-1; j++) { 179 | - if (term.line[i][j].mode & attr) { 180 | + if (line[j].mode & attr) { 181 | tsetdirt(i, i); 182 | break; 183 | } 184 | } 185 | + y = (y+1) % TSCREEN.size; 186 | } 187 | } 188 | 189 | @@ -996,27 +1018,19 @@ tfulldirt(void) 190 | void 191 | tcursor(int mode) 192 | { 193 | - static TCursor c[2]; 194 | - int alt = IS_SET(MODE_ALTSCREEN); 195 | - 196 | if (mode == CURSOR_SAVE) { 197 | - c[alt] = term.c; 198 | + TSCREEN.sc = term.c; 199 | } else if (mode == CURSOR_LOAD) { 200 | - term.c = c[alt]; 201 | - tmoveto(c[alt].x, c[alt].y); 202 | + term.c = TSCREEN.sc; 203 | + tmoveto(term.c.x, term.c.y); 204 | } 205 | } 206 | 207 | void 208 | treset(void) 209 | { 210 | - uint i; 211 | - 212 | - term.c = (TCursor){{ 213 | - .mode = ATTR_NULL, 214 | - .fg = defaultfg, 215 | - .bg = defaultbg 216 | - }, .x = 0, .y = 0, .state = CURSOR_DEFAULT}; 217 | + int i, j; 218 | + Glyph g = (Glyph){ .fg = defaultfg, .bg = defaultbg}; 219 | 220 | memset(term.tabs, 0, term.col * sizeof(*term.tabs)); 221 | for (i = tabspaces; i < term.col; i += tabspaces) 222 | @@ -1028,17 +1042,37 @@ treset(void) 223 | term.charset = 0; 224 | 225 | for (i = 0; i < 2; i++) { 226 | - tmoveto(0, 0); 227 | - tcursor(CURSOR_SAVE); 228 | - tclearregion(0, 0, term.col-1, term.row-1); 229 | - tswapscreen(); 230 | + term.screen[i].sc = (TCursor){{ 231 | + .fg = defaultfg, 232 | + .bg = defaultbg 233 | + }}; 234 | + term.screen[i].cur = 0; 235 | + term.screen[i].off = 0; 236 | + for (j = 0; j < term.row; ++j) { 237 | + if (term.col != term.linelen) 238 | + term.screen[i].buffer[j] = xrealloc(term.screen[i].buffer[j], term.col * sizeof(Glyph)); 239 | + clearline(term.screen[i].buffer[j], g, 0, term.col); 240 | + } 241 | + for (j = term.row; j < term.screen[i].size; ++j) { 242 | + free(term.screen[i].buffer[j]); 243 | + term.screen[i].buffer[j] = NULL; 244 | + } 245 | } 246 | + tcursor(CURSOR_LOAD); 247 | + term.linelen = term.col; 248 | + tfulldirt(); 249 | } 250 | 251 | void 252 | tnew(int col, int row) 253 | { 254 | - term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } }; 255 | + int i; 256 | + term = (Term){}; 257 | + term.screen[0].buffer = xmalloc(HISTSIZE * sizeof(Line)); 258 | + term.screen[0].size = HISTSIZE; 259 | + term.screen[1].buffer = NULL; 260 | + for (i = 0; i < HISTSIZE; ++i) term.screen[0].buffer[i] = NULL; 261 | + 262 | tresize(col, row); 263 | treset(); 264 | } 265 | @@ -1046,14 +1080,42 @@ tnew(int col, int row) 266 | void 267 | tswapscreen(void) 268 | { 269 | - Line *tmp = term.line; 270 | - 271 | - term.line = term.alt; 272 | - term.alt = tmp; 273 | term.mode ^= MODE_ALTSCREEN; 274 | tfulldirt(); 275 | } 276 | 277 | +void 278 | +kscrollup(const Arg *a) 279 | +{ 280 | + int n = a->i; 281 | + 282 | + if (IS_SET(MODE_ALTSCREEN)) 283 | + return; 284 | + 285 | + if (n < 0) n = (-n) * term.row; 286 | + if (n > TSCREEN.size - term.row - TSCREEN.off) n = TSCREEN.size - term.row - TSCREEN.off; 287 | + while (!TLINE(-n)) --n; 288 | + TSCREEN.off += n; 289 | + selscroll(0, n); 290 | + tfulldirt(); 291 | +} 292 | + 293 | +void 294 | +kscrolldown(const Arg *a) 295 | +{ 296 | + 297 | + int n = a->i; 298 | + 299 | + if (IS_SET(MODE_ALTSCREEN)) 300 | + return; 301 | + 302 | + if (n < 0) n = (-n) * term.row; 303 | + if (n > TSCREEN.off) n = TSCREEN.off; 304 | + TSCREEN.off -= n; 305 | + selscroll(0, -n); 306 | + tfulldirt(); 307 | +} 308 | + 309 | void 310 | tscrolldown(int orig, int n) 311 | { 312 | @@ -1062,15 +1124,29 @@ tscrolldown(int orig, int n) 313 | 314 | LIMIT(n, 0, term.bot-orig+1); 315 | 316 | - tsetdirt(orig, term.bot-n); 317 | - tclearregion(0, term.bot-n+1, term.col-1, term.bot); 318 | + /* Ensure that lines are allocated */ 319 | + for (i = -n; i < 0; i++) { 320 | + TLINE(i) = ensureline(TLINE(i)); 321 | + } 322 | 323 | - for (i = term.bot; i >= orig+n; i--) { 324 | - temp = term.line[i]; 325 | - term.line[i] = term.line[i-n]; 326 | - term.line[i-n] = temp; 327 | + /* Shift non-scrolling areas in ring buffer */ 328 | + for (i = term.bot+1; i < term.row; i++) { 329 | + temp = TLINE(i); 330 | + TLINE(i) = TLINE(i-n); 331 | + TLINE(i-n) = temp; 332 | + } 333 | + for (i = 0; i < orig; i++) { 334 | + temp = TLINE(i); 335 | + TLINE(i) = TLINE(i-n); 336 | + TLINE(i-n) = temp; 337 | } 338 | 339 | + /* Scroll buffer */ 340 | + TSCREEN.cur = (TSCREEN.cur + TSCREEN.size - n) % TSCREEN.size; 341 | + /* Clear lines that have entered the view */ 342 | + tclearregion(0, orig, term.linelen-1, orig+n-1); 343 | + /* Redraw portion of the screen that has scrolled */ 344 | + tsetdirt(orig+n-1, term.bot); 345 | selscroll(orig, n); 346 | } 347 | 348 | @@ -1082,15 +1158,29 @@ tscrollup(int orig, int n) 349 | 350 | LIMIT(n, 0, term.bot-orig+1); 351 | 352 | - tclearregion(0, orig, term.col-1, orig+n-1); 353 | - tsetdirt(orig+n, term.bot); 354 | + /* Ensure that lines are allocated */ 355 | + for (i = term.row; i < term.row + n; i++) { 356 | + TLINE(i) = ensureline(TLINE(i)); 357 | + } 358 | 359 | - for (i = orig; i <= term.bot-n; i++) { 360 | - temp = term.line[i]; 361 | - term.line[i] = term.line[i+n]; 362 | - term.line[i+n] = temp; 363 | + /* Shift non-scrolling areas in ring buffer */ 364 | + for (i = orig-1; i >= 0; i--) { 365 | + temp = TLINE(i); 366 | + TLINE(i) = TLINE(i+n); 367 | + TLINE(i+n) = temp; 368 | + } 369 | + for (i = term.row-1; i >term.bot; i--) { 370 | + temp = TLINE(i); 371 | + TLINE(i) = TLINE(i+n); 372 | + TLINE(i+n) = temp; 373 | } 374 | 375 | + /* Scroll buffer */ 376 | + TSCREEN.cur = (TSCREEN.cur + n) % TSCREEN.size; 377 | + /* Clear lines that have entered the view */ 378 | + tclearregion(0, term.bot-n+1, term.linelen-1, term.bot); 379 | + /* Redraw portion of the screen that has scrolled */ 380 | + tsetdirt(orig, term.bot-n+1); 381 | selscroll(orig, -n); 382 | } 383 | 384 | @@ -1194,6 +1284,7 @@ tsetchar(Rune u, const Glyph *attr, int x, int y) 385 | "⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */ 386 | "│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */ 387 | }; 388 | + Line line = TLINE(y); 389 | 390 | /* 391 | * The table is proudly stolen from rxvt. 392 | @@ -1202,25 +1293,25 @@ tsetchar(Rune u, const Glyph *attr, int x, int y) 393 | BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41]) 394 | utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ); 395 | 396 | - if (term.line[y][x].mode & ATTR_WIDE) { 397 | + if (line[x].mode & ATTR_WIDE) { 398 | if (x+1 < term.col) { 399 | - term.line[y][x+1].u = ' '; 400 | - term.line[y][x+1].mode &= ~ATTR_WDUMMY; 401 | + line[x+1].u = ' '; 402 | + line[x+1].mode &= ~ATTR_WDUMMY; 403 | } 404 | - } else if (term.line[y][x].mode & ATTR_WDUMMY) { 405 | - term.line[y][x-1].u = ' '; 406 | - term.line[y][x-1].mode &= ~ATTR_WIDE; 407 | + } else if (line[x].mode & ATTR_WDUMMY) { 408 | + line[x-1].u = ' '; 409 | + line[x-1].mode &= ~ATTR_WIDE; 410 | } 411 | 412 | term.dirty[y] = 1; 413 | - term.line[y][x] = *attr; 414 | - term.line[y][x].u = u; 415 | + line[x] = *attr; 416 | + line[x].u = u; 417 | } 418 | 419 | void 420 | tclearregion(int x1, int y1, int x2, int y2) 421 | { 422 | - int x, y, temp; 423 | + int x, y, L, S, temp; 424 | Glyph *gp; 425 | 426 | if (x1 > x2) 427 | @@ -1228,15 +1319,16 @@ tclearregion(int x1, int y1, int x2, int y2) 428 | if (y1 > y2) 429 | temp = y1, y1 = y2, y2 = temp; 430 | 431 | - LIMIT(x1, 0, term.col-1); 432 | - LIMIT(x2, 0, term.col-1); 433 | + LIMIT(x1, 0, term.linelen-1); 434 | + LIMIT(x2, 0, term.linelen-1); 435 | LIMIT(y1, 0, term.row-1); 436 | LIMIT(y2, 0, term.row-1); 437 | 438 | + L = TLINEOFFSET(y1); 439 | for (y = y1; y <= y2; y++) { 440 | term.dirty[y] = 1; 441 | for (x = x1; x <= x2; x++) { 442 | - gp = &term.line[y][x]; 443 | + gp = &TSCREEN.buffer[L][x]; 444 | if (selected(x, y)) 445 | selclear(); 446 | gp->fg = term.c.attr.fg; 447 | @@ -1244,6 +1336,7 @@ tclearregion(int x1, int y1, int x2, int y2) 448 | gp->mode = 0; 449 | gp->u = ' '; 450 | } 451 | + L = (L + 1) % TSCREEN.size; 452 | } 453 | } 454 | 455 | @@ -1258,7 +1351,7 @@ tdeletechar(int n) 456 | dst = term.c.x; 457 | src = term.c.x + n; 458 | size = term.col - src; 459 | - line = term.line[term.c.y]; 460 | + line = TLINE(term.c.y); 461 | 462 | memmove(&line[dst], &line[src], size * sizeof(Glyph)); 463 | tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); 464 | @@ -1275,7 +1368,7 @@ tinsertblank(int n) 465 | dst = term.c.x + n; 466 | src = term.c.x; 467 | size = term.col - dst; 468 | - line = term.line[term.c.y]; 469 | + line = TLINE(term.c.y); 470 | 471 | memmove(&line[dst], &line[src], size * sizeof(Glyph)); 472 | tclearregion(src, term.c.y, dst - 1, term.c.y); 473 | @@ -2079,7 +2172,7 @@ tdumpline(int n) 474 | char buf[UTF_SIZ]; 475 | const Glyph *bp, *end; 476 | 477 | - bp = &term.line[n][0]; 478 | + bp = &TLINE(n)[0]; 479 | end = &bp[MIN(tlinelen(n), term.col) - 1]; 480 | if (bp != end || bp->u != ' ') { 481 | for ( ; bp <= end; ++bp) 482 | @@ -2466,11 +2559,11 @@ check_control_code: 483 | if (selected(term.c.x, term.c.y)) 484 | selclear(); 485 | 486 | - gp = &term.line[term.c.y][term.c.x]; 487 | + gp = &TLINE(term.c.y)[term.c.x]; 488 | if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) { 489 | gp->mode |= ATTR_WRAP; 490 | tnewline(1); 491 | - gp = &term.line[term.c.y][term.c.x]; 492 | + gp = &TLINE(term.c.y)[term.c.x]; 493 | } 494 | 495 | if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) { 496 | @@ -2483,7 +2576,7 @@ check_control_code: 497 | tnewline(1); 498 | else 499 | tmoveto(term.col - width, term.c.y); 500 | - gp = &term.line[term.c.y][term.c.x]; 501 | + gp = &TLINE(term.c.y)[term.c.x]; 502 | } 503 | 504 | tsetchar(u, &term.c.attr, term.c.x, term.c.y); 505 | @@ -2514,6 +2607,11 @@ twrite(const char *buf, int buflen, int show_ctrl) 506 | Rune u; 507 | int n; 508 | 509 | + if (TSCREEN.off) { 510 | + TSCREEN.off = 0; 511 | + tfulldirt(); 512 | + } 513 | + 514 | for (n = 0; n < buflen; n += charsize) { 515 | if (IS_SET(MODE_UTF8)) { 516 | /* process a complete utf8 char */ 517 | @@ -2540,56 +2638,85 @@ twrite(const char *buf, int buflen, int show_ctrl) 518 | } 519 | 520 | void 521 | -tresize(int col, int row) 522 | +clearline(Line line, Glyph g, int x, int xend) 523 | { 524 | int i; 525 | + g.mode = 0; 526 | + g.u = ' '; 527 | + for (i = x; i < xend; ++i) { 528 | + line[i] = g; 529 | + } 530 | +} 531 | + 532 | +Line 533 | +ensureline(Line line) 534 | +{ 535 | + if (!line) { 536 | + line = xmalloc(term.linelen * sizeof(Glyph)); 537 | + } 538 | + return line; 539 | +} 540 | + 541 | +void 542 | +tresize(int col, int row) 543 | +{ 544 | + int i, j; 545 | int minrow = MIN(row, term.row); 546 | int mincol = MIN(col, term.col); 547 | + int linelen = MAX(col, term.linelen); 548 | int *bp; 549 | - TCursor c; 550 | 551 | - if (col < 1 || row < 1) { 552 | + if (col < 1 || row < 1 || row > HISTSIZE) { 553 | fprintf(stderr, 554 | "tresize: error resizing to %dx%d\n", col, row); 555 | return; 556 | } 557 | 558 | - /* 559 | - * slide screen to keep cursor where we expect it - 560 | - * tscrollup would work here, but we can optimize to 561 | - * memmove because we're freeing the earlier lines 562 | - */ 563 | - for (i = 0; i <= term.c.y - row; i++) { 564 | - free(term.line[i]); 565 | - free(term.alt[i]); 566 | + /* Shift buffer to keep the cursor where we expect it */ 567 | + if (row <= term.c.y) { 568 | + term.screen[0].cur = (term.screen[0].cur - row + term.c.y + 1) % term.screen[0].size; 569 | + } 570 | + 571 | + /* Resize and clear line buffers as needed */ 572 | + if (linelen > term.linelen) { 573 | + for (i = 0; i < term.screen[0].size; ++i) { 574 | + if (term.screen[0].buffer[i]) { 575 | + term.screen[0].buffer[i] = xrealloc(term.screen[0].buffer[i], linelen * sizeof(Glyph)); 576 | + clearline(term.screen[0].buffer[i], term.c.attr, term.linelen, linelen); 577 | + } 578 | + } 579 | + for (i = 0; i < minrow; ++i) { 580 | + term.screen[1].buffer[i] = xrealloc(term.screen[1].buffer[i], linelen * sizeof(Glyph)); 581 | + clearline(term.screen[1].buffer[i], term.c.attr, term.linelen, linelen); 582 | + } 583 | } 584 | - /* ensure that both src and dst are not NULL */ 585 | - if (i > 0) { 586 | - memmove(term.line, term.line + i, row * sizeof(Line)); 587 | - memmove(term.alt, term.alt + i, row * sizeof(Line)); 588 | + /* Allocate all visible lines for regular line buffer */ 589 | + for (j = term.screen[0].cur, i = 0; i < row; ++i, j = (j + 1) % term.screen[0].size) 590 | + { 591 | + if (!term.screen[0].buffer[j]) { 592 | + term.screen[0].buffer[j] = xmalloc(linelen * sizeof(Glyph)); 593 | + } 594 | + if (i >= term.row) { 595 | + clearline(term.screen[0].buffer[j], term.c.attr, 0, linelen); 596 | + } 597 | } 598 | - for (i += row; i < term.row; i++) { 599 | - free(term.line[i]); 600 | - free(term.alt[i]); 601 | + /* Resize alt screen */ 602 | + term.screen[1].cur = 0; 603 | + term.screen[1].size = row; 604 | + for (i = row; i < term.row; ++i) { 605 | + free(term.screen[1].buffer[i]); 606 | + } 607 | + term.screen[1].buffer = xrealloc(term.screen[1].buffer, row * sizeof(Line)); 608 | + for (i = term.row; i < row; ++i) { 609 | + term.screen[1].buffer[i] = xmalloc(linelen * sizeof(Glyph)); 610 | + clearline(term.screen[1].buffer[i], term.c.attr, 0, linelen); 611 | } 612 | 613 | /* resize to new height */ 614 | - term.line = xrealloc(term.line, row * sizeof(Line)); 615 | - term.alt = xrealloc(term.alt, row * sizeof(Line)); 616 | term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); 617 | term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); 618 | 619 | - /* resize each row to new width, zero-pad if needed */ 620 | - for (i = 0; i < minrow; i++) { 621 | - term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); 622 | - term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph)); 623 | - } 624 | - 625 | - /* allocate any new rows */ 626 | - for (/* i = minrow */; i < row; i++) { 627 | - term.line[i] = xmalloc(col * sizeof(Glyph)); 628 | - term.alt[i] = xmalloc(col * sizeof(Glyph)); 629 | - } 630 | + /* fix tabstops */ 631 | if (col > term.col) { 632 | bp = term.tabs + term.col; 633 | 634 | @@ -2599,26 +2726,16 @@ tresize(int col, int row) 635 | for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces) 636 | *bp = 1; 637 | } 638 | + 639 | /* update terminal size */ 640 | term.col = col; 641 | term.row = row; 642 | + term.linelen = linelen; 643 | /* reset scrolling region */ 644 | tsetscroll(0, row-1); 645 | /* make use of the LIMIT in tmoveto */ 646 | tmoveto(term.c.x, term.c.y); 647 | - /* Clearing both screens (it makes dirty all lines) */ 648 | - c = term.c; 649 | - for (i = 0; i < 2; i++) { 650 | - if (mincol < col && 0 < minrow) { 651 | - tclearregion(mincol, 0, col - 1, minrow - 1); 652 | - } 653 | - if (0 < col && minrow < row) { 654 | - tclearregion(0, minrow, col - 1, row - 1); 655 | - } 656 | - tswapscreen(); 657 | - tcursor(CURSOR_LOAD); 658 | - } 659 | - term.c = c; 660 | + tfulldirt(); 661 | } 662 | 663 | void 664 | @@ -2630,14 +2747,15 @@ resettitle(void) 665 | void 666 | drawregion(int x1, int y1, int x2, int y2) 667 | { 668 | - int y; 669 | + int y, L; 670 | 671 | + L = TLINEOFFSET(y1); 672 | for (y = y1; y < y2; y++) { 673 | - if (!term.dirty[y]) 674 | - continue; 675 | - 676 | - term.dirty[y] = 0; 677 | - xdrawline(term.line[y], x1, y, x2); 678 | + if (term.dirty[y]) { 679 | + term.dirty[y] = 0; 680 | + xdrawline(TSCREEN.buffer[L], x1, y, x2); 681 | + } 682 | + L = (L + 1) % TSCREEN.size; 683 | } 684 | } 685 | 686 | @@ -2652,14 +2770,15 @@ draw(void) 687 | /* adjust cursor position */ 688 | LIMIT(term.ocx, 0, term.col-1); 689 | LIMIT(term.ocy, 0, term.row-1); 690 | - if (term.line[term.ocy][term.ocx].mode & ATTR_WDUMMY) 691 | + if (TLINE(term.ocy)[term.ocx].mode & ATTR_WDUMMY) 692 | term.ocx--; 693 | - if (term.line[term.c.y][cx].mode & ATTR_WDUMMY) 694 | + if (TLINE(term.c.y)[cx].mode & ATTR_WDUMMY) 695 | cx--; 696 | 697 | drawregion(0, 0, term.col, term.row); 698 | - xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], 699 | - term.ocx, term.ocy, term.line[term.ocy][term.ocx]); 700 | + if (TSCREEN.off == 0) 701 | + xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx], 702 | + term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]); 703 | term.ocx = cx; 704 | term.ocy = term.c.y; 705 | xfinishdraw(); 706 | diff --git a/st.h b/st.h 707 | index fd3b0d8..3cea73b 100644 708 | --- a/st.h 709 | +++ b/st.h 710 | @@ -19,6 +19,7 @@ 711 | 712 | #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) 713 | #define IS_TRUECOL(x) (1 << 24 & (x)) 714 | +#define HISTSIZE 2000 715 | 716 | enum glyph_attribute { 717 | ATTR_NULL = 0, 718 | diff --git a/x.c b/x.c 719 | index bd23686..25785a6 100644 720 | --- a/x.c 721 | +++ b/x.c 722 | @@ -59,6 +59,8 @@ static void zoom(const Arg *); 723 | static void zoomabs(const Arg *); 724 | static void zoomreset(const Arg *); 725 | static void ttysend(const Arg *); 726 | +void kscrollup(const Arg *); 727 | +void kscrolldown(const Arg *); 728 | 729 | /* config.h for applying patches and the configuration. */ 730 | #include "config.h" 731 | -------------------------------------------------------------------------------- /st/config.def.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | 3 | /* 4 | * appearance 5 | * 6 | * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html 7 | */ 8 | static char *font = "Cascadia Mono NF:size=19:antialias=true:autohint=true"; 9 | static int borderpx = 2; 10 | 11 | /* 12 | * What program is execed by st depends of these precedence rules: 13 | * 1: program passed with -e 14 | * 2: scroll and/or utmp 15 | * 3: SHELL environment variable 16 | * 4: value of shell in /etc/passwd 17 | * 5: value of shell in config.h 18 | */ 19 | static char *shell = "/bin/sh"; 20 | char *utmp = NULL; 21 | /* scroll program: to enable use a string like "scroll" */ 22 | char *scroll = NULL; 23 | char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; 24 | 25 | /* identification sequence returned in DA and DECID */ 26 | char *vtiden = "\033[?6c"; 27 | 28 | /* Kerning / character bounding-box multipliers */ 29 | static float cwscale = 1.0; 30 | static float chscale = 1.0; 31 | 32 | /* 33 | * word delimiter string 34 | * 35 | * More advanced example: L" `'\"()[]{}" 36 | */ 37 | wchar_t *worddelimiters = L" "; 38 | 39 | /* selection timeouts (in milliseconds) */ 40 | static unsigned int doubleclicktimeout = 300; 41 | static unsigned int tripleclicktimeout = 600; 42 | 43 | /* alt screens */ 44 | int allowaltscreen = 1; 45 | 46 | /* allow certain non-interactive (insecure) window operations such as: 47 | setting the clipboard text */ 48 | int allowwindowops = 0; 49 | 50 | /* 51 | * draw latency range in ms - from new content/keypress/etc until drawing. 52 | * within this range, st draws when content stops arriving (idle). mostly it's 53 | * near minlatency, but it waits longer for slow updates to avoid partial draw. 54 | * low minlatency will tear/flicker more, as it can "detect" idle too early. 55 | */ 56 | static double minlatency = 2; 57 | static double maxlatency = 33; 58 | 59 | /* 60 | * blinking timeout (set to 0 to disable blinking) for the terminal blinking 61 | * attribute. 62 | */ 63 | static unsigned int blinktimeout = 0; 64 | 65 | /* 66 | * thickness of underline and bar cursors 67 | */ 68 | static unsigned int cursorthickness = 2; 69 | 70 | /* 71 | * bell volume. It must be a value between -100 and 100. Use 0 for disabling 72 | * it 73 | */ 74 | static int bellvolume = 0; 75 | 76 | /* default TERM value */ 77 | char *termname = "st-256color"; 78 | 79 | /* 80 | * spaces per tab 81 | * 82 | * When you are changing this value, don't forget to adapt the »it« value in 83 | * the st.info and appropriately install the st.info in the environment where 84 | * you use this st version. 85 | * 86 | * it#$tabspaces, 87 | * 88 | * Secondly make sure your kernel is not expanding tabs. When running `stty 89 | * -a` »tab0« should appear. You can tell the terminal to not expand tabs by 90 | * running following command: 91 | * 92 | * stty tabs 93 | */ 94 | unsigned int tabspaces = 8; 95 | 96 | /* Terminal colors (16 first used in escape sequence) */ 97 | static const char *colorname[] = { 98 | /* 8 normal colors */ 99 | "black", 100 | "red3", 101 | "green3", 102 | "yellow3", 103 | "blue2", 104 | "magenta3", 105 | "cyan3", 106 | "gray90", 107 | 108 | /* 8 bright colors */ 109 | "gray50", 110 | "red", 111 | "green", 112 | "yellow", 113 | "#5c5cff", 114 | "magenta", 115 | "cyan", 116 | "white", 117 | 118 | [255] = 0, 119 | 120 | /* more colors can be added after 255 to use with DefaultXX */ 121 | "#cccccc", 122 | "#555555", 123 | "gray90", /* default foreground colour */ 124 | "black", /* default background colour */ 125 | }; 126 | 127 | 128 | /* 129 | * Default colors (colorname index) 130 | * foreground, background, cursor, reverse cursor 131 | */ 132 | unsigned int defaultfg = 258; 133 | unsigned int defaultbg = 259; 134 | unsigned int defaultcs = 256; 135 | static unsigned int defaultrcs = 257; 136 | 137 | /* 138 | * Default shape of cursor 139 | * 2: Block ("█") 140 | * 4: Underline ("_") 141 | * 6: Bar ("|") 142 | * 7: Snowman ("☃") 143 | */ 144 | static unsigned int cursorshape = 2; 145 | 146 | /* 147 | * Default columns and rows numbers 148 | */ 149 | 150 | static unsigned int cols = 80; 151 | static unsigned int rows = 24; 152 | 153 | /* 154 | * Default colour and shape of the mouse cursor 155 | */ 156 | static unsigned int mouseshape = XC_xterm; 157 | static unsigned int mousefg = 7; 158 | static unsigned int mousebg = 0; 159 | 160 | /* 161 | * Color used to display font attributes when fontconfig selected a font which 162 | * doesn't match the ones requested. 163 | */ 164 | static unsigned int defaultattr = 11; 165 | 166 | /* 167 | * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set). 168 | * Note that if you want to use ShiftMask with selmasks, set this to an other 169 | * modifier, set to 0 to not use it. 170 | */ 171 | static uint forcemousemod = ShiftMask; 172 | 173 | /* 174 | * Internal mouse shortcuts. 175 | * Beware that overloading Button1 will disable the selection. 176 | */ 177 | static MouseShortcut mshortcuts[] = { 178 | /* mask button function argument release */ 179 | { ShiftMask, Button4, kscrollup, {.i = 1} }, 180 | { ShiftMask, Button5, kscrolldown, {.i = 1} }, 181 | { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, 182 | { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, 183 | { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, 184 | { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} }, 185 | { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} }, 186 | }; 187 | 188 | /* Internal keyboard shortcuts. */ 189 | #define MODKEY Mod1Mask 190 | #define TERMMOD (ControlMask|ShiftMask) 191 | 192 | static Shortcut shortcuts[] = { 193 | /* mask keysym function argument */ 194 | { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, 195 | { ControlMask, XK_Print, toggleprinter, {.i = 0} }, 196 | { ShiftMask, XK_Print, printscreen, {.i = 0} }, 197 | { XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, 198 | { TERMMOD, XK_I, zoom, {.f = +1} }, 199 | { TERMMOD, XK_O, zoom, {.f = -1} }, 200 | { TERMMOD, XK_Z, zoomreset, {.f = 0} }, 201 | { TERMMOD, XK_C, clipcopy, {.i = 0} }, 202 | { TERMMOD, XK_V, clippaste, {.i = 0} }, 203 | { TERMMOD, XK_Y, selpaste, {.i = 0} }, 204 | { ShiftMask, XK_Insert, selpaste, {.i = 0} }, 205 | { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, 206 | { TERMMOD, XK_U, kscrollup, {.i = -1} }, 207 | { TERMMOD, XK_D, kscrolldown, {.i = -1} }, 208 | }; 209 | 210 | /* 211 | * Special keys (change & recompile st.info accordingly) 212 | * 213 | * Mask value: 214 | * * Use XK_ANY_MOD to match the key no matter modifiers state 215 | * * Use XK_NO_MOD to match the key alone (no modifiers) 216 | * appkey value: 217 | * * 0: no value 218 | * * > 0: keypad application mode enabled 219 | * * = 2: term.numlock = 1 220 | * * < 0: keypad application mode disabled 221 | * appcursor value: 222 | * * 0: no value 223 | * * > 0: cursor application mode enabled 224 | * * < 0: cursor application mode disabled 225 | * 226 | * Be careful with the order of the definitions because st searches in 227 | * this table sequentially, so any XK_ANY_MOD must be in the last 228 | * position for a key. 229 | */ 230 | 231 | /* 232 | * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) 233 | * to be mapped below, add them to this array. 234 | */ 235 | static KeySym mappedkeys[] = { -1 }; 236 | 237 | /* 238 | * State bits to ignore when matching key or button events. By default, 239 | * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored. 240 | */ 241 | static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; 242 | 243 | /* 244 | * This is the huge key array which defines all compatibility to the Linux 245 | * world. Please decide about changes wisely. 246 | */ 247 | static Key key[] = { 248 | /* keysym mask string appkey appcursor */ 249 | { XK_KP_Home, ShiftMask, "\033[2J", 0, -1}, 250 | { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1}, 251 | { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1}, 252 | { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1}, 253 | { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0}, 254 | { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1}, 255 | { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1}, 256 | { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0}, 257 | { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1}, 258 | { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1}, 259 | { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0}, 260 | { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1}, 261 | { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1}, 262 | { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0}, 263 | { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1}, 264 | { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1}, 265 | { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0}, 266 | { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, 267 | { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0}, 268 | { XK_KP_End, ControlMask, "\033[J", -1, 0}, 269 | { XK_KP_End, ControlMask, "\033[1;5F", +1, 0}, 270 | { XK_KP_End, ShiftMask, "\033[K", -1, 0}, 271 | { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0}, 272 | { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0}, 273 | { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0}, 274 | { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0}, 275 | { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0}, 276 | { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0}, 277 | { XK_KP_Insert, ControlMask, "\033[L", -1, 0}, 278 | { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0}, 279 | { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, 280 | { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, 281 | { XK_KP_Delete, ControlMask, "\033[M", -1, 0}, 282 | { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0}, 283 | { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0}, 284 | { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0}, 285 | { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0}, 286 | { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, 287 | { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0}, 288 | { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0}, 289 | { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0}, 290 | { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0}, 291 | { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0}, 292 | { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0}, 293 | { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0}, 294 | { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0}, 295 | { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0}, 296 | { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0}, 297 | { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0}, 298 | { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0}, 299 | { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0}, 300 | { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0}, 301 | { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0}, 302 | { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0}, 303 | { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0}, 304 | { XK_Up, ShiftMask, "\033[1;2A", 0, 0}, 305 | { XK_Up, Mod1Mask, "\033[1;3A", 0, 0}, 306 | { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0}, 307 | { XK_Up, ControlMask, "\033[1;5A", 0, 0}, 308 | { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0}, 309 | { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0}, 310 | { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0}, 311 | { XK_Up, XK_ANY_MOD, "\033[A", 0, -1}, 312 | { XK_Up, XK_ANY_MOD, "\033OA", 0, +1}, 313 | { XK_Down, ShiftMask, "\033[1;2B", 0, 0}, 314 | { XK_Down, Mod1Mask, "\033[1;3B", 0, 0}, 315 | { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0}, 316 | { XK_Down, ControlMask, "\033[1;5B", 0, 0}, 317 | { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0}, 318 | { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0}, 319 | { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0}, 320 | { XK_Down, XK_ANY_MOD, "\033[B", 0, -1}, 321 | { XK_Down, XK_ANY_MOD, "\033OB", 0, +1}, 322 | { XK_Left, ShiftMask, "\033[1;2D", 0, 0}, 323 | { XK_Left, Mod1Mask, "\033[1;3D", 0, 0}, 324 | { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0}, 325 | { XK_Left, ControlMask, "\033[1;5D", 0, 0}, 326 | { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0}, 327 | { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0}, 328 | { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0}, 329 | { XK_Left, XK_ANY_MOD, "\033[D", 0, -1}, 330 | { XK_Left, XK_ANY_MOD, "\033OD", 0, +1}, 331 | { XK_Right, ShiftMask, "\033[1;2C", 0, 0}, 332 | { XK_Right, Mod1Mask, "\033[1;3C", 0, 0}, 333 | { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0}, 334 | { XK_Right, ControlMask, "\033[1;5C", 0, 0}, 335 | { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0}, 336 | { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0}, 337 | { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0}, 338 | { XK_Right, XK_ANY_MOD, "\033[C", 0, -1}, 339 | { XK_Right, XK_ANY_MOD, "\033OC", 0, +1}, 340 | { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0}, 341 | { XK_Return, Mod1Mask, "\033\r", 0, 0}, 342 | { XK_Return, XK_ANY_MOD, "\r", 0, 0}, 343 | { XK_Insert, ShiftMask, "\033[4l", -1, 0}, 344 | { XK_Insert, ShiftMask, "\033[2;2~", +1, 0}, 345 | { XK_Insert, ControlMask, "\033[L", -1, 0}, 346 | { XK_Insert, ControlMask, "\033[2;5~", +1, 0}, 347 | { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, 348 | { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, 349 | { XK_Delete, ControlMask, "\033[M", -1, 0}, 350 | { XK_Delete, ControlMask, "\033[3;5~", +1, 0}, 351 | { XK_Delete, ShiftMask, "\033[2K", -1, 0}, 352 | { XK_Delete, ShiftMask, "\033[3;2~", +1, 0}, 353 | { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0}, 354 | { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, 355 | { XK_BackSpace, XK_NO_MOD, "\177", 0, 0}, 356 | { XK_BackSpace, Mod1Mask, "\033\177", 0, 0}, 357 | { XK_Home, ShiftMask, "\033[2J", 0, -1}, 358 | { XK_Home, ShiftMask, "\033[1;2H", 0, +1}, 359 | { XK_Home, XK_ANY_MOD, "\033[H", 0, -1}, 360 | { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1}, 361 | { XK_End, ControlMask, "\033[J", -1, 0}, 362 | { XK_End, ControlMask, "\033[1;5F", +1, 0}, 363 | { XK_End, ShiftMask, "\033[K", -1, 0}, 364 | { XK_End, ShiftMask, "\033[1;2F", +1, 0}, 365 | { XK_End, XK_ANY_MOD, "\033[4~", 0, 0}, 366 | { XK_Prior, ControlMask, "\033[5;5~", 0, 0}, 367 | { XK_Prior, ShiftMask, "\033[5;2~", 0, 0}, 368 | { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, 369 | { XK_Next, ControlMask, "\033[6;5~", 0, 0}, 370 | { XK_Next, ShiftMask, "\033[6;2~", 0, 0}, 371 | { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0}, 372 | { XK_F1, XK_NO_MOD, "\033OP" , 0, 0}, 373 | { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0}, 374 | { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0}, 375 | { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0}, 376 | { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0}, 377 | { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0}, 378 | { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0}, 379 | { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0}, 380 | { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0}, 381 | { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0}, 382 | { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0}, 383 | { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0}, 384 | { XK_F3, XK_NO_MOD, "\033OR" , 0, 0}, 385 | { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0}, 386 | { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0}, 387 | { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0}, 388 | { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0}, 389 | { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0}, 390 | { XK_F4, XK_NO_MOD, "\033OS" , 0, 0}, 391 | { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0}, 392 | { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0}, 393 | { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0}, 394 | { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0}, 395 | { XK_F5, XK_NO_MOD, "\033[15~", 0, 0}, 396 | { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0}, 397 | { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0}, 398 | { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0}, 399 | { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0}, 400 | { XK_F6, XK_NO_MOD, "\033[17~", 0, 0}, 401 | { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0}, 402 | { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0}, 403 | { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0}, 404 | { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0}, 405 | { XK_F7, XK_NO_MOD, "\033[18~", 0, 0}, 406 | { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0}, 407 | { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0}, 408 | { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0}, 409 | { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0}, 410 | { XK_F8, XK_NO_MOD, "\033[19~", 0, 0}, 411 | { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0}, 412 | { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0}, 413 | { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0}, 414 | { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0}, 415 | { XK_F9, XK_NO_MOD, "\033[20~", 0, 0}, 416 | { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0}, 417 | { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0}, 418 | { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0}, 419 | { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0}, 420 | { XK_F10, XK_NO_MOD, "\033[21~", 0, 0}, 421 | { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0}, 422 | { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0}, 423 | { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0}, 424 | { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0}, 425 | { XK_F11, XK_NO_MOD, "\033[23~", 0, 0}, 426 | { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0}, 427 | { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0}, 428 | { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0}, 429 | { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0}, 430 | { XK_F12, XK_NO_MOD, "\033[24~", 0, 0}, 431 | { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0}, 432 | { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0}, 433 | { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0}, 434 | { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0}, 435 | { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0}, 436 | { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0}, 437 | { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0}, 438 | { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0}, 439 | { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0}, 440 | { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0}, 441 | { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0}, 442 | { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0}, 443 | { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0}, 444 | { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0}, 445 | { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0}, 446 | { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0}, 447 | { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0}, 448 | { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0}, 449 | { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0}, 450 | { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0}, 451 | { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0}, 452 | { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0}, 453 | { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0}, 454 | { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0}, 455 | { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0}, 456 | { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0}, 457 | { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0}, 458 | }; 459 | 460 | /* 461 | * Selection types' masks. 462 | * Use the same masks as usual. 463 | * Button1Mask is always unset, to make masks match between ButtonPress. 464 | * ButtonRelease and MotionNotify. 465 | * If no match is found, regular selection is used. 466 | */ 467 | static uint selmasks[] = { 468 | [SEL_RECTANGULAR] = Mod1Mask, 469 | }; 470 | 471 | /* 472 | * Printable characters in ASCII, used to estimate the advance width 473 | * of single wide characters. 474 | */ 475 | static char ascii_printable[] = 476 | " !\"#$%&'()*+,-./0123456789:;<=>?" 477 | "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" 478 | "`abcdefghijklmnopqrstuvwxyz{|}~"; 479 | --------------------------------------------------------------------------------