From 7d68c46feb845c572ef335f824062f90fdebf655 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Thu, 21 Mar 2019 19:38:55 +0100 Subject: [PATCH] kakoune: add module --- modules/misc/news.nix | 7 + modules/modules.nix | 1 + modules/programs/kakoune.nix | 574 +++++++++++++++++++++++++++++++++++ 3 files changed, 582 insertions(+) create mode 100644 modules/programs/kakoune.nix diff --git a/modules/misc/news.nix b/modules/misc/news.nix index 59f1726d..fce1eb68 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -1145,6 +1145,13 @@ in A new module is available: 'services.taskwarrior-sync'. ''; } + + { + time = "2019-07-17T20:05:29+00:00"; + message = '' + A new module is available: 'programs.kakoune'. + ''; + } ]; }; } diff --git a/modules/modules.nix b/modules/modules.nix index d5efe2d1..03e048e2 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -62,6 +62,7 @@ let (loadModule ./programs/info.nix { }) (loadModule ./programs/irssi.nix { }) (loadModule ./programs/jq.nix { }) + (loadModule ./programs/kakoune.nix { }) (loadModule ./programs/keychain.nix { }) (loadModule ./programs/lesspipe.nix { }) (loadModule ./programs/lsd.nix { }) diff --git a/modules/programs/kakoune.nix b/modules/programs/kakoune.nix new file mode 100644 index 00000000..5ac4a7b6 --- /dev/null +++ b/modules/programs/kakoune.nix @@ -0,0 +1,574 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.programs.kakoune; + + hook = types.submodule { + options = { + name = mkOption { + type = types.enum [ + "NormalBegin" "NormalIdle" "NormalEnd" "NormalKey" + "InsertBegin" "InsertIdle" "InsertEnd" "InsertKey" + "InsertChar" "InsertDelete" "InsertMove" "WinCreate" + "WinClose" "WinResize" "WinDisplay" "WinSetOption" + "BufSetOption" "BufNewFile" "BufOpenFile" "BufCreate" + "BufWritePre" "BufWritePost" "BufReload" "BufClose" + "BufOpenFifo" "BufReadFifo" "BufCloseFifo" "RuntimeError" + "ModeChange" "PromptIdle" "GlobalSetOption" "KakBegin" + "KakEnd" "FocusIn" "FocusOut" "RawKey" + "InsertCompletionShow" "InsertCompletionHide" + "InsertCompletionSelect" + ]; + example = "SetOption"; + description = '' + The name of the hook. For a description, see + . + ''; + }; + + once = mkOption { + type = types.bool; + default = false; + description = '' + Remove the hook after running it once. + ''; + }; + + group = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Add the hook to the named group. + ''; + }; + + option = mkOption { + type = types.nullOr types.str; + default = null; + example = "filetype=latex"; + description = '' + Additional option to pass to the hook. + ''; + }; + + commands = mkOption { + type = types.lines; + default = ""; + example = "set-option window indentwidth 2"; + description = '' + Commands to run when the hook is activated. + ''; + }; + }; + }; + + keyMapping = types.submodule { + options = { + mode = mkOption { + type = types.enum [ + "insert" + "normal" + "prompt" + "menu" + "user" + "goto" + "view" + "object" + ]; + example = "user"; + description = '' + The mode in which the mapping takes effect. + ''; + }; + + docstring = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Optional documentation text to display in info boxes. + ''; + }; + + key = mkOption { + type = types.str; + example = ""; + description = '' + The key to be mapped. See + + for possible values. + ''; + }; + + effect = mkOption { + type = types.str; + example = ":wq"; + description = '' + The sequence of keys to be mapped. + ''; + }; + }; + }; + + configModule = types.submodule { + options = { + colorScheme = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Set the color scheme. To see available schemes, enter + colorscheme at the kakoune prompt. + ''; + }; + + tabStop = mkOption { + type = types.nullOr types.ints.unsigned; + default = null; + description = '' + The width of a tab in spaces. The kakoune default is + 6. + ''; + }; + + indentWidth = mkOption { + type = types.nullOr types.ints.unsigned; + default = null; + description = '' + The width of an indentation in spaces. + The kakoune default is 4. + If 0, a tab will be used instead. + ''; + }; + + incrementalSearch = mkOption { + type = types.bool; + default = true; + description = '' + Execute a search as it is being typed. + ''; + }; + + alignWithTabs = mkOption { + type = types.bool; + default = false; + description = '' + Use tabs for the align command. + ''; + }; + + autoInfo = mkOption { + type = types.nullOr (types.listOf (types.enum [ "command" "onkey" "normal" ])); + default = null; + example = [ "command" "normal" ]; + description = '' + Contexts in which to display automatic information box. + The kakoune default is [ "command" "onkey" ]. + ''; + }; + + autoComplete = mkOption { + type = types.nullOr(types.listOf (types.enum [ "insert" "prompt" ])); + default = null; + description = '' + Modes in which to display possible completions. + The kakoune default is [ "insert" "prompt" ]. + ''; + }; + + autoReload = mkOption { + type = types.nullOr (types.enum [ "yes" "no" "ask" ]); + default = null; + description = '' + Reload buffers when an external modification is detected. + The kakoune default is "ask". + ''; + }; + + scrollOff = mkOption { + type = types.nullOr (types.submodule { + options = { + lines = mkOption { + type = types.ints.unsigned; + default = 0; + description = '' + The number of lines to keep visible around the cursor. + ''; + }; + + columns = mkOption { + type = types.ints.unsigned; + default = 0; + description = '' + The number of columns to keep visible around the cursor. + ''; + }; + }; + }); + default = null; + description = '' + How many lines and columns to keep visible around the cursor. + ''; + }; + + ui = mkOption { + type = types.nullOr (types.submodule { + options = { + setTitle = mkOption { + type = types.bool; + default = false; + description = '' + Change the title of the terminal emulator. + ''; + }; + + statusLine = mkOption { + type = types.enum [ "top" "bottom" ]; + default = "bottom"; + description = '' + Where to display the status line. + ''; + }; + + assistant = mkOption { + type = types.enum [ "clippy" "cat" "dilbert" "none" ]; + default = "clippy"; + description = '' + The assistant displayed in info boxes. + ''; + }; + + enableMouse = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable mouse support. + ''; + }; + + changeColors = mkOption { + type = types.bool; + default = true; + description = '' + Change color palette. + ''; + }; + + wheelDownButton = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Button to send for wheel down events. + ''; + }; + + wheelUpButton = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Button to send for wheel up events. + ''; + }; + + shiftFunctionKeys = mkOption { + type = types.nullOr types.ints.unsigned; + default = null; + description = '' + Amount by which shifted function keys are offset. That + is, if the terminal sends F13 for Shift-F1, this + should be 12. + ''; + }; + + useBuiltinKeyParser = mkOption { + type = types.bool; + default = false; + description = '' + Bypass ncurses key parser and use an internal one. + ''; + }; + }; + }); + default = null; + description = '' + Settings for the ncurses interface. + ''; + }; + + showMatching = mkOption { + type = types.bool; + default = false; + description = '' + Highlight the matching char of the character under the + selections' cursor using the MatchingChar + face. + ''; + }; + + wrapLines = mkOption { + type = types.nullOr (types.submodule { + options = { + enable = mkEnableOption "the wrap lines highlighter"; + + word = mkOption { + type = types.bool; + default = false; + description = '' + Wrap at word boundaries instead of codepoint boundaries. + ''; + }; + + indent = mkOption { + type = types.bool; + default = false; + description = '' + Preserve line indentation when wrapping. + ''; + }; + + maxWidth = mkOption { + type = types.nullOr types.ints.unsigned; + default = null; + description = '' + Wrap text at maxWidth, even if the window is wider. + ''; + }; + + marker = mkOption { + type = types.nullOr types.str; + default = null; + example = "⏎"; + description = '' + Prefix wrapped lines with marker text. + If not null, + the marker text will be displayed in the indentation if possible. + ''; + }; + }; + }); + default = null; + description = '' + Settings for the wrap lines highlighter. + ''; + }; + + numberLines = mkOption { + type = types.nullOr (types.submodule { + options = { + enable = mkEnableOption "the number lines highlighter"; + + relative = mkOption { + type = types.bool; + default = false; + description = '' + Show line numbers relative to the main cursor line. + ''; + }; + + highlightCursor = mkOption { + type = types.bool; + default = false; + description = '' + Highlight the cursor line with a separate face. + ''; + }; + + separator = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + String that separates the line number column from the + buffer contents. The kakoune default is + "|". + ''; + }; + }; + }); + default = null; + description = '' + Settings for the number lines highlighter. + ''; + }; + + showWhitespace = mkOption { + type = types.nullOr (types.submodule { + options = { + enable = mkEnableOption "the show whitespace highlighter"; + + lineFeed = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + The character to display for line feeds. + The kakoune default is "¬". + ''; + }; + + space = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + The character to display for spaces. + The kakoune default is "·". + ''; + }; + + nonBreakingSpace = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + The character to display for non-breaking spaces. + The kakoune default is "⍽". + ''; + }; + + tab = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + The character to display for tabs. + The kakoune default is "→". + ''; + }; + + tabStop = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + The character to append to tabs to reach the width of a tabstop. + The kakoune default is " ". + ''; + }; + }; + }); + default = null; + description = '' + Settings for the show whitespaces highlighter. + ''; + }; + + keyMappings = mkOption { + type = types.listOf keyMapping; + default = []; + description = '' + User-defined key mappings. For documentation, see + + ''; + }; + + hooks = mkOption { + type = types.listOf hook; + default = []; + description = '' + Global hooks. For documentation, see + . + ''; + }; + }; + }; + + configFile = + let + wrapOptions = with cfg.config.wrapLines; concatStrings [ + "${optionalString word " -word"}" + "${optionalString indent " -indent"}" + "${optionalString (marker != null) " -marker ${marker}"}" + "${optionalString (maxWidth != null) " -width ${toString maxWidth}"}" + ]; + + numberLinesOptions = with cfg.config.numberLines; concatStrings [ + "${optionalString relative " -relative "}" + "${optionalString highlightCursor " -hlcursor"}" + "${optionalString (separator != null) " -separator ${separator}"}" + ]; + + uiOptions = with cfg.config.ui; concatStringsSep " " [ + "ncurses_set_title=${if setTitle then "true" else "false"}" + "ncurses_status_on_top=${if (statusLine == "top") then "true" else "false"}" + "ncurses_assistant=${assistant}" + "ncurses_enable_mouse=${if enableMouse then "true" else "false"}" + "ncurses_change_colors=${if changeColors then "true" else "false"}" + "${optionalString (wheelDownButton != null) + "ncurses_wheel_down_button=${wheelDownButton}"}" + "${optionalString (wheelUpButton != null) + "ncurses_wheel_up_button=${wheelUpButton}"}" + "${optionalString (shiftFunctionKeys != null) + "ncurses_shift_function_key=${toString shiftFunctionKeys}"}" + "ncurses_builtin_key_parser=${if useBuiltinKeyParser then "true" else "false"}" + ]; + + keyMappingString = km: concatStringsSep " " [ + "map global" + "${km.mode} ${km.key} '${km.effect}'" + "${optionalString (km.docstring != null) "-docstring '${km.docstring}'"}" + ]; + + hookString = h: concatStringsSep " " [ + "hook" "${optionalString (h.group != null) "-group ${group}"}" + "${optionalString (h.once) "-once"}" "global" + "${h.name}" "${optionalString (h.option != null) h.option}" + "%{ ${h.commands} }" + ]; + + cfgStr = with cfg.config; concatStringsSep "\n" ( + [ "# Generated by home-manager" ] + ++ optional (colorScheme != null) "colorscheme ${colorScheme}" + ++ optional (tabStop != null) "set-option global tabstop ${toString tabStop}" + ++ optional (indentWidth != null) "set-option global indentwidth ${toString indentWidth}" + ++ optional (!incrementalSearch) "set-option global incsearch false" + ++ optional (alignWithTabs) "set-option global aligntab true" + ++ optional (autoInfo != null) "set-option global autoinfo ${concatStringsSep "|" autoInfo}" + ++ optional (autoComplete != null) "set-option global autocomplete ${concatStringsSep "|" autoComplete}" + ++ optional (autoReload != null) "set-option global/ autoreload ${autoReload}" + ++ optional (wrapLines != null && wrapLines.enable) "add-highlighter global/ wrap${wrapOptions}" + ++ optional (numberLines != null && numberLines.enable) + "add-highlighter global/ number-lines${numberLinesOptions}" + ++ optional showMatching "add-highlighter global/ show-matching" + ++ optional (scrollOff != null) + "set-option global scrolloff ${toString scrollOff.lines},${toString scrollOff.columns}" + + ++ [ "# UI options" ] + ++ optional (ui != null) "set-option global ui_options ${uiOptions}" + + ++ [ "# Key mappings" ] + ++ map keyMappingString keyMappings + + ++ [ "# Hooks" ] + ++ map hookString hooks + ); + in + pkgs.writeText "kakrc" ( + optionalString (cfg.config != null) cfgStr + + cfg.extraConfig + ); + +in + +{ + options = { + programs.kakoune = { + enable = mkEnableOption "the kakoune text editor"; + + config = mkOption { + type = types.nullOr configModule; + default = {}; + description = "kakoune configuration options."; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra configuration lines to add to + ~/.config/kak/kakrc. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + home.packages = [ pkgs.kakoune ]; + xdg.configFile."kak/kakrc".source = configFile; + }; +}