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

Prettify-symbols config for emacs #312

Closed
To1ne opened this issue Nov 21, 2016 · 47 comments
Closed

Prettify-symbols config for emacs #312

To1ne opened this issue Nov 21, 2016 · 47 comments

Comments

@To1ne
Copy link

To1ne commented Nov 21, 2016

The methods for Emacs currently explained on the wiki are not really working for me. I would like to facilitate emacs prettify-symbols-mode instead (as suggested by @siegebell).

This is what I've got at the moment:

Enable prettify symbols globally:

(global-prettify-symbols-mode 1)

Un-prettify symbols at point for easier editing (one of the reasons why I want to use this method):

(setq prettify-symbols-unprettify-at-point t)

Define prettify symbols:

  (add-hook 'prog-mode-hook
            (lambda ()
              (push '("<=" . ?≤) prettify-symbols-alist)))

For this last piece of config I need your help. I like to have the full list of symbol combo's (e.g. <=) with their ligature (e.g. ). So I would appreciate you would share it with us.

@tonsky
Copy link
Owner

tonsky commented Nov 21, 2016

I’m not sure how best to address this. Ligatures are named glyphs in font file, but they don’t have unicode code or anything. They have names (e.g. greater_greater_hyphen.liga), but I’m not sure to what it is translated in OTF/TTF files.

@To1ne
Copy link
Author

To1ne commented Nov 21, 2016

Owkey, thanks I did not understand this correctly. Too bad, because the unprettify-at-point is pretty useful. See the screenshot below, when the cursor is on the ligature, it unprettifies it.

screen shot 2016-11-21 at 15 54 25

I'll check and see if I can accomplish this with the FiraCode-Regular-Symbol font posted in #211.

@To1ne
Copy link
Author

To1ne commented Nov 22, 2016

So how does Pragmata Pro do this? https://gist.github.com/kwf/dea7bc51101083acb95c875140e2a96d

@tonsky
Copy link
Owner

tonsky commented Nov 22, 2016

They map ligatures to Unicode private use area. E.g. !! is mapped to U+E720. Looks like there’s a way to that, actually, https://glyphsapp.com/tutorials/roll-your-own-glyph-data/. I’ll try to do that in the next version

@fabianhjr
Copy link

@To1ne this is what I was using, however it currently broken. (used to work, something weird is happening now and that's why I came here; found it somwhere on the web/here)

  (custom-set-variables '(haskell-font-lock-symbols t)
                        '(haskell-font-lock-symbols-alist
                          (and (fboundp 'decode-char)
                               (list (cons "&&" (decode-char 'ucs #XE100))
                                     (cons "***" (decode-char 'ucs #XE101))
                                     (cons "*>" (decode-char 'ucs #XE102))
                                     (cons "\\\\" (decode-char 'ucs #XE103))
                                     (cons "||" (decode-char 'ucs #XE104))
                                     (cons "|>" (decode-char 'ucs #XE105))
                                     (cons "::" (decode-char 'ucs #XE106))
                                     (cons "==" (decode-char 'ucs #XE107))
                                     (cons "===" (decode-char 'ucs #XE108))
                                     (cons "==>" (decode-char 'ucs #XE109))
                                     (cons "=>" (decode-char 'ucs #XE10A))
                                     (cons "=<<" (decode-char 'ucs #XE10B))
                                     (cons "!!" (decode-char 'ucs #XE10C))
                                     (cons ">>" (decode-char 'ucs #XE10D))
                                     (cons ">>=" (decode-char 'ucs #XE10E))
                                     (cons ">>>" (decode-char 'ucs #XE10F))
                                     (cons ">>-" (decode-char 'ucs #XE110))
                                     (cons ">-" (decode-char 'ucs #XE111))
                                     (cons "->" (decode-char 'ucs #XE112))
                                     (cons "-<" (decode-char 'ucs #XE113))
                                     (cons "-<<" (decode-char 'ucs #XE114))
                                     (cons "<*" (decode-char 'ucs #XE115))
                                     (cons "<*>" (decode-char 'ucs #XE116))
                                     (cons "<|" (decode-char 'ucs #XE117))
                                     (cons "<|>" (decode-char 'ucs #XE118))
                                     (cons "<$>" (decode-char 'ucs #XE119))
                                     (cons "<>" (decode-char 'ucs #XE11A))
                                     (cons "<-" (decode-char 'ucs #XE11B))
                                     (cons "<<" (decode-char 'ucs #XE11C))
                                     (cons "<<<" (decode-char 'ucs #XE11D))
                                     (cons "<+>" (decode-char 'ucs #XE11E))
                                     (cons ".." (decode-char 'ucs #XE11F))
                                     (cons "..." (decode-char 'ucs #XE120))
                                     (cons "++" (decode-char 'ucs #XE121))
                                     (cons "+++" (decode-char 'ucs #XE122))
                                     (cons "/=" (decode-char 'ucs #XE123))))))

@To1ne
Copy link
Author

To1ne commented Nov 25, 2016

@fabianhjr It seems to me you need the FiraCode-Regular-Symbol font, see this comment.

@howdoicomputer
Copy link

Ah, this would be pretty neat; the suggested workaround currently breaks helm for me in Emacs.

@PhilArmstrong
Copy link

I’m not sure how best to address this. Ligatures are named glyphs in font file, but they don’t have unicode code or anything. They have names (e.g. greater_greater_hyphen.liga), but I’m not sure to what it is translated in OTF/TTF files.

According to https://forum.glyphsapp.com/t/how-to-add-a-glyph-and-assign-it-a-custom-unicode-hex-value-like-font-awesome/900/6

You can give a glyph it’s own unicode number by doing the following:

"you can check "Use custom naming" in Font info > other settings (temporarily). Then the unicode field in the info box in the lower left of the font view will become editable. So that you can add your own values. The you can define the glyph names and the unicodes independently. "

So you could do that, assign the ligatures unicode numbers in the private range (0xE000 upwards) and then emacs users will be able to use the glyphs in the fonts you ship directly by putting appropriate mappings in prettify-symbols-alist.

That still leaves the overlap problem - I’m not quite sure why apps that display the glyphs just fine (like gedit for example) aren’t doing this too. It may a disagreement over where the ligature 0 bound should sit between different applications. I’ve tried changing the ligatures so that the char boundary is at the left end of the glyph & that seems to make emacs behave, but it probably not a change you want to make.

Looking at the code for prettify-symbols, it should be possible to tell it that a sequence of characters is being replaced by a bunch of new ones in sequence, but the format is really weird & at the moment I can’t get it to work at all. If I get it working I’ll let you know.

@PhilArmstrong
Copy link

OK. I’ve fixed the printing of the extra spaces in prettify-symbols-alist, but that just leads to more rendering errors in emacs - looks like emacs really doesn’t like the layout of these ligatures.

For reference, you can do something like the following to insert the requisite extra spaces:

(defun pretty-symbols ()
  "make some word or string show as pretty Unicode symbols"
  (setq prettify-symbols-alist
        '(
	  ("**" . (?\s (Br . Bl) ?\uE004) )
	  ("***" . (?\s (Br . Bl) ?\s (Br . Bl) ?\uE005) )
	  )
	)
  (prettify-symbols-mode)
;  (setq prettify-symbols-unprettify-at-point t)
  )

(add-hook 'prog-mode-hook 'pretty-symbols)

(I’ve mapped ** and *** to U+E004 and U+E005 respectively in my quick custom version of FiraCode-Medium)

This works fine as you type the symbol, but as soon as you type anything after the symbol, emacs goes back and overwrites the two characters to the left of the new ligature with extra spaces! It looks like it isn’t taking account of the full width of the ligature when rendering it initially, but then is including it afterwards, so either way you get rendering errors with FiraCode as currently designed :(

@PhilArmstrong
Copy link

OK, so editing the font so that the ligature starts at offset 0 (well, a small positive offset in fact) instead of -1000 or so means that emacs seems to work just fine, without any need for the extra spaces. Is there some reason the ligatures have this negative offset? I’ve had a look at the ligatures for things like ffi / ffl in other fonts & they don’t seem to need it.

@PhilArmstrong
Copy link

Having had a poke around, I see that both Hasklig & Monoid seem to do the same thing, ie position the ligature so that the 0 point is in between the second & third characters for a three character ligature. This does seem to confuse emacs unfortunately!

Is this behaviour documented anywhere in the ttf standards? What does PragmataPro do, does anyone have a copy they could have a look at?

It would be nice to get this fixed - but either emacs or the fonts are doing it wrong - before I poke the emacs devs it would be good to be able to quote chapter & verse at them from somewhere authoritative.

@PhilArmstrong
Copy link

PhilArmstrong commented Jan 4, 2017

OK. So I borrowed a copy of Pragmata Pro for testing purposes only & have discovered that it’s ligatures are defined with the leftmost part of the ligature starting at a positive offset from 0. ie, no part of the ligature is to the left of the origin.

So the free monospace coding fonts with multi-character ligatures (Hasklig, FiraCode) differ from Pragmata Pro in this respect.

@PhilArmstrong
Copy link

(Can confirm that emacs works perfectly with PragmataPro & a custom pretty-symbols-alist btw. I may hack FiraCode & change all the ligatures to have their origin on the left. Will see if I have the tuits.)

@tonsky
Copy link
Owner

tonsky commented Jan 4, 2017

@PhilArmstrong this is done so that editors would let you “step into” ligature. This feels more natural when editing the code. Without it, e.g. <-> would be rendered as a single glyph and you won’t be able to position your cursor inside and e.g. remove the dash

@tonsky
Copy link
Owner

tonsky commented Jan 4, 2017

I’ll leave this picture here (it’s code table from PragmataPro so it won’t get lost)

ligatures

@PhilArmstrong
Copy link

@tonsky I can step into the PragmataPro ligatures just fine in the editors I have available to me (not including emacs). Eg I can type ***, get the three asterisk ligature, step back one character into the ligature, see the caret displayed between the second & third *s, delete the middle * and end up with the two asterisk ligature. (This using geany, which is IIRC a GTK3 based editor).

Which editors require these left shifting ligatures?

Ignoring the placement issue, it would be great if FiraCode assigned unicode private space codepoints to the ligatures!

Thanks for all your work on FiraCode.

@PhilArmstrong
Copy link

(You can also mark caret points in ligatures, which should let editors automatically backstep into them in a natural fashion, although poking at the PragmataPro ttf in fontforge it doesn’t look like it’s using that feature. It might be an OpenType-only feature?)

@tonsky
Copy link
Owner

tonsky commented Jan 4, 2017

Atom and CodeMirror require it, IntelliJ IDEA does not. I’ll explore if I can make use of caret points, that would be a great help, actually.

@PhilArmstrong
Copy link

IntelliJ is (presumably) using the HarfBuzz layout engine as that’s what (IIRC) all the Java runtimes use & it’s also the backend behind most of the Linux text rendering libraries, so it makes sense that Java & GTK3 / Qt - based editors would share the same behaviour.

@PhilArmstrong
Copy link

PhilArmstrong commented Jan 4, 2017

(It’s also why FiraCode doesn’t work in the Gnome Terminal or any other libvte based program - it doesn’t use a layout engine to paint the glyphs, so no ligatures.)

@tonsky
Copy link
Owner

tonsky commented Jan 4, 2017

Unfortunately, Atom doesn’t seem to understand caret positions. Also, Terminal.app (OS X) doesn’t show normal ligatures (liga) or dlig, but does show calt. So I think I’ll stick with that technique. I’ll see what can be done for Emacs, maybe I’ll just copy same ligatures but fix the offset for duplicates and assign Unicode codes to that

@PhilArmstrong
Copy link

After some poking, it turns out that CodeMirror works just fine in firefox, but not in Chrome, which suggests that it’s the Chrome font rendering that’s at fault in Atom. How annoying!

@PhilArmstrong
Copy link

(Atom being based on electron which is, IIRC, a packaged up Chrome browser.)

@Profpatsch
Copy link

Profpatsch commented May 3, 2017

So, after reading documentation for a bit, especially on how compose-region works (which is used by prettify-symbols-mode), I was able to create a full solution for Hasklig code points: i-tu/Hasklig#84 (comment)

If #211 gets implemented and each combined glyph gets a code point, this is easily translated to FiraCode.

@Triavanicus
Copy link

Triavanicus commented Nov 13, 2018

So this?

(defun fira-code-mode--make-alist (list)
  "Generate prettify-symbols alist from LIST."
  (let ((idx -1))
    (mapcar
     (lambda (s)
       (setq idx (1+ idx))
       (let* ((code (+ #Xe100 idx))
	      (width (string-width s))
	      (prefix ())
	      (suffix '(?\s (Br . Br)))
	      (n 1))
	 (while (< n width)
	   (setq prefix (append prefix '(?\s (Br . Bl))))
	   (setq n (1+ n)))
	 (cons s (append prefix suffix (list (decode-char 'ucs code))))))
     list)))

(defconst fira-code-mode--ligatures
  '("www" "**" "***" "**/" "*>" "*/" "\\\\" "\\\\\\"
    "{-" "[]" "::" ":::" ":=" "!!" "!=" "!==" "-}"
    "--" "---" "-->" "->" "->>" "-<" "-<<" "-~"
    "#{" "#[" "##" "###" "####" "#(" "#?" "#_" "#_("
    ".-" ".=" ".." "..<" "..." "?=" "??" ";;" "/*"
    "/**" "/=" "/==" "/>" "//" "///" "&&" "||" "||="
    "|=" "|>" "^=" "$>" "++" "+++" "+>" "=:=" "=="
    "===" "==>" "=>" "=>>" "<=" "=<<" "=/=" ">-" ">="
    ">=>" ">>" ">>-" ">>=" ">>>" "<*" "<*>" "<|" "<|>"
    "<$" "<$>" "<!--" "<-" "<--" "<->" "<+" "<+>" "<="
    "<==" "<=>" "<=<" "<>" "<<" "<<-" "<<=" "<<<" "<~"
    "<~~" "</" "</>" "~@" "~-" "~=" "~>" "~~" "~~>" "%%"
    "x" ":" "+" "+" "*"))



(defvar fira-code-mode--old-prettify-alist)

(defun fira-code-mode--enable ()
  "Enable Fira Code ligatures in current buffer."
  (setq-local fira-code-mode--old-prettify-alist prettify-symbols-alist)
  (setq-local prettify-symbols-alist (append (fira-code-mode--make-alist fira-code-mode--ligatures) fira-code-mode--old-prettify-alist))
  (prettify-symbols-mode t))

(defun fira-code-mode--disable ()
  "Disable Fira Code ligatures in current buffer."
  (setq-local prettify-symbols-alist fira-code-mode--old-prettify-alist)
  (prettify-symbols-mode -1))

(define-minor-mode fira-code-mode
  "Fira Code ligatures minor mode"
  :lighter " FiraCode"
  (setq-local prettify-symbols-unprettify-at-point 'right-edge)
  (if fira-code-mode
      (fira-code-mode--enable)
    (fira-code-mode--disable)))

(defun fira-code-mode--setup ()
  "Setup Fira Code Symbols"
  (set-fontset-font t '(#Xe100 . #Xe16f) "Fira Code Symbol"))

(provide 'fira-code-mode)

(Updated November 20, 2018 at 6:40 am CST)

@radrow
Copy link

radrow commented Nov 20, 2018

@Triavanicus

It did not work for me. Instead I got strange characters and below
_screenshot

@wedens
Copy link

wedens commented Nov 20, 2018

@radrow Do you have "Fira Code Symbol" font installed (not just plain Fira Code)?

Also, you'll need to set the font for the ligatures codepoint range: (set-fontset-font t '(#Xe100 . #Xe16f) "Fira Code Symbol"). For some reason this is not included in the snippet above.

@Triavanicus
Copy link

I updated the snippit, and put it in the (fira-code-mode--setup) function

@radrow
Copy link

radrow commented Nov 20, 2018

Strange. It is still buggy, but a bit less when using "Fira Code" as default instead of "Fira Code Symbol" (eg. :: turns into =>). Which version of emacs are you testing this on? I am using emacs 26.1 with spacemacs and putting snippet in user-init (before packages load)

@Profpatsch
Copy link

Profpatsch commented Nov 21, 2018

It did not work for me. Instead I got strange characters and below

Have you restarted Emacs lor (||) rebooted? That’s sometimes required to make font caches update.

@radrow
Copy link

radrow commented Nov 21, 2018

Rebooted, no difference

@To1ne
Copy link
Author

To1ne commented Nov 28, 2018

Thanks everyone. Especially @Triavanicus.

I've restructured the wiki page with all findings. It should be easy now for other to find them. So I'm closing this issue.

@To1ne To1ne closed this as completed Nov 28, 2018
@To1ne
Copy link
Author

To1ne commented Nov 28, 2018

@radrow I think the Fira Code Symbol font you have is not good. It seems characters have switched places. I hope we can some time soon have an official font with the symbols in the private Unicode area, but I'm leaving that to #211.

But at the moment the wiki is suggesting the one from: #211 (comment) The symbol map is included, so you can see if the error is an offset problem, or actually a swap of symbols?

If you see an offset issue, something odd happens with the generation of the prettify-symbols-alist. Can you please post the content of prettify-symbols-alist here?

@wedens
Copy link

wedens commented Dec 16, 2018

Note that Fira Code Symbol conflicts with Material Icons (overlapping codepoints), so you may have ligatures instead of icons where material icons are used via all-the-icons.

@radrow
Copy link

radrow commented Dec 22, 2018

Okay, it turned that I didn't have Fira Code Symbol installed correctly. I did not recieve any warning nor error from emacs about this

@Triavanicus
Copy link

Triavanicus commented Dec 24, 2018 via email

@ezmiller
Copy link

@Triavanicus so far I've just dropped it into my .spacemacs file. I didn't realize that to get this to work you need to activate the mode. I tested this by just doing it in the editor: C-M 'fira-code-mode.

That showed some progress, but when I activated the mode I was getting odd symbols with numbers, e.g.

image

Any idea why this may be happening? Thanks for the help!

@Triavanicus
Copy link

Triavanicus commented Dec 24, 2018 via email

@ezmiller
Copy link

I downloaded that, installed it using the "Font Book" app on mac, and then added this to the font settings in my .spacemacs file:

   dotspacemacs-default-font '(("Fira Code"
                                :size 16
                                :weight normal
                                :width normal
                                :powerline-scale 1.2)
                               ("Fira Code Symbol"
                                :size 16
                                :weight normal
                                :width normal
                                :powerline-scale 1.2))

@Triavanicus
Copy link

Triavanicus commented Dec 24, 2018 via email

@ezmiller
Copy link

Hi, I posted the entirety of the snippet above into the .spacemacs file, below everything else. My understanding was that the snippet above enables that mode such that I was able to activate it in the editor.

I haven't tried that method you referenced as I was trying to avoid installing the alternate mac port of emacs.

@Triavanicus
Copy link

Triavanicus commented Dec 24, 2018

@ezmiller
which, at least for me, it does so long as do the following. Also reading some more into the issue, you might have to reset your fontconfig cache (which if you know how to do, it will save you a reboot, otherwise, you will have to reboot :( )

(fira-code-mode--setup)
(add-hook 'prog-mode-hook 'fira-code-mode)

other than that, I don't know what your issue could be.

@ejmg
Copy link

ejmg commented Jan 8, 2019

@Triavanicus I really appreciate your solution that you added to the wiki. I think it works a lot better than the previous hack I had used.

I have just one question, if you don't mind?

How can I disable the ligature rendering for "x" from the prettify-symbols list without messing up the character encoding? Based on the way you enumerate the font character codes, if I were to remove "x" from fira-code-mode--ligatures, every ligature after that is offset by -1, meaning : renders as x, + renders as : and so forth.

I don't fully understand what fira-code-mode--make-alist is doing (or how fonts work on emacs, for that matter), and have tried to skip over/ignore adding the encoding for "x" to no avail. Is there any easy/obvious way to "unset" or skip over the "x" ligature provided by siegebell's FiraCode-Regular-Symbol pack?

@Triavanicus
Copy link

Triavanicus commented Jan 8, 2019 via email

@soraros
Copy link

soraros commented Apr 12, 2019

This one is easy. Replace fira-code-mode--make-alist with the following and pass in only the list of symbols you want to enable.

(defun fira-code-mode--make-alist (lat)
  "Generate prettify-symbols alist from LIST."
  (let ((alist (cl-mapcar #'cons
                          fira-code-mode--ligatures
                          (number-sequence 0 (- (length fira-code-mode--ligatures) 1)))))
    (mapcar
     (lambda (s)
       (let* ((idx (cdr (assoc s alist)))
              (code (+ #Xe100 idx))
              (width (string-width s))
              (prefix ())
              (suffix '(?\s (Br . Br)))
              (n 1))
         (while (< n width)
           (setq prefix (append prefix '(?\s (Br . Bl))))
           (setq n (1+ n)))
         (cons s (append prefix suffix (list (decode-char 'ucs code))))))
     lat)))

@GaussianWonder
Copy link

The methods for Emacs currently explained on the wiki are not really working for me. I would like to facilitate emacs prettify-symbols-mode instead (as suggested by @siegebell).

This is what I've got at the moment:

Enable prettify symbols globally:

(global-prettify-symbols-mode 1)

Un-prettify symbols at point for easier editing (one of the reasons why I want to use this method):

(setq prettify-symbols-unprettify-at-point t)

Define prettify symbols:

  (add-hook 'prog-mode-hook
            (lambda ()
              (push '("<=" . ?≤) prettify-symbols-alist)))

For this last piece of config I need your help. I like to have the full list of symbol combo's (e.g. <=) with their ligature (e.g. ). So I would appreciate you would share it with us.

i know this is suuuuuper late but this might help
https://www.copypastecharacter.com/all-characters. Just copy paste them, seems to work :))

@hyiltiz
Copy link

hyiltiz commented Feb 29, 2020

Does the wiki on Emacs support need an update now that HarfBuzz based font rendering is in Emacs?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests