Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FiraCode “Ligature” integration #6972

Closed
Profpatsch opened this issue Aug 31, 2016 · 63 comments
Closed

FiraCode “Ligature” integration #6972

Profpatsch opened this issue Aug 31, 2016 · 63 comments
Labels
Discussion Fonts stale marked as a stale issue/pr (usually by a bot)

Comments

@Profpatsch
Copy link
Contributor

FiraCode is a nice derivation from Fira Mono that adds many ligatures for a nice code look. It uses Unicode ligatures, but Emacs sadly doesn’t support them (yet). I’d like to add a layer to Spacemacs to support that.

There is a page about integration into Emacs via font-lock, and the second example is also how Hasklig can be made to work with Emacs. I noticed integrating too many ligatures that way makes font rendering very slow.

@TheBB
Copy link
Contributor

TheBB commented Sep 7, 2016

Is there a reason why prettify-symbols-mode is not being used for this?

@Profpatsch
Copy link
Contributor Author

Profpatsch commented Sep 7, 2016

Probably not, no. But it looks awesome.

@GregorySchwartz
Copy link

I'm not sure if that's the right solution here, as it looks like prettify-symbols-mode alters the number of characters per row, while the ligature rendering preserves that property. For instance, using FiraCode in Konsole would make "->" become an arrow but still take up two characters. Similarly, "::", ">>=", et al. conserve that many characters, keeping the spacing correct. However, if prettify-symbols-mode can keep the character count, then that works too.

@hyiltiz
Copy link

hyiltiz commented Feb 21, 2017

So to install and use Fira code with spacemacs, does one follow the instructions for emacs from the fira code project site [1], or there is already some mechanism in spacemacs that can use fira code so that the user only needs to "helm xselect font" the Fira Code Retina? I would very much like to use Fira Code in Spacemacs, but am trying not to break anything. I am just coming from Vim, and know almost nothing about Lisp except what is taught in Wikipedia. I tried putting the first snippet provided in that page to my .spacemacs file within the user-config() function, but after restarting, when I restart spacemacs and type "=>", nothing changes (I do not see a ligature).

[1] https://github.com/tonsky/FiraCode/wiki/Setting-up-Emacs

@Profpatsch
Copy link
Contributor Author

I haven’t yet looked at it any further, maybe the regex-method works, but I suspect it to severely slow down every kind of text display. (It’s essentially running a couple dozen matches on every substring in each buffer…)

@Profpatsch
Copy link
Contributor Author

News!
https://ekaschalk.github.io/post/prettify-mode/

It seems to work with firacode now. If anyone wants to take a look: go for it!

@Profpatsch
Copy link
Contributor Author

Another update: Hasklig seems to have moved to the FiraCode mechanism with 1.0 as well. So getting this to work would give us two fonts to choose from.

@GregorySchwartz
Copy link

Unfortunately that method still does not allow multiple blocks to be taken up by a single ligature (from the website @Profpatsch linked to). This is problematic for coding:

For ligatures, the number of visual points composing the replacement is the same as its composing characters. For instance, the ligature for -> occupies two spaces.

But this is not the case for prettify-symbols or pretty-mode. Both alpha and not in are reduced to one
character.

So the line width you see may not be the same as its actual width.

This has two effects:

A line could then exceed 80 characters with prettify-mode disabled.
Indentation is performed using the Unicode replacements, not actual spacing.

@Profpatsch
Copy link
Contributor Author

Oh no. Maybe it can be patched?

@GregorySchwartz
Copy link

I think that prettify would have to support adding in the lost space.

@Profpatsch
Copy link
Contributor Author

Well, these fonts make the ligatures exactly as wide as the normal combinations, so it must support multi-width characters as well.

@ekaschalk
Copy link

ekaschalk commented May 15, 2017

Hi I wrote the blog on pretty-mode linked earlier.

The options as I see it are:

  1. Don't use any symbols with disagreeing number of spaces.
  2. Use the visual spacing - your indentation won't agree with the unfontified buffer.
  3. Use the true spacing - your visuals will have extraneous spaces. (Possible with: https://github.com/Ilazki/prettify-utils.el)
  4. Use the visual spacing with true indentation - your visuals will have wrong indentation.
  5. Pre/post-save (or commit/etc..) hook that unfontifies and runs tab on the buffer then refontifies and tabs again.
  6. Use the visual spacing and visually modify indentation, ie. the true indentation is font-locked.

I took a shot at the hook:

(defun test-fontlock-fix-before ()
  (font-lock-mode -1)
  (spacemacs/indent-region-or-buffer))

(defun test-fontlock-fix-after ()
  (font-lock-mode 1)
  (sit-for 1)  ; Without the sleep it doesnt reindent.
  (spacemacs/indent-region-or-buffer))

(add-hook 'before-save-hook 'test-fontlock-fix-before)
(add-hook 'after-save-hook 'test-fontlock-fix-after)

This works in all cases that (spacemacs/indent-region-or-buffer) does, which I found it is not everytime.

The glaring flaws are the sleep and that save-file cannot tell anymore when your file hasn't changed, especially annoying with eg magit.

Number 6 is the only true solution I see to this problem but it seems quite involved.

Any other thoughts on how spacing could be handled?

@Profpatsch
Copy link
Contributor Author

I implemented the visual spacing solution:
https://github.com/Profpatsch/blog/blob/master/posts/ligature-emulation-in-emacs/post.md

I only afterwards noticed that it’s not perfect, but it works fine for me right now with Hasklig.

My idea would be to switch back to non-visual and tag every symbol with the number of spaces it occupies, then prefix them with spaces accordingly. I think I’m gonna try that next.

@CMCDragonkai
Copy link

When I use Fira Code in Spacemacs even without ligature support sometimes the character alignment is off, specifically where line 1 uses bold for some characters, and line 2 doesn't have bold, then they don't line up vertically. What could be causing this?

@root42
Copy link

root42 commented Aug 22, 2017

@Profpatsch did you considered making a MELPA package from your code?

@Profpatsch
Copy link
Contributor Author

@root42 No, not really. But if you want one, go ahead. You have my blessing. :) It’s MIT-licensed anyway.

@honza
Copy link

honza commented Sep 12, 2017

@Profpatsch How can I plug that into my .spacemacs?

@Profpatsch
Copy link
Contributor Author

@honza Just copy the code verbatim, then Spc f e R or Spc r R if that does not work.

@honza
Copy link

honza commented Sep 13, 2017

Putting this code:

  (defun my-correct-symbol-bounds (pretty-alist)
    "Prepend a TAB character to each symbol in this alist,
this way compose-region called by prettify-symbols-mode
will use the correct width of the symbols
instead of the width measured by char-width."
    (mapcar (lambda (el)
              (setcdr el (string ?\t (cdr el)))
              el)
            pretty-alist))

  (defun my-ligature-list (ligatures codepoint-start)
    "Create an alist of strings to replace with
codepoints starting from codepoint-start."
    (let ((codepoints (-iterate '1+ codepoint-start (length ligatures))))
      (-zip-pair ligatures codepoints)))

  (setq my-fira-code-ligatures
        (let* ((ligs '("www" "**" "***" "**/" "*>" "*/" "\\\\" "\\\\\\"
                       "{-" "[]" "::" ":::" ":=" "!!" "!=" "!==" "-}"
                       "--" "---" "-->" "->" "->>" "-<" "-<<" "-~"
                       "#{" "#[" "##" "###" "####" "#(" "#?" "#_" "#_("
                       ".-" ".=" ".." "..<" "..." "?=" "??" ";;" "/*"
                       "/**" "/=" "/==" "/>" "//" "///" "&&" "||" "||="
                       "|=" "|>" "^=" "$>" "++" "+++" "+>" "=:=" "=="
                       "===" "==>" "=>" "=>>" "<=" "=<<" "=/=" ">-" ">="
                       ">=>" ">>" ">>-" ">>=" ">>>" "<*" "<*>" "<|" "<|>"
                       "<$" "<$>" "<!--" "<-" "<--" "<->" "<+" "<+>" "<="
                       "<==" "<=>" "<=<" "<>" "<<" "<<-" "<<=" "<<<" "<~"
                       "<~~" "</" "</>" "~@" "~-" "~=" "~>" "~~" "~~>" "%%"
                       "x" ":" "+" "+" "*")))
          (my-correct-symbol-bounds (my-ligature-list ligs #Xe100))))

to the (defun dotspacemacs/user-config ()) section, and restarting Emacs has no effect. I also set the font to Fira Code.

@Profpatsch
Copy link
Contributor Author

Profpatsch commented Sep 13, 2017

You forgot the code that adds it to the hooks that are called when you enable a mode.

  ;; nice glyphs for haskell with hasklig
  (defun my-set-hasklig-ligatures ()
    "Add hasklig ligatures for use with prettify-symbols-mode."
    (setq prettify-symbols-alist
          (append my-hasklig-ligatures prettify-symbols-alist))
    (prettify-symbols-mode))

  (add-hook 'haskell-mode-hook 'my-set-hasklig-ligatures)

For FiraCode change accordingly.

@honza
Copy link

honza commented Sep 13, 2017

@Profpatsch Ah, thanks! I was hoping to enable it globally.

@honza
Copy link

honza commented Sep 13, 2017

I can confirm that works wonderfully. Thanks @Profpatsch <3

@Profpatsch
Copy link
Contributor Author

Profpatsch commented Sep 13, 2017

Afaik inherits every mode from fundamental-mode and every programming language mode from prog-mode. So (maybe?) hooking it into one of these makes it work globally.

@ekaschalk
Copy link

I've developed a proof of concept fix to ligature indentation that you all might find interesting: http://www.modernemacs.com/post/lig-spacing/

@gustavAR
Copy link

gustavAR commented Feb 22, 2018

emacs-mac doesn't override your old emacs installation automatically.

Homebrew has probably installed emacs-mac in /usr/local/opt/emacs-mac/.
so you're going to want to create an alias of Emacs.app by right-clicking it:
image
Move the alias to your Applications folder and make sure it's the only one. I tried doing this automatically by using brew linkapps, but for some reason this command prioritised my pre-existing installation of emacs-plus.

You might also want to make the emacs command refer to your new installation. If so, add an alias to your ~/.bashrc, which can be done by running the following command in your terminal and restarting your terminals.

echo "alias emacs=\"/usr/local/opt/emacs-mac/bin/emacs\"" >> ~/.bashrc

@rlopzc
Copy link

rlopzc commented Feb 22, 2018

Fixed! Thanks @gustavAR 👍

Btw now my themes are displaying correctly, and is faster than before!

@abeluck
Copy link

abeluck commented Mar 28, 2018

This issue is quite long and there are many comments, some specific to macOS and some not.

As a debian spacemacs user, is there a known solution/workaround to make FiraCode work in (spac)emacs with ligatures not affecting line length?

@fosskers
Copy link
Contributor

fosskers commented Mar 28, 2018

@abeluck Have you tried this and followed the conversation for a few messages from this timestamp?

@Huxpro
Copy link

Huxpro commented Nov 11, 2018

@gustavAR As far as I know, emacs-mac and emacs-plus were two different distributions of Emacs on mac. Any caveats of switching from one to the another? I couldn't find any detailed comparison between both sadly.

@mdedetrich
Copy link

I made a ticket about this, i.e. a specific implementation already exists #11639

@github-actions
Copy link

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Please let us know if this issue is still valid!

@github-actions github-actions bot added the stale marked as a stale issue/pr (usually by a bot) label Feb 29, 2020
@hyiltiz
Copy link

hyiltiz commented Feb 29, 2020

@github-actions this issue is still open and awaits action from the devs to support in the develop branch out of the box (or via an option via a variable `spacemacs-use-font-ligature 'always/'code/'never).

@Profpatsch not sure which one is more convenient/easy to do: writing up a layer for spacemacs, or publishing a melpa package?

@Profpatsch
Copy link
Contributor Author

Profpatsch commented Mar 2, 2020

@Profpatsch not sure which one is more convenient/easy to do: writing up a layer for spacemacs, or publishing a melpa package?

I don’t know, I have never created a melpa package

@nixmaniack
Copy link
Contributor

We should keep this issue open.

@duianto duianto removed the stale marked as a stale issue/pr (usually by a bot) label Mar 13, 2020
@ViktorHaag
Copy link

emacs-mac doesn't override your old emacs installation automatically.

Homebrew has probably installed emacs-mac in /usr/local/opt/emacs-mac/.

Another solution is to use homebrew to install the cask of emacs-mac instead of building from a recipe. It trails the version available via recipe sometimes, but otherwise it's solid and it installs /Applications/Emacs.app automagically.

@jerbaroo
Copy link

You can also use the development version of Emacs (28) which has ligature support. emacs-plus@28 on homebrew. https://github.com/d12frosted/homebrew-emacs-plus

@hyiltiz
Copy link

hyiltiz commented Aug 26, 2020

@barischrooneyj care to share your set up for the ligature support in Emacs 28? There was HarfBuzz support there but seemed it seeded some configuration [1,2].

[1] https://www.reddit.com/r/emacs/comments/byddvm/emacsdevel_harfbuzz_is_now_available_on_master/
[2] https://www.reddit.com/r/emacs/comments/a5upu5/emacs_text_shaping_using_harfbuzz/

@liny01-nbsa
Copy link

I think even Emacs 27 has the support too. microsoft/cascadia-code#153 (comment). Use the config from it, I have tested with JetBrainsMono FiraCode.

@hyiltiz
Copy link

hyiltiz commented Sep 21, 2020

Copied from microsoft/cascadia-code#153 (comment) for convenience here:

(use-package composite
  :defer t
  :init
  (defvar composition-ligature-table (make-char-table nil))
  :hook
  (((prog-mode conf-mode nxml-mode markdown-mode help-mode)
    . (lambda () (setq-local composition-function-table composition-ligature-table))))
  :config
  ;; support ligatures, some toned down to prevent hang
  (when (version<= "27.0" emacs-version)
    (let ((alist
           '((33 . ".\\(?:\\(==\\|[!=]\\)[!=]?\\)")
             (35 . ".\\(?:\\(###?\\|_(\\|[(:=?[_{]\\)[#(:=?[_{]?\\)")
             (36 . ".\\(?:\\(>\\)>?\\)")
             (37 . ".\\(?:\\(%\\)%?\\)")
             (38 . ".\\(?:\\(&\\)&?\\)")
             (42 . ".\\(?:\\(\\*\\*\\|[*>]\\)[*>]?\\)")
             ;; (42 . ".\\(?:\\(\\*\\*\\|[*/>]\\).?\\)")
             (43 . ".\\(?:\\([>]\\)>?\\)")
             ;; (43 . ".\\(?:\\(\\+\\+\\|[+>]\\).?\\)")
             (45 . ".\\(?:\\(-[->]\\|<<\\|>>\\|[-<>|~]\\)[-<>|~]?\\)")
             ;; (46 . ".\\(?:\\(\\.[.<]\\|[-.=]\\)[-.<=]?\\)")
             (46 . ".\\(?:\\(\\.<\\|[-=]\\)[-<=]?\\)")
             (47 . ".\\(?:\\(//\\|==\\|[=>]\\)[/=>]?\\)")
             ;; (47 . ".\\(?:\\(//\\|==\\|[*/=>]\\).?\\)")
             (48 . ".\\(?:\\(x[a-fA-F0-9]\\).?\\)")
             (58 . ".\\(?:\\(::\\|[:<=>]\\)[:<=>]?\\)")
             (59 . ".\\(?:\\(;\\);?\\)")
             (60 . ".\\(?:\\(!--\\|\\$>\\|\\*>\\|\\+>\\|-[-<>|]\\|/>\\|<[-<=]\\|=[<>|]\\|==>?\\||>\\||||?\\|~[>~]\\|[$*+/:<=>|~-]\\)[$*+/:<=>|~-]?\\)")
             (61 . ".\\(?:\\(!=\\|/=\\|:=\\|<<\\|=[=>]\\|>>\\|[=>]\\)[=<>]?\\)")
             (62 . ".\\(?:\\(->\\|=>\\|>[-=>]\\|[-:=>]\\)[-:=>]?\\)")
             (63 . ".\\(?:\\([.:=?]\\)[.:=?]?\\)")
             (91 . ".\\(?:\\(|\\)[]|]?\\)")
             ;; (92 . ".\\(?:\\([\\n]\\)[\\]?\\)")
             (94 . ".\\(?:\\(=\\)=?\\)")
             (95 . ".\\(?:\\(|_\\|[_]\\)_?\\)")
             (119 . ".\\(?:\\(ww\\)w?\\)")
             (123 . ".\\(?:\\(|\\)[|}]?\\)")
             (124 . ".\\(?:\\(->\\|=>\\||[-=>]\\||||*>\\|[]=>|}-]\\).?\\)")
             (126 . ".\\(?:\\(~>\\|[-=>@~]\\)[-=>@~]?\\)"))))
      (dolist (char-regexp alist)
        (set-char-table-range composition-ligature-table (car char-regexp)
                              `([,(cdr char-regexp) 0 font-shape-gstring]))))
    (set-char-table-parent composition-ligature-table composition-function-table))
  )

@github-actions
Copy link

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Please let us know if this issue is still valid!

@github-actions github-actions bot added the stale marked as a stale issue/pr (usually by a bot) label Mar 14, 2022
@Profpatsch
Copy link
Contributor Author

👾 👾 👾

activityyyyy

@lebensterben lebensterben removed - Forum - stale marked as a stale issue/pr (usually by a bot) labels Mar 15, 2022
@lebensterben
Copy link
Contributor

@Profpatsch

There will be no ligature for any specific font. But ligature in general is already supported with unicode-fonts layer. The only issue is currently it won't work with Emacs 27.

Copy link

github-actions bot commented May 1, 2024

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Please let us know if this issue is still valid!

@github-actions github-actions bot added the stale marked as a stale issue/pr (usually by a bot) label May 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Discussion Fonts stale marked as a stale issue/pr (usually by a bot)
Projects
None yet
Development

No branches or pull requests