From d41cff489f6d8ad326abcb2ccb53d716690b2c16 Mon Sep 17 00:00:00 2001 From: iyefrat Date: Fri, 22 Apr 2022 01:21:32 +0300 Subject: [PATCH] module: add :input bidi * module: add :input bidi Co-authored-by: Yoav Marco * docs(bidi): flesh out README.org Co-authored-by: Itai Y. Efrat * feat(bidi): add +bidi-global-mode * docs(bidi): improve font setting instructions * feat(bidi): add +bidi-(hebrew|arabic)-font Since the Hebrew and Arabic unicode blocks cover the vast majority of RTL languages used today, we provide these fonts so end users don't have to bother with setting up the hooks themselves. * feat(bidi): add smart fontify Adds support for using the bidi fonts on surrounding whitespace and punctuation through. On by default, customizable through +bidi-want-smart-fontify and +bidi-smart-fontify-keywords. Also adds face versions of the bidi fonts. * docs(bidi): recommend known good nastaliq fonts * fix(bidi): re-set bidi faces after changing fonts * feat(bidi): add +bidi-paragraph-direction This allows users to choose what bidi-paragraph-direction is set to when +bidi-mode is on, so they can choose if they want per paragraph alignment (the default) or to force everything to be aligned RTL * docs(bidi): conform to verbatim/code conventions * docs(bidi): add font overview to Features * docs(bidi): warn on rtl forced alignment footgun +bidi-paragraph-direction is a nice variable to have if you primarily use +bidi-mode for rtl text buffers, but it shouldn't be used in conjunction with +bidi-global-mode since it messes up English buffers. Co-authored-by: Yoav Marco --- docs/modules.org | 1 + init.example.el | 1 + modules/input/bidi/README.org | 156 ++++++++++++++++++++++++++++++++++ modules/input/bidi/config.el | 93 ++++++++++++++++++++ 4 files changed, 251 insertions(+) create mode 100644 modules/input/bidi/README.org create mode 100644 modules/input/bidi/config.el diff --git a/docs/modules.org b/docs/modules.org index 33b2bdbf4..1a6a70372 100644 --- a/docs/modules.org +++ b/docs/modules.org @@ -89,6 +89,7 @@ Modules that reconfigure or augment packages or features built into Emacs. + wanderlust =+gmail= - TODO * :input ++ [[file:../modules/input/bidi/README.org][bidi]] - (tfel ot) thgir etirw uoy gnipleh + [[file:../modules/input/chinese/README.org][chinese]] - TODO + [[file:../modules/input/japanese/README.org][japanese]] - TODO + [[file:../modules/input/layout/README.org][layout]] =+azerty +bepo= - TODO diff --git a/init.example.el b/init.example.el index 2fe2b108b..07bcfaa6e 100644 --- a/init.example.el +++ b/init.example.el @@ -15,6 +15,7 @@ ;; directory (for easy access to its source code). (doom! :input + ;;bidi ; (tfel ot) thgir etirw uoy gnipleh ;;chinese ;;japanese ;;layout ; auie,ctsrnm is the superior home row diff --git a/modules/input/bidi/README.org b/modules/input/bidi/README.org new file mode 100644 index 000000000..5f801da2e --- /dev/null +++ b/modules/input/bidi/README.org @@ -0,0 +1,156 @@ +#+TITLE: input/bidi +#+DATE: September 28, 2021 +#+SINCE: v3.0.0 +#+STARTUP: inlineimages nofold + +* Table of Contents :TOC_3:noexport: +- [[#description][Description]] + - [[#maintainers][Maintainers]] + - [[#module-flags][Module Flags]] + - [[#plugins][Plugins]] +- [[#prerequisites][Prerequisites]] +- [[#features][Features]] +- [[#configuration][Configuration]] + - [[#using-bidi-mode][Using ~+bidi-mode~]] + - [[#force-rtl-text-alignment][Force RTL text alignment]] + - [[#input-methods][Input Methods]] + - [[#fonts][Fonts]] + - [[#smart-fontify][Smart Fontify]] + - [[#change-dictionary-language-on-bidi-buffers][Change Dictionary Language On Bidi Buffers]] + - [[#automatic-input-mode-switching][Automatic input mode switching]] +- [[#troubleshooting][Troubleshooting]] + - [[#nastaliq-font-display-bug][Nastaliq font display bug]] + +* Description + +This module improves support for bidi (bidirectional text). It should be enabled +if you regularly write in languages that write right-to-left. It also provides +some added configuration instructions in the README, since a lot of it is user +specific. + +** Maintainers ++ [[https://github.com/iyefrat][@iyefrat]] ++ [[https://github.com/ymarco][@ymarco]] + +** Module Flags +This module provides no flags. + +** Plugins +This module provides no plugins. + +* Prerequisites +This module has no prerequisites. + +* Features +This module provides ~+bidi-mode~, a minor mode that improves the display of RTL +text by right-aligning lines that start with an RTL language, on a per-line +basis. Since exact use cases vary, turning on this mode is left to the user. + +It also provides easy font configuration for Hebrew and Arabic-derived scripts +(Arabic, Persian, Urdu, etc.) in ~+bidi-hebrew-font~ and ~+bidi-arabic-font~. +See [[Fonts]] for more information. If you use an RTL language that isn't covered by +these characters, open an issue requesting support for it. + +* Configuration +** Using ~+bidi-mode~ +~+bidi-mode~ is a local minor mode, meaning it has to be turned on a per-buffer +basis. + +If you want to have it on for all buffers, use ~+bidi-global-mode~: + +#+begin_src emacs-lisp +;; ~/.doom.d/config.el +(+bidi-global-mode 1) +#+end_src + +If you only need it for specific purposes, e.g. editing LaTeX +documents, you probably want to enable it through a hook: + +#+begin_src emacs-lisp +(add-hook 'TeX-mode-hook #'+bidi-mode) +#+end_src + +This is also useful for adding specific functionality for when ~+bidi-mode~ is on. + +** Force RTL text alignment +By default, ~+bidi-mode~ will align paragraphs by the first character with +strong directionality. If you want to force all paragraphs to be aligned +right-to-left when ~+bidi-mode~ is on, add the following to your config: + +#+begin_src emacs-lisp +(setq +bidi-paragraph-direction 'right-to-left) +#+end_src + +*Warning:* do not do this if you are using ~+bidi-global-mode~, it will mess up +all of the buffers in Emacs that use English, including things like the =M-x= buffer. + +** Input Methods +If you need bidi support, it's likely that you want to easily switch between +English and your favorite RTL language. In order to be able to do this without +losing access to all of the keybindings require English letters, you should use +[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Input-Methods.html][input methods]] to switch languages instead of changing the system keyboard +language. If you use a non-qwerty layout, you will need extra configuration to +keep the input method consistent, see [[https://github.com/ymarco/doom-emacs-config/blob/2d655adb6a35c5cd3afcba24e76327f5444cf774/dvorak-config.el#L3-L18][here]] for an example for dvorak. + +Toggling the input method bound to =C-\=. It prompts you to choose an input +method the first time you do this in a session, but you bypass this by setting +the default input method: + +#+begin_src emacs-lisp +(setq default-input-method "hebrew") +#+end_src + +** Fonts +Many good English fonts do not have great coverage for RTL languages, especially +for Hebrew and monospace fonts. To this end, we provide ~+bidi-hebrew-font~ and +~+bidi-arabic-font~ as an easy way to override the default fonts but only for +Hebrew and Arabic characters. They are set by default to =DejaVu Sans=, since +it has pretty decent looking Hebrew and Arabic characters. + +Note, that if you are writing in an Arabic-derived script, such as Persian, +Urdu, or Pashto, you may want to change ~+bidi-arabic-font~ to one specific to +your language, especially if you want your script to be written in the Nastaliq +style. + +If you use an RTL language the script of which isn't covered by the =hebrew= or +=arabic= unicode blocks, you can set a font override manually. For example: + +#+begin_src emacs-lisp +(add-hook 'after-setting-font-hook + (lambda () (set-fontset-font t 'syriac (font-spec :family "DejaVu Sans")))) +#+end_src + +Make sure to use the correct unicode block name, see the documentation of +~set-fontset-font~ for more details. + +*** Smart Fontify +Since good bidi fonts are often not monospace (as is the default =DejaVu Sans=), +It usually looks better to have the surrounding spaces and punctuation in the +use the bidi font as well. This is the default behaviour, but you can turn this +off by setting: + +#+begin_src emacs-lisp +(setq +bidi-want-smart-fontify nil) +#+end_src + +** Change Dictionary Language On Bidi Buffers +If you are only using ~+bidi-mode~ in specific buffers, you might want to +automatically change the dictionary language there. For example: + +#+begin_src emacs-lisp +(add-hook! '+bidi-mode-hook + (if +bidi-mode + (ispell-change-dictionary "hebrew") + (ispell-change-dictionary "default"))) +#+end_src + +** Automatic input mode switching +You may want to Emacs to try and guess when you want it to switch input methods. +See [[https://github.com/ymarco/doom-emacs-config/blob/2d655adb6a35c5cd3afcba24e76327f5444cf774/hebrew-latex-config.el#L7-L21][here]] and [[https://github.com/ymarco/doom-emacs-config/blob/2d655adb6a35c5cd3afcba24e76327f5444cf774/hebrew-latex-config.el#L99-L102][here]] for an example of how to get Emacs to switch to hebrew when +entering insert mode after a hebrew character, in LaTeX buffers. + +* Troubleshooting + +** Nastaliq font display bug +If Emacs is having trouble properly displaying a Nastaliq font, try using one of +[[https://urdufonts.net/fonts/jameel-noori-nastaleeq-regular][these]] [[https://urdufonts.net/fonts/alvi-nastaleeq-regular][two]] fonts for ~+bidi-arabic-font~. diff --git a/modules/input/bidi/config.el b/modules/input/bidi/config.el new file mode 100644 index 000000000..1b91819a2 --- /dev/null +++ b/modules/input/bidi/config.el @@ -0,0 +1,93 @@ +;;; input/bidi/config.el -*- lexical-binding: t; -*- + +(defvar +bidi-mode-map (make-sparse-keymap) + "Keymap for `+bidi-mode'.") + +(defvar +bidi-hebrew-font (font-spec :family "DejaVu Sans") + "Overriding font for hebrew script. +Must be a `font-spec', see `doom-font' for examples. + +WARNING: if you specify a size for this font it will hard-lock any usage of this +font to that size. It's rarely a good idea to do so!") + +(defface +bidi-hebrew-face `((t :font ,+bidi-hebrew-font)) "") + +(defvar +bidi-arabic-font (font-spec :family "DejaVu Sans") + "Overriding font for arabic and arabic-derived scripts. +Must be a `font-spec', see `doom-font' for examples. + +WARNING: if you specify a size for this font it will hard-lock any usage of this +font to that size. It's rarely a good idea to do so!") + +(defface +bidi-arabic-face `((t :font ,+bidi-arabic-font)) "") + +(defcustom +bidi-want-smart-fontify t + "Use bidi override fonts on surrounding space and punctuation as well. +Add `+bidi-smart-fontify-keywords' to `font-lock-keywords' on editable buffers +when `+bidi-mode' is on." + :type 'boolean) + +(defvar +bidi-smart-fontify-keywords + `((,(rx (any (#x0590 . #x05FF)) ; Hebrew + (group (one-or-more (any " " punctuation)))) + (1 '+bidi-hebrew-face t)) + (,(rx (or (any (#x0600 . #x06FF)) ; Arabic + (any (#x0750 . #x077F)) ; Arabic Supplement + (any (#x0870 . #x089F)) ; Arabic Extended-B + (any (#x08A0 . #x08FF))) ; Arabic Extended-A + (group (one-or-more (any " " punctuation)))) + (1 '+bidi-arabic-face t))) + + "`font-lock' keywords matching spaces and punctuation after RTL characters. +See the variable `font-lock-keywords' for information on the format.") + +(defcustom +bidi-paragraph-direction nil + "The value of `bidi-paragragh-direction' when `+bidi-mode' is on. +See the `bidi-paragraph-direction' for more info. + +Warning: do not change this if you are using `+bidi-global-mode'.'" + :type '(choice + (const :tag "Left to Right" left-to-right) + (const :tag "Right to Left" right-to-left) + (const :tag "Dynamic, according to paragraph text" nil))) + +;;;###autoload +(define-minor-mode +bidi-mode + "Minor mode for using bidirectional text in a buffer. + +Note that the whole buffer doesn't have to contain any +bidirectional text at all, this mode just makes bidi editing +easier." + :keymap +bidi-mode-map + (if +bidi-mode + (progn + (setq bidi-paragraph-direction +bidi-paragraph-direction ; Better paragraph alignment + bidi-paragraph-separate-re "^" ; No need for empty lines to switch alignment + bidi-paragraph-start-re "^" ; ^ + bidi-inhibit-bpa nil) ; Better bidi paren logic + (when (and +bidi-want-smart-fontify + (not buffer-read-only)) + (font-lock-add-keywords + nil + +bidi-smart-fontify-keywords + 'append) + (font-lock-flush))) + (setq bidi-paragraph-direction 'left-to-right + bidi-paragraph-separate-re nil + bidi-paragraph-start-re nil + bidi-inhibit-bpa t) + (when (and +bidi-want-smart-fontify + (not buffer-read-only)) + (font-lock-remove-keywords + nil + +bidi-smart-fontify-keywords) + (font-lock-flush)))) + +(define-globalized-minor-mode +bidi-global-mode +bidi-mode +bidi-mode) + +(add-hook! 'after-setting-font-hook + (defun +bidi-set-fonts-h () + (set-fontset-font t 'hebrew +bidi-hebrew-font) + (set-fontset-font t 'arabic +bidi-arabic-font) + (set-face-font '+bidi-arabic-face +bidi-arabic-font) + (set-face-font '+bidi-hebrew-face +bidi-hebrew-font)))