├── LICENSE ├── README.md └── focus.kak /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Cem Aksoylar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kakoune-focus 2 | `kakoune-focus` is a plugin to let you work on multiple selections more efficiently by hiding lines that are far from your selections using Kakoune's `replace-ranges` highlighter (`:doc highlighters specs-highlighters`). 3 | 4 | > **Note** 5 | > This plugin requires [Kakoune release 2022.10.31](https://github.com/mawww/kakoune/releases/tag/v2022.10.31) or a revision after the breaking change at [mawww/kakoune@ef8a11b](https://github.com/mawww/kakoune/commit/ef8a11b3dbefb8a1222974a8c34e15fa006d56e0). 6 | 7 | ![demo](https://caksoylar.github.io/kakoune-focus/focus.gif) 8 | 9 | ## Installation 10 | You can copy `focus.kak` to your `autoload` folder, e.g. into `~/.config/kak/autoload`. 11 | 12 | If you are using [plug.kak](https://github.com/andreyorst/plug.kak): 13 | ```kak 14 | plug "caksoylar/kakoune-focus" config %{ 15 | # configuration here 16 | } 17 | ``` 18 | 19 | ## Usage 20 | Once you have the (ideally multiple) selections you want to focus on, use `focus-selections` to hide the surrounding lines. You can use `focus-clear` to disable this or use `focus-toggle` to toggle it on and off. 21 | 22 | I recommend assigning a mapping for easy access, for example `,` to toggle: 23 | ```kak 24 | map global user ': focus-toggle' -docstring "toggle selections focus" 25 | ``` 26 | 27 | You can also extend the focus area to include your current selections using `focus-extend`, which can be called multiple times. Using this feature you can even create a live-updating focus area that extends itself to lines you have visited. For example you can define and use commands like below: 28 | ```kak 29 | define-command focus-live-enable %{ 30 | focus-selections 31 | hook -group focus window NormalIdle .* %{ focus-extend } 32 | } 33 | define-command focus-live-disable %{ 34 | remove-hooks window focus 35 | focus-clear 36 | } 37 | ``` 38 | 39 | ## Configuration 40 | There are a couple of options you can configure: 41 | - `focus_separator (str)`: What string to use as the separator to replace hidden lines, can use markup strings `:doc faces markup-strings` 42 | - `focus_context_lines (int)`: How many lines of context to preserve above and below selections (default: 1) 43 | 44 | ## Caveats 45 | Due to [a Kakoune shortcoming](https://github.com/mawww/kakoune/issues/3644) with the `replace-ranges` highlighter, some lines can be visually cut off from the bottom after focusing. This seems to be an issue especially when long spans of lines are hidden and soft line wrapping is enabled with the `wrap` highlighter. 46 | 47 | ## License 48 | MIT 49 | -------------------------------------------------------------------------------- /focus.kak: -------------------------------------------------------------------------------- 1 | declare-option str focus_separator "{Whitespace}────────────────────────────────────────────────────────────────────────────────" 2 | declare-option int focus_context_lines 1 3 | declare-option -hidden range-specs focus_hidden_lines 4 | declare-option -hidden str-list focus_selections 5 | declare-option -hidden bool focus_enabled false 6 | 7 | define-command focus-selections -docstring "Focus on selections" %{ 8 | # save selections with timestamp using a temporary mark register 9 | evaluate-commands -save-regs f %{ 10 | execute-keys <">fZ 11 | set-option window focus_selections %reg{f} 12 | } 13 | 14 | set-option window focus_hidden_lines 15 | evaluate-commands -draft %{ 16 | try %{ 17 | evaluate-commands %sh{ [ "$kak_opt_focus_context_lines" -gt 0 ] || echo fail } 18 | execute-keys %opt{focus_context_lines} J 19 | execute-keys %opt{focus_context_lines} K 20 | } 21 | try %{ invert-lines } catch %{ fail "focus: All lines selected, cannot focus" } 22 | 23 | # remove single EOL and end of selection EOL 24 | execute-keys \A\n\z H 25 | 26 | # remove single line selections 27 | execute-keys \n 28 | 29 | set-option window focus_hidden_lines %val{timestamp} "%val{selection_desc}|%opt{focus_separator}" 30 | try %{ 31 | execute-keys 32 | evaluate-commands -itersel %{ 33 | set-option -add window focus_hidden_lines "%val{selection_desc}|%opt{focus_separator}" 34 | } 35 | } 36 | 37 | try %{ add-highlighter window/focus-hidden replace-ranges focus_hidden_lines } 38 | } 39 | echo -markup "{Information}focus: Focused selections" 40 | set-option window focus_enabled true 41 | } 42 | 43 | define-command focus-extend -docstring "Extend focus area with current selections" %{ 44 | evaluate-commands -draft -save-regs cp %{ 45 | # restore previous selections through a temporary mark register and append current ones 46 | execute-keys <">cZ 47 | try %{ 48 | set-register p %opt{focus_selections} 49 | execute-keys <">pz 50 | execute-keys <">ca 51 | } 52 | 53 | focus-selections 54 | } 55 | } 56 | 57 | define-command focus-clear -docstring "Clear selection focus" %{ 58 | set-option window focus_selections 59 | remove-highlighter window/focus-hidden 60 | echo -markup "{Information}focus: Cleared focus" 61 | set-option window focus_enabled false 62 | } 63 | 64 | define-command focus-toggle -docstring "Toggle selection focus" %{ 65 | evaluate-commands %sh{ [ "$kak_opt_focus_enabled" = "true" ] && echo "focus-clear" || echo "focus-selections" } 66 | } 67 | 68 | define-command -hidden invert-lines %{ 69 | execute-keys x 70 | 71 | # sort selections by descriptors 72 | evaluate-commands %sh{ 73 | printf "select " 74 | printf "%s\n" "$kak_selections_desc" | tr ' ' '\n' | sort -n -t. | tr '\n' ' ' 75 | } 76 | 77 | # select line intervals outside selections 78 | evaluate-commands %sh{ 79 | printf 'select' 80 | eval "set -- $kak_quoted_selections_desc" 81 | i=1 82 | start=${1%%.*}; end=${1#*,}; end=${end%.*} 83 | shift 84 | while [ $i -le "$kak_buf_line_count" ]; do 85 | if [ $i -lt "$start" ]; then # not yet at next selection, select until its beginning 86 | printf ' %s.1,%s.1' $i $(( start - 1 )) 87 | i=$start 88 | else # encountered a selection, skip to its end 89 | i=$(( end + 1 )) 90 | if [ $# -gt 0 ]; then 91 | start=${1%%.*}; end=${1#*,}; end=${end%.*} 92 | shift 93 | else # all selections done, select until end of buffer 94 | start=$(( kak_buf_line_count + 1 )) 95 | fi 96 | fi 97 | done 98 | } 99 | execute-keys x 100 | } 101 | 102 | alias global focus-enable focus-selections 103 | alias global focus-disable focus-clear 104 | --------------------------------------------------------------------------------