emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Ligatures


From: Tassilo Horn
Subject: Re: Ligatures
Date: Tue, 19 May 2020 17:36:44 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

Eli Zaretskii <address@hidden> writes:

>> > it be very common to deconstruct such ligatures, like → into ->?
>> > 
>> > No, I don't think so.  Why would this be common?
>> 
>> I thought it would be the default. Emacs shows →, and you can put the
>> point either before (|→), in the middle (-|>), or after (→|).
>
> Doesn't sound as a useful default to me.  It could be an optional
> feature, though.

To me it sounds like a good default.

>> Here's a fairly common case: when writing html or XML, you may type
>> <, then >, then press C-b and type the tag name; or you may use < and
>> a paredit-like setup that inserts the > automatically.  If the font
>> has a ligature for <> and you can't put the point in the middle, this
>> breaks.  Same for || — the notation |x| { … } is used for lambdas in
>> some languages; if you type || then try to move the point back inside
>> the composed || glyph it won't work.
>
> Sounds like a bug or misfeature that needs a solution, not necessarily
> the one that's been proposed here.  For example, how about a special
> insert command that would disable ligation with the character it
> inserts?

I use the attached self-written ligature.el (Eli, you've helped me with
that some months back).  That's all nice but sometimes I too have the
problem that I want to edit the name of a "private" function/variable
foo--do-stuff and cannot move point inside the double-dash because it is
composed as one char.  As a little cure, I disable ligatures in the
minibuffer where I absolutely need to do completion stuff like
foo-<TAB>-bar.

Another case is where when inserting < automatically inserts >
immediately giving a <> diamond where I cannot move into.

A special insert command will not help here because it is already
inserted.

Bye,
Tassilo
(defgroup ligature nil
  "Support for font ligatures"
  :version "28.1"
  :prefix "ligature-")

(defcustom ligature-arrows
  (list "-->" "<!--" "->>" "<<-" "->" "<-"
        "<-<" ">>-" ">-" "<~>" "-<" "-<<"
        "<=>" "=>" "<=<" "<<=" "<==" "<==>" "==>" "=>>" ">=>" ">>="
        "<-|" "<=|"  "|=>" "|->" "<~~" "<~"  "~~>"
        "~>" "<->")
  "Arrow ligatures."
  :type '(repeat string))

(defcustom ligature-misc
  (list "..<"  "~-" "-~" "~@"  "-|" "_|_" "|-" "||-" "|=" "||="
        ".?" "?="  "<|>" "<:" ":<" ":>" ">:"
        ".=" ".-" "__" "<<<" ">>>" "<<" ">>" "~~"
        "<$>" "<$" "$>" "<+>" "<+" "+>" "<*>" "<*" "*>" "</" "</>" "/>"
        "|}" "{|" "[<" ">]" ":?>" ":?"  "[||]" "?:" "?."
        "|>" "<|" "||>" "<||" "|||>" "<|||::=" "|]" "[|"
        "#{" "#[" "]#" "#(" "#?" "#_" "#_(" "#:" "#!" "#=")
  "Miscellaneous ligatures."
  :type '(repeat string))

(defcustom ligature-relations
  (list "==" "!=" "<=" ">=" "=:=" "!==" "===" "<>" "/==" "=!=" "=/=" "~=" ":="
        "/=" "^=")
  "Relation ligatures."
  :type '(repeat string))

(defcustom ligature-operators
  (list "&&" "&&&" "||" "++" "--" "!!" "::" "+++" "??" ":::" "***" "---"
        "/\\" "\\/")
  "Operator ligatures."
  :type '(repeat string))

(defcustom ligature-comments-c-like
  (list "//" "///" "/**" "/*" "*/")
  "Ligatures for comments in C-like languages."
  :type '(repeat string))

(defcustom ligature-comments-xml-like
  (list "<!--" "-->")
  "Ligatures for comments in XML-like languages."
  :type '(repeat string))

(defcustom ligature-hashes
  (list "##" "###" "####")
  "Ligatures for comments in languages with # being the comment character."
  :type '(repeat string))

(defcustom ligature-dots
  (list "..." "..")
  "Dot ligatures."
  :type '(repeat string))

(defcustom ligature-semicolons
  (list ";;" ";;;")
  "Ligatures for comments in lisp languages."
  :type '(repeat string))

(defun ligature--get-all ()
  (append ligature-arrows
          ligature-relations
          ligature-operators
          ligature-misc
          ligature-dots
          ligature-comments-c-like
          ligature-comments-xml-like
          ligature-hashes
          ligature-semicolons))

(defun ligature--apply (ligatures)
  (let ((groups (seq-group-by #'string-to-char ligatures)))
    (dolist (group groups)
      (let ((c (car group))
            (rx (regexp-opt (mapcar (lambda (s) (substring s 1))
                                    (cdr group)))))
        (set-char-table-range composition-function-table
                              c `([,(concat "." rx) 0 
compose-gstring-for-graphic]))))))

(define-minor-mode ligature-minor-mode
  "A mode for font ligatures."
  nil "" nil
  (if ligature-minor-mode
      (progn
        (when (minibufferp)
          (error "Cannot use ligature-minor-mode in minibuffer"))
        ;; FIXME: This doesn't work.  When enabled, there will be a local
        ;; variable but the global value is the same (and also includes the
        ;; ligature composition rules).
        (ligature--apply (ligature--get-all)))
    ;; FIXME: Even if the above worked, this could remove much more than this
    ;; mode added itself.
    (kill-local-variable 'composition-function-table)))

(defun ligature-minor-mode--apply-if-possible ()
  (unless (minibufferp)
    (ligature-minor-mode)))

(define-globalized-minor-mode global-ligature-minor-mode
  ligature-minor-mode
  ligature-minor-mode--apply-if-possible)

(provide 'ligature)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]