From 6381a5c0ae9f3dd639b09636d80f950e7ba92ba1 Mon Sep 17 00:00:00 2001 From: Andrew Whatson Date: Mon, 26 Aug 2019 00:53:18 +1000 Subject: [PATCH] Add :editor word-wrap module Defines a new minor-mode `+word-wrap-mode` which configures adaptive-wrap-prefix-mode and visual-line-mode for smart soft-wrapping of code. Evil users can toggle it with `SPC t w`. Enable globally with `+global-word-wrap-mode`. See the README for more details! --- init.example.el | 1 + modules/config/default/+evil-bindings.el | 1 + modules/editor/word-wrap/README.org | 73 +++++++++++++++++++++++ modules/editor/word-wrap/autoload.el | 76 ++++++++++++++++++++++++ modules/editor/word-wrap/config.el | 15 +++++ modules/editor/word-wrap/packages.el | 4 ++ 6 files changed, 170 insertions(+) create mode 100644 modules/editor/word-wrap/README.org create mode 100644 modules/editor/word-wrap/autoload.el create mode 100644 modules/editor/word-wrap/config.el create mode 100644 modules/editor/word-wrap/packages.el diff --git a/init.example.el b/init.example.el index ed527734f..fec33a81c 100644 --- a/init.example.el +++ b/init.example.el @@ -54,6 +54,7 @@ ;;parinfer ; turn lisp into python, sort of rotate-text ; cycle region at point between text candidates snippets ; my elves. They type so I don't have to + ;;word-wrap ; soft wrapping with language-aware indent :emacs dired ; making dired pretty [functional] diff --git a/modules/config/default/+evil-bindings.el b/modules/config/default/+evil-bindings.el index edd4d3a87..569938ab4 100644 --- a/modules/config/default/+evil-bindings.el +++ b/modules/config/default/+evil-bindings.el @@ -824,6 +824,7 @@ :desc "Indent guides" "i" #'highlight-indent-guides-mode :desc "Indent style" "I" #'doom/toggle-indent-style :desc "Line numbers" "l" #'doom/toggle-line-numbers + :desc "Word-wrap mode" "w" #'+word-wrap-mode :desc "org-tree-slide mode" "p" #'+org-present/start :desc "Flyspell" "s" #'flyspell-mode)) diff --git a/modules/editor/word-wrap/README.org b/modules/editor/word-wrap/README.org new file mode 100644 index 000000000..2b6f37187 --- /dev/null +++ b/modules/editor/word-wrap/README.org @@ -0,0 +1,73 @@ +#+TITLE: editor/word-wrap +#+DATE: August 26, 2019 +#+SINCE: v2.1 + +* Table of Contents :TOC_3:noexport: +- [[#description][Description]] + - [[#module-flags][Module Flags]] + - [[#plugins][Plugins]] +- [[#configuration][Configuration]] + +* Description +This module adds a minor-mode ~+word-wrap-mode~, which intelligently wraps long +lines in the buffer without modifying the buffer content. + +Wrapped lines will be indented to match the preceding line. Lines which are not +inside a comment will have extra indentation as determined by +~+word-wrap-extra-indent~. The default is to increase the indent by twice the +major-mode indent. + +The ~+word-wrap-extra-indent~ variable supports the following values: +- ~double~: indent by twice the major-mode indentation +- ~single~: indent by the major-mode indentation +- a positive integer: indent by this fixed amount +- a negative integer: dedent by this fixed amount +- ~nil~: no extra indent + +This module also includes a global minor-mode ~+global-word-wrap-mode~ to +automatically enable wrapping in most buffers. Wrapping will not be enabled in +buffers whose major mode is marked "special", or are listed in +~+word-wrap-disabled-modes~. + +** Module Flags +This module provides no flags. + +** Plugins ++ [[https://elpa.gnu.org/packages/adaptive-wrap.html][adaptive-wrap]] + +* Configuration +Word wrapping is not enabled by default. + +Wrapping can be toggled in the current buffer with ~M-x +word-wrap-mode~. The +default doom bindings bind this to ~SPC t w~ for ~evil~ users. + +To enable wrapping in a specific mode, add it to the appropriate hook in your +~config.el~: + +#+BEGIN_SRC emacs-lisp +;; enable word-wrap in C/C++/ObjC/Java +(add-hook 'c-mode-common-hook #'+word-wrap-mode) +#+END_SRC + +To customize the extra indent for a specific mode: + +#+BEGIN_SRC emacs-lisp +;; enable word-wrap with fixed extra 2 spaces in org-mode +(add-hook! 'org-mode-hook + (setq-local +word-wrap-extra-indent 2) + (+word-wrap-mode +1)) +#+END_SRC + +To turn on word wrapping (almost) everywhere: + +#+BEGIN_SRC emacs-lisp +;; enable word-wrap (almost) everywhere +(+global-word-wrap-mode +1) +#+END_SRC + +To disable global word-wrapping in a specific mode: + +#+BEGIN_SRC emacs-lisp +;; disable global word-wrap in emacs-lisp-mode +(add-to-list '+word-wrap-disabled-modes 'emacs-lisp-mode) +#+END_SRC diff --git a/modules/editor/word-wrap/autoload.el b/modules/editor/word-wrap/autoload.el new file mode 100644 index 000000000..f024dd6a0 --- /dev/null +++ b/modules/editor/word-wrap/autoload.el @@ -0,0 +1,76 @@ +;;; editor/word-wrap/autoload.el -*- lexical-binding: t; -*- + +(defvar +word-wrap--prev-adaptive-wrap-mode nil) +(defvar +word-wrap--prev-visual-line-mode nil) +(defvar +word-wrap--major-mode-indent-var nil) + +(defun +word-wrap--adjust-extra-indent-a (orig-fn beg end) + "Contextually adjust extra word-wrap indentation." + (let ((adaptive-wrap-extra-indent (+word-wrap--calc-extra-indent beg))) + (funcall orig-fn beg end))) + +(defun +word-wrap--calc-extra-indent (p) + "Calculate extra word-wrap indentation at point." + (if (not (sp-point-in-comment p)) + (pcase +word-wrap-extra-indent + ('double + (* 2 (symbol-value +word-wrap--major-mode-indent-var))) + ('single + (symbol-value +word-wrap--major-mode-indent-var)) + ((and (pred integerp) fixed) + fixed) + (_ 0)) + 0)) + +;;;###autoload +(define-minor-mode +word-wrap-mode + "Wrap long lines in the buffer with language-aware indentation. + +This mode configures `adaptive-wrap' and `visual-line-mode' to wrap long lines +without modifying the buffer content. This is useful when dealing with legacy +code which contains gratuitously long lines, or running emacs on your +wrist-phone. + +Wrapped lines will be indented to match the preceding line. Lines which are not +inside a comment will have additional indentation according to the configuration +of `+word-wrap-extra-indent'." + :init-value nil + (if +word-wrap-mode + (progn + (require 'adaptive-wrap) + (require 'dtrt-indent) ; for dtrt-indent--search-hook-mapping + (require 'smartparens) ; for sp-point-in-string-or-comment + + (setq-local +word-wrap--prev-adaptive-wrap-mode adaptive-wrap-prefix-mode) + (setq-local +word-wrap--prev-visual-line-mode visual-line-mode) + (setq-local +word-wrap--major-mode-indent-var + (caddr (dtrt-indent--search-hook-mapping major-mode))) + + (advice-add #'adaptive-wrap-fill-context-prefix :around #'+word-wrap--adjust-extra-indent-a) + + (unless +word-wrap--prev-adaptive-wrap-mode + (adaptive-wrap-prefix-mode +1)) + (unless +word-wrap--prev-visual-line-mode + (visual-line-mode +1))) + + ;; disable +word-wrap-mode + (advice-remove #'adaptive-wrap-fill-context-prefix #'+word-wrap--adjust-extra-indent-a) + + (unless +word-wrap--prev-adaptive-wrap-mode + (adaptive-wrap-prefix-mode -1)) + (unless +word-wrap--prev-visual-line-mode + (visual-line-mode -1)))) + +(defun +word-wrap--enable-global-mode () + "Enable `+word-wrap-mode' for `+word-wrap-global-mode'. + +Wrapping will be automatically enabled in all modes except special modes, or +modes explicitly listed in `+word-wrap-disabled-modes'." + (unless (or (eq (get major-mode 'mode-class) 'special) + (memq major-mode +word-wrap-disabled-modes)) + (+word-wrap-mode +1))) + +;;;###autoload +(define-globalized-minor-mode +global-word-wrap-mode + +word-wrap-mode + +word-wrap--enable-global-mode) diff --git a/modules/editor/word-wrap/config.el b/modules/editor/word-wrap/config.el new file mode 100644 index 000000000..f45faa88b --- /dev/null +++ b/modules/editor/word-wrap/config.el @@ -0,0 +1,15 @@ +;;; editor/word-wrap/config.el -*- lexical-binding: t; -*- + +(defvar +word-wrap-extra-indent 'double + "The amount of extra indentation for wrapped non-comment lines. + +When 'double, indent by twice the major-mode indentation. +When 'single, indent by the major-mode indentation. +When a positive integer, indent by this fixed amount. +When a negative integer, dedent by this fixed amount. +Otherwise no extra indentation will be used.") + +(defvar +word-wrap-disabled-modes + '(fundamental-mode so-long-mode) + "Major-modes where `+global-word-wrap-mode' should not enable + `+word-wrap-mode'.") diff --git a/modules/editor/word-wrap/packages.el b/modules/editor/word-wrap/packages.el new file mode 100644 index 000000000..85d7b2c55 --- /dev/null +++ b/modules/editor/word-wrap/packages.el @@ -0,0 +1,4 @@ +;; -*- no-byte-compile: t; -*- +;;; editor/word-wrap/packages.el + +(package! adaptive-wrap)