tonsky / FiraCode

Free monospaced font with programming ligatures
SIL Open Font License 1.1
77.3k stars 3.1k forks source link

Add glyphs to unicode reserved plane #211

Open driusan opened 8 years ago

driusan commented 8 years ago

I'm trying to use FiraCode w/ ligatures in a text editor I'm writing (where I'm currently using Deja Vu Sans Mono), but there doesn't seem to be any way to access the ligatures from Go, where the standard font drawing methods are based on converting unicode runes to glyphs and have no knowledge of ligatures.

The Unicode private use area planes is designed for this purpose, according to wikipedia, but doesn't seem to be used by Firacode (at least as far as I can tell by printing runes starting at 0x100000 or 0x0f0000 and visually scanning). Would it be possible to map the ligatures to the supplementary plan? If they were accessible as runes in a private use area with a documented mapping, I could manually do the context-sensitive mapping when rendering.

It's possible that I'm missing something, because all the "how to use the font" documentation seems to be user documentation, and I can't find any developer documentation..

siegebell commented 8 years ago

Providing the fancy glyphs via private use area (PUA) codes would resolve #42 via prettify-symbols-mode.

siegebell commented 8 years ago

@mordocai I believe this is what you're looking for.

siegebell commented 8 years ago

@mordocai Here's a workaround: I've extracted the glyphs that Fira Code adds into a separate font, and assigned each a Unicode ID in the private character area. Download the symbols font: FiraCode-Regular-Symbol.zip

This symbols font should be assigned as a fallback font for either Fira Code or Fira Mono because it does not define the regular characters.

Character map:

 www  \ue100     **   \ue101    ***  \ue102    **/  \ue103
  *>  \ue104     */   \ue105     \\  \ue106    \\\  \ue107
  {-  \ue108     []   \ue109     ::  \ue10a    :::  \ue10b
  :=  \ue10c     !!   \ue10d     !=  \ue10e    !==  \ue10f
  -}  \ue110     --   \ue111    ---  \ue112    -->  \ue113
  ->  \ue114    ->>   \ue115     -<  \ue116    -<<  \ue117
  -~  \ue118     #{   \ue119     #[  \ue11a     ##  \ue11b
 ###  \ue11c   ####   \ue11d     #(  \ue11e     #?  \ue11f
  #_  \ue120    #_(   \ue121     .-  \ue122     .=  \ue123
  ..  \ue124    ..<   \ue125    ...  \ue126     ?=  \ue127
  ??  \ue128     ;;   \ue129     /*  \ue12a    /**  \ue12b
  /=  \ue12c    /==   \ue12d     />  \ue12e     //  \ue12f
 ///  \ue130     &&   \ue131     ||  \ue132    ||=  \ue133
  |=  \ue134     |>   \ue135     ^=  \ue136     $>  \ue137
  ++  \ue138    +++   \ue139     +>  \ue13a     +>  \ue13a
 =:=  \ue13b     ==   \ue13c    ===  \ue13d    ==>  \ue13e
  =>  \ue13f    =>>   \ue140     <=  \ue141    =<<  \ue142
 =/=  \ue143     >-   \ue144     >=  \ue145    >=>  \ue146
  >>  \ue147    >>-   \ue148    >>=  \ue149    >>>  \ue14a
  <*  \ue14b    <*>   \ue14c     <|  \ue14d    <|>  \ue14e
  <$  \ue14f    <$>   \ue150   <!--  \ue151     <-  \ue152
 <--  \ue153    <->   \ue154     <+  \ue155    <+>  \ue156
  <=  \ue157    <==   \ue158    <=>  \ue159    <=<  \ue15a
  <>  \ue15b     <<   \ue15c    <<-  \ue15d    <<=  \ue15e
 <<<  \ue15f     <~   \ue160    <~~  \ue161     </  \ue162
 </>  \ue163     ~@   \ue164     ~-  \ue165     ~=  \ue166
  ~>  \ue167     ~~   \ue168    ~~>  \ue169     %%  \ue16a
   x  \ue16b      :   \ue16c      +  \ue16d      *  \ue16f
siegebell commented 8 years ago

And if you're using the prettify-symbols-mode extension for vscode, you can use the following substitution settings. (prettify-symbols-mode for Emacs should look similar-ish, but you'll combine the pre, ugly, and post into the same regex and \ue00a0 maybe can be replaced with a normal space.)

"prettifySymbolsMode.substitutions": [
  {
    "language": "*",
    "substitutions": [
      { "ugly": "\\{2}", "pretty": "\u03bb", "post": "\\s*(?:\\w|_).*?\\s*->" },
      { "ugly": "\\.=", "pretty": " \ue123", "pre": "[^.=:!/<>]|^", "post": "[^.=:!/<>]|$" },
      { "ugly": "\\.-", "pretty": " \ue122", "pre": "[^.=:!/<>]|^", "post": "[^.=:!/<>]|$" },
      { "ugly": ":=", "pretty": " \ue10c", "pre": "[^.=:!/<>]|^", "post": "[^.=:!/<>]|$" },
      { "ugly": "=:=", "pretty": "\u00a0  \ue13b", "pre": "[^.=:!/<>]|^", "post": "[^.=:!/<>]|$" },
      { "ugly": "==", "pretty": " \ue13c", "pre": "[^.=:!/<>]|^", "post": "[^.=:!/<>]|$" },
      { "ugly": "!=", "pretty": " \ue10e", "pre": "[^.=:!/<>]|^", "post": "[^.=:!/<>]|$" },
      { "ugly": "===", "pretty": "\u00a0  \ue13d", "pre": "[^.=:!/<>]|^", "post": "[^.=:!/<>]|$" },
      { "ugly": "!==", "pretty": "\u00a0  \ue10f", "pre": "[^.=:!/<>]|^", "post": "[^.=:!/<>]|$" },
      { "ugly": "=/=", "pretty": "\u00a0  \ue143", "pre": "[^.=:!/<>]|^", "post": "[^.=:!/<>]|$" },
      { "ugly": "<-", "pretty": " \ue152", "pre": "[^<\\->=]|^", "post": "[^<\\-=>]|$" },
      { "ugly": "->", "pretty": " \ue114", "pre": "[^<\\->=]|^", "post": "[^<\\-=>]|$" },
      { "ugly": "<--", "pretty": "\u00a0  \ue153", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "-->", "pretty": "\u00a0  \ue113", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "<->", "pretty": "\u00a0  \ue154", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "<<-", "pretty": "\u00a0  \ue15d", "pre": "[^<\\->=]|^", "post": "[^<\\-=>]|$" },
      { "ugly": "->>", "pretty": "\u00a0  \ue115", "pre": "[^<\\->=]|^", "post": "[^<\\-=>]|$" },
      { "ugly": "=>", "pretty": " \ue13f", "pre": "[^<\\->=]|^", "post": "[^<\\-=>]|$" },
      { "ugly": "<==", "pretty": "\u00a0  \ue158", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "==>", "pretty": "\u00a0  \ue13e", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "<=>", "pretty": "\u00a0  \ue159", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "<=<", "pretty": "\u00a0  \ue15a", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "<<=", "pretty": "\u00a0  \ue15e", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "=>>", "pretty": "\u00a0  \ue140", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": ">=>", "pretty": "\u00a0  \ue146", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": ">>=", "pretty": "\u00a0  \ue149", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": ">>-", "pretty": "\u00a0  \ue148", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": ">-", "pretty": " \ue144", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "-<", "pretty": " \ue116", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "-<<", "pretty": "\u00a0  \ue117", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "=<<", "pretty": "\u00a0  \ue142", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "<~~", "pretty": "\u00a0  \ue161", "pre": "[^<\\->=~]|^", "post": "[^<\\->=~]|$" },
      { "ugly": "<~", "pretty": " \ue160", "pre": "[^<\\->=~]|^", "post": "[^<\\->=~]|$" },
      { "ugly": "~~", "pretty": " \ue168", "pre": "[^<\\->=~]|^", "post": "[^<\\->=~]|$" },
      { "ugly": "~>", "pretty": " \ue167", "pre": "[^<\\->=~]|^", "post": "[^<\\->=~]|$" },
      { "ugly": "~~>", "pretty": "\u00a0  \ue169", "pre": "[^<\\->=~]|^", "post": "[^<\\->=~]|$" },
      { "ugly": "<<<", "pretty": "\u00a0  \ue15f", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "<<", "pretty": " \ue15c", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "<=", "pretty": " \ue141", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "<>", "pretty": " \ue15b", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": ">=", "pretty": " \ue145", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": ">>", "pretty": " \ue147", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": ">>>", "pretty": "\u00a0  \ue14a", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "<\\|", "pretty": " \ue14d", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "<\\|>", "pretty": "\u00a0  \ue14e", "pre": "[^<\\->=|]|^", "post": "[^<\\->=|]|$" },
      { "ugly": "\\|>", "pretty": " \ue135", "pre": "[^<\\->=|]|^", "post": "[^<\\->=|]|$" },
      { "ugly": "<\\$", "pretty": " \ue14f", "pre": "[^<\\->=$]|^", "post": "[^<\\->=$]|$" },
      { "ugly": "<\\$>", "pretty": "\u00a0  \ue150", "pre": "[^<\\->=$]|^", "post": "[^<\\->=$]|$" },
      { "ugly": "\\$>", "pretty": " \ue137", "pre": "[^<\\->=$]|^", "post": "[^<\\->=$]|$" },
      { "ugly": "<\\+", "pretty": " \ue155", "pre": "[^<\\->=+]|^", "post": "[^<\\->=+]|$" },
      { "ugly": "<\\+>", "pretty": "\u00a0  \ue156", "pre": "[^<\\->=+]|^", "post": "[^<\\->=+]|$" },
      { "ugly": "\\+>", "pretty": " \ue13a", "pre": "[^<\\->=+]|^", "post": "[^<\\->=+]|$" },
      { "ugly": "<\\*", "pretty": " \ue14b", "pre": "[^<\\->=*]|^", "post": "[^<\\->=*]|$" },
      { "ugly": "<\\*>", "pretty": "\u00a0  \ue14c", "pre": "[^<\\->=*]|^", "post": "[^<\\->=*]|$" },
      { "ugly": "\\*>", "pretty": " \ue104", "pre": "[^<\\->=*]|^", "post": "[^<\\->=*]|$" },
      { "ugly": "\\\\\\\\", "pretty": " \ue106", "pre": "[^<\\\\\\->=]|^", "post": "[^<\\\\\\->=]|$" },
      { "ugly": "\\\\\\\\\\\\", "pretty": "\u00a0  \ue107", "pre": "[^<\\\\\\->=]|^", "post": "[^<\\\\\\->=]|$" },
      { "ugly": "\\{-", "pretty": " \ue108", "pre": "[^<\\\\\\->={}]|^", "post": "[^<\\\\\\->={}]|$" },
      { "ugly": "-}", "pretty": " \ue110", "pre": "[^<\\->={}]|^", "post": "[^<\\->={}]|$" },
      { "ugly": "//", "pretty": " \ue12f", "pre": "[^<\\->=/]|^", "post": "[^<\\->=/]|$" },
      { "ugly": "///", "pretty": "\u00a0  \ue130", "pre": "[^<\\->=/]|^", "post": "[^<\\->=/]|$" },
      { "ugly": "/\\*", "pretty": " \ue12a", "pre": "[^<\\->=/*]|^", "post": "[^<\\->=/*]|$" },
      { "ugly": "/\\*\\*", "pretty": "\u00a0  \ue12b", "pre": "[^<\\->=/*]|^", "post": "[^<\\->=/*]|$" },
      { "ugly": "\\*\\*/", "pretty": "\u00a0  \ue103", "pre": "[^<\\->=/*]|^", "post": "[^<\\->=/*]|$" },
      { "ugly": "\\*/", "pretty": " \ue105", "pre": "[^<\\->=/*]|^", "post": "[^<\\->=/*]|$" },
      { "ugly": "</", "pretty": " \ue162", "pre": "[^<\\->=/]|^", "post": "[^<\\->=/]|$" },
      { "ugly": "<\\!--", "pretty": "\u00a0 \u00a0\ue151", "pre": "[^<\\->=!]|^", "post": "[^<\\->=!]|$" },
      { "ugly": "</>", "pretty": "\u00a0  \ue163", "pre": "[^<\\->=]|^", "post": "[^<\\->=]|$" },
      { "ugly": "/>", "pretty": " \ue12e", "pre": "[^<\\->=/]|^", "post": "[^<\\->=/]|$" },
      { "ugly": "x", "pretty": "\ue16b", "pre": "[0-9a-fA-F]", "post": "[0-9a-fA-F]" },
      { "ugly": ":", "pretty": "\ue16c", "pre": "[0-9]{1,2}", "post": "[0-9]{1,2}" },
      { "ugly": "\\+", "pretty": "\ue16d", "pre": "[0-9a-zA-Z]", "post": "[0-9a-zA-Z]" },
      { "ugly": "-", "pretty": "-", "pre": "[0-9a-zA-Z]", "post": "[0-9a-zA-Z]" },
      { "ugly": "\\*", "pretty": "*", "pre": "", "post": "" },
      { "ugly": "www", "pretty": "\u00a0  \ue100", "pre": "\\b", "post": "\\b" },
      { "ugly": ";;", "pretty": " \ue129", "pre": "[^;]|^", "post": "[^;]|$" },
      { "ugly": "::", "pretty": " \ue10a", "pre": "[^:]|^", "post": "[^:]|$" },
      { "ugly": ":::", "pretty": "\u00a0  \ue10b", "pre": "[^:]|^", "post": "[^:]|$" },
      { "ugly": "!!", "pretty": " \ue10d", "pre": "[^!]|^", "post": "[^!]|$" },
      { "ugly": "\\?{2}", "pretty": " \ue128", "pre": "[^?]|^", "post": "[^?]|$" },
      { "ugly": "%%", "pretty": " \ue16a", "pre": "[^%]|^", "post": "[^%]|$" },
      { "ugly": "&&", "pretty": " \ue131", "pre": "[^&]|^", "post": "[^&]|$" },
      { "ugly": "\\|{2}", "pretty": " \ue132", "pre": "[^|=]|^", "post": "[^|=]|$" },
      { "ugly": "\\.{2}", "pretty": " \ue124", "pre": "[^.<]|^", "post": "[^.<]|$" },
      { "ugly": "\\.{3}", "pretty": "\u00a0  \ue126", "pre": "[^.<]|^", "post": "[^.<]|$" },
      { "ugly": "\\.\\.<", "pretty": "\u00a0  \ue125", "pre": "[^.<]|^", "post": "[^.<]|$" },
      { "ugly": "\\[\\]", "pretty": " \ue109", "pre": "[^[\\]]|^", "post": "[^[\\]]|$" },
      { "ugly": "--", "pretty": " \ue111", "pre": "[^\\-+*=<>~]|^", "post": "[^\\-+*=<>~]|$" },
      { "ugly": "---", "pretty": "\u00a0 \ue112", "pre": "[^\\-+*=<>~]|^", "post": "[^\\-+*=<>~]|$" },
      { "ugly": "\\+{2}", "pretty": " \ue138", "pre": "[^\\-+*=<>~]|^", "post": "[^\\-+*=<>~]|$" },
      { "ugly": "\\+{3}", "pretty": "\u00a0  \ue139", "pre": "[^\\-+*=<>~]|^", "post": "[^\\-+*=<>~]|$" },
      { "ugly": "\\*{2}", "pretty": " \ue101", "pre": "[^\\-+*=<>~]|^", "post": "[^\\-+*=<>~]|$" },
      { "ugly": "\\*{3}", "pretty": "\u00a0  \ue102", "pre": "[^\\-+*=<>~]|^", "post": "[^\\-+*=<>~]|$" },
      { "ugly": "~=", "pretty": " \ue166", "pre": "[^~=\\-]|^", "post": "[^~=\\-]|$" },
      { "ugly": "~-", "pretty": " \ue165", "pre": "[^~=\\-<>]|^", "post": "[^~=\\-<>]|$" },
      { "ugly": "-~", "pretty": " \ue118", "pre": "[^~=\\-<>]|^", "post": "[^~=\\-<>]|$" },
      { "ugly": "~@", "pretty": " \ue164", "pre": "[^~=\\-@~]|^", "post": "[^~=\\-@~]|$" },
      { "ugly": "\\^=", "pretty": " \ue136", "pre": "[^~=\\-^]|^", "post": "[^~=\\-^]|$" },
      { "ugly": "\\?=", "pretty": " \ue127", "pre": "[^~=\\-/?]|^", "post": "[^~=\\-/?]|$" },
      { "ugly": "/=", "pretty": " \ue12c", "pre": "[^~=\\-/]|^", "post": "[^~=\\-/]|$" },
      { "ugly": "/==", "pretty": "\u00a0  \ue12d", "pre": "[^~=\\-/]|^", "post": "[^~=\\-/]|$" },
      { "ugly": "\\|=", "pretty": " \ue134", "pre": "[^~=\\-/|]|^", "post": "[^~=\\-/|]|$" },
      { "ugly": "\\|{2}=", "pretty": "\u00a0  \ue133", "pre": "[^~=\\-/|]|^", "post": "[^~=\\-/|]|$" },
      { "ugly": "##", "pretty": " \ue11b", "pre": "[^#_?({[\\]]|^", "post": "[^#_?({[\\]]|$" },
      { "ugly": "###", "pretty": "\u00a0  \ue11c", "pre": "[^#_?({[\\]]|^", "post": "[^#_?({[\\]]|$" },
      { "ugly": "####", "pretty": "\u00a0\u00a0 \ue11d", "pre": "[^#_?({[\\]]|^", "post": "[^#_?({[\\]]|$" },
      { "ugly": "#{", "pretty": " \ue119", "pre": "[^#_?({[\\]]|^", "post": "[^#_?({[\\]]|$" },
      { "ugly": "#\\[", "pretty": " \ue11a", "pre": "[^#_?({[\\]]|^", "post": "[^#_?({[\\]]|$" },
      { "ugly": "#\\(", "pretty": " \ue11e", "pre": "[^#_?({[\\]]|^", "post": "[^#_?({[\\]]|$" },
      { "ugly": "#\\?", "pretty": " \ue11f", "pre": "[^#_?({[\\]]|^", "post": "[^#_?({[\\]]|$" },
      { "ugly": "#_", "pretty": " \ue120", "pre": "[^#_?({[\\]]|^", "post": "[^#_?({[\\]]|$" },
      { "ugly": "#_\\(", "pretty": "\u00a0  \ue121", "pre": "[^#_?({[\\]]|^", "post": "[^#_?({[\\]]|$" }
    ]
  }
]
ghost commented 8 years ago

@siegebell There's a bug and i'm not sure whether it is fira code or emacs.

So with font set to Fira Code and setting the fontset to use fira code symbol for \ue100 to \ue16f I'm getting some weird behavior.

The symbols appear to the left of the original text a significant amount. So, for instance, if I do <-- as the first text on the line i'll get most of it rendering off the left side of the screen. Including emacs config and screenshot here, not yet sure what the problem is.

Edit: If there is other text to the left this bug will actually cause the symbol to overlap with the text!

Edit2: Loading it with no other emacs config has the same effect so shouldn't be some package interfering. In addition, it looks like it is about two spaces/characters to the left of where it should be.

Edit3: I see now that you are dealing with this via \u00a0 in the vscode config? Not sure if I can do that with emacs or not.

Emacs config:

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

(set-fontset-font t '(#Xe100 . #Xe16f) "Fira Code Symbol")

(defconst fira-code-font-lock-symbols-alist
  (mapcar (lambda (s)
            (cons (car s) (decode-char 'ucs (car (cdr s)))))
          (list '("www" #Xe100)
                '("<--" #Xe153))))

(add-hook 'prog-mode-hook
          (lambda ()
            (dolist (alias fira-code-font-lock-symbols-alist)
              (push alias prettify-symbols-alist))
            (prettify-symbols-mode)))

fira-code-emacs-bug

ghost commented 8 years ago

@siegebell So this definitely looks like it is because emacs expects to be replacing multiple characters with a character with a width of one where as the fira code symbols are designed to take up multiple character widths. Haven't yet figured out a solution.

ghost commented 8 years ago

Found an uglier way that works.

(add-hook 'prog-mode-hook
          (lambda ()
            (font-lock-add-keywords nil
                                    `(("\\(###\\)"
                                       (0 (prog1 ()
                                            (compose-region (match-beginning 1)
                                                            (match-end 1)
                                                            ;; The first argument to concat is a string containing a literal tab character inserted via C-q <tab>. It is important!
                                                            ,(concat "  " (list (decode-char 'ucs #Xe11c)))))))))))

I'm going to turn it into a helper function then I just need to figure out emacs's awful regex syntax for each thing and we should be good.

tonsky commented 8 years ago

@mordocai FYI in Fira symbols visually take multiple character places but marked as taking just one (rightmost) single place:

screen shot 2016-08-11 at 13 14 42

So in fact when I do ligature substitution in font code, I replace e.g. hyphen hyphen greater with space space hyphen_hyphen_greater.liga (CR stands for space):

    sub CR CR greater' by hyphen_hyphen_greater.liga;
    sub CR hyphen' greater  by CR;
    sub hyphen' hyphen  greater  by CR;

The reason for that is that editors will still see result of substitution as three single-width characters, and will allow to “step inside” the ligature glyph. Without that, ligature will act as it’s a single character, which changes editing behaviour which we want to avoid. We want to keep feeling that substitution is purely visual and underlying code is there unchanged.

The downside of that is that glyphs span outside their container. This is usually perfectly fine with all known editors, but might surprise anyone who tries to use them directly without knowing about that gotcha.

Hope that helps.

ghost commented 8 years ago

@tonsky Yeah, I ended up figuring out what was going on! Luckily the new way I'm doing it with emacs knows how to handle things like that by using a special string beginning with a tab.

Everyone: I got it working! Here is the emacs code:

https://gist.github.com/mordocai/50783defab3c3d1650e068b4d1c91495

Linking to gist so I can update it later if necessary.

Edit: Screenshot. Also, sorry for spamming this issue so bad. I kept thinking I was going to give up for the night, but then didn't... fira-code-emacs-working

emmanueltouzery commented 8 years ago

@mordocai thanks for the work! I tried the gist but I get mostly garbage. See the picture. Maybe I'm using the wrong version of the font or something? I'm pretty sure I'm using 0.200 although I did install older versions in the past.

EDIT OK SORRY IT WORKS. Need to install the Fira code symbol font additionnally. The "x" does look weird, in "Text" for instance. It's replaced by a cross. Also the ligature for =<< doesn't work while fira code appears to support it.

emmanueltouzery commented 8 years ago

to fix the =<< in the gist =>

          ("\\(=<<\\)"                   #Xe142)    (changed from ==<)
          ("[^-=]\\(<<\\)"               #Xe15c)    (excluded the = before the << as well)

this is for the overzealous cross:

          ;; ("\\(x\\)"                     #Xe16b)

would need to require non-word characters before & after but my emacs regex-fu is weak for that, so I just commented that locally.

siegebell commented 8 years ago

For example, this should only match 'x' if the preceding character is a number and the subsequent character is either a number or letter:

          ("[0-9]\\(x\\)[0-9a-fA-F]"                     #Xe16b)

edit: changed a-F to a-f

emmanueltouzery commented 8 years ago

@siegebell i think the ideal would be a "word boundary" regex before & after the x. I was a bit lazy earlier, but this seems to work great =>

          ("\\b\\(x\\)\\b"               #Xe16b)
emmanueltouzery commented 8 years ago

hmm actually the 'x' just bothers me :-) in haskell we often use the 'x' variable (x:xs) and that triggers it. I'll keep that line commented for my use.

ghost commented 8 years ago

Updated my gist with @emmanueltouzery's changes. I also had ended up commenting out the the X so I included that too.

siegebell commented 8 years ago

@emmanueltouzery that's why I didn't use \b :)

Anyhow, the advantage of prettify-symbols-mode is that every user can easily pick & choose their favorite substitutions. And fancy 0xFF notation is useful in only a few kinds of projects.

emmanueltouzery commented 8 years ago

@siegebell ohhh... that 'x' was for hex numbers!!! I totally didn't get it. I thought some languages use it for multiplication or something like that, so I didn't undersand your regex. I thought you were trying to be helpful by showing some generic example of regex =D Then maybe your regex should be used instead.

emmanueltouzery commented 8 years ago

enabled @siegebell 's 'x' regex for me locally. There is a little typo, @siegebell put a-FA-F instead of a-fA-F btw (so it only worked for uppercase hex digits).

otherwise I agree this mode is great. You can enable per-mode and per-glyph. It's just great. And also you can combine the symbols with other fonts. I'm actually using these new symbols in combination with the usual fira mono, NOT with the base fira code!

Probably we should update the FiraCode wiki with these instructions? The question is whether this way works also on OSX? Do we have two sets of instructions, OSX & linux or we just put these new instructions for all emacs versions? This way requires to install a separate font which @tonsky may not be willing to support in the future. On the other hand, the OSX-specific way seems to cause all kinds of hangs in all kinds of situations...

siegebell commented 8 years ago

@emmanueltouzery there's no particular reason why this needs to be a separate symbols font. I created it this way for expediency/convenience because the free font editor I have access to, Font Forge, is a buggy UI-nightmare to work with. Creating a separate [symbols] font is best suited for when you want to add glyphs to a non-free font that you cannot redistribute, but this approach is limited to text editors that support font fallback.

I think it would be best for @tonsky to merge these changes back into Fira Code to avoid needless forking. (I would submit a PR if only I could run the trial of Glyphs App on Windows...)

emmanueltouzery commented 8 years ago

some feedback after using @siegebell & @mordocai 's solution daily for a while: it works great, two little things.

  1. The regex for substitution should probably blacklist symbols which can repeat more times than the symbol covers. For instance ";;;" doesn't look good, we get ";; ;". Ideally the regex for substitution should be something like ";;[^;]" or something like that. Same for some others, like "##", "//", "!!!" and probably more. I am currently too lazy to deal with it :-p
  2. that's a tougher one: company completion renders completion combos as ascii art more or less. Ligatures/glyph substitution breaks expectations that company makes and the completion combos end up looking ugly (see screenshot). I guess there's no easy fix for that.

screenshot from 2016-09-04 11-42-52

I'm still keeping it

davidar commented 8 years ago

@emmanueltouzery It looks like there might be a problem with the widths of the ligatures in your screenshot (they should be an integer multiple of the normal character width)

siegebell commented 8 years ago

@emmanueltouzery most of the ugliness in the regex I posted was essentially "blacklisting"; applying a substitution only when it is clearly not part of a larger symbol [which may have no ligature]. Converting it to emacs regex should look something like ("${pre}\\(${ugly}\\)${post}" ${unicodeSymbol}). Most of it has been left out of @mordocai's translation to emacs, probably because it was very tedious and [I suppose] he chose to only keep "blacklisting" for the more likely collisions in found in Haskell programming.

ghost commented 8 years ago

@siegebell Actually ruby/javascript/lisp programming but otherwise correct :). Since emacs regexes are different it was a pain to copy the originals and modify them so instead I just made new ones from scratch and I didn't check for all such "blacklisting". It hasn't bothered me too much, so far, so I haven't fixed it.

As far as the widths, i've noticed using the "tab as first character to compose-region string argument" method in emacs, described in docs as

If it is a string, the elements are alternate characters. In this case, TAB element has a special meaning. If the first character is TAB, the glyphs are displayed with left padding space so that no pixel overlaps with the previous column. If the last character is TAB, the glyphs are displayed with right padding space so that no pixel overlaps with the following column.

Doesn't seem to line up the columns correctly, which may also be the issue with company. Currently its doing the tab as the first character(so left padding space), i haven't tried tab as last character (so right padding space). If right padding space is just as bad/doesn't work(my guess is it won't work), may be best to try and use the unicode spaces like @siegebell did in the other examples. The function (and configuration) will need to take an extra argument for number of spaces to add though, if that is the case.

dominikh commented 7 years ago

@mordocai using TAB doesn't seem to be a perfect solution, either. TAB makes sure that the replacement doesn't overlap with the previous column, but it still gets spacing wrong for the || ligature. Doing x||y will show it noticeably closer to x than to y, as opposed to the centered look it should have.

clembu commented 7 years ago

Okay folks. This is all great. I thank you very much for your work.

But I'm now wondering, would you go about updating @siegebell 's font with the new ligatures? It'd be awesome if this font could be updated with Fira Code.

ice1000 commented 7 years ago

What about <~>?

ghost commented 7 years ago

It's inconvenient that emacs users only get a very dated version of the font, is there any reason for not including the ligatures in private area of official releases?

tonsky commented 7 years ago

I’m planning to do that in the next Fira Code version

Alexx-G commented 6 years ago

What's the situation on this? Does somebody have an actual and working snippet? The info is quite fragmented and some of gists are deleted. So far, I didn't manage to put everything together to get a properly working solution.

Alexx-G commented 6 years ago

Update: This one works properly and doesn't hang Emacs comparing to the solution from Wiki. https://github.com/Profpatsch/blog/blob/master/posts/ligature-emulation-in-emacs/post.md#appendix-b-update-1-firacode-integration

tonsky commented 6 years ago

Thx! Added it to https://github.com/tonsky/FiraCode/wiki/Emacs-instructions

reiver-dev commented 6 years ago

Followed current instructions to make it work for my emacs setup. Results:

Gist with implementation: https://gist.github.com/reiver-dev/82da77ba3f0008c56624661a7375e0e8 Patched font files: FiraCode-private-area.zip

emacs-pretty-fira-code

ghost commented 6 years ago

@reiver-dev

Is it possible for you to supply the patched font? Or possibly add it to the emacs-instructions?

reiver-dev commented 6 years ago

@lshoravi

Updated previous comment with an archive with fonts. It lacks some one-symbol ligatures though.

NeQuissimus commented 6 years ago

Very cool, @reiver-dev ! Using it right now :) It would be awesome to have this in the standard font, though.

zbeekman commented 6 years ago

I had been following the instructions at https://github.com/tonsky/FiraCode/wiki/Emacs-instructions to enable FiraCode ligatures in Emacs. Specifically I had followed the 2nd set of instructions that reference this issue and the author had success with emacs 24.5.1 on Debian Linux. I am on macOS (High Sierra) and this had been working for me.

However, I recently updated either Emacs or FiraCode (via Homebrew) or both to Emacs Version 25.3 (9.0) and FiraCode 1.205 and this stopped working. I can't figure out why. I tried reinstalling the FiraCode unicode private area font files, but still no dice. I also tried the other solutions on the wiki without any luck.

Does anyone know how to get FiraCode working with Emacs 25.3 on macOS?

xerz-one commented 6 years ago

Hey, out of curiosity, what's stopping the ligature glyphs from being moved to the private area? Is there any blocking issue?

tonsky commented 6 years ago

Hey, out of curiosity, what's stopping the ligature glyphs from being moved to the private area? Is there any blocking issue?

just lack of time

Qqwy commented 6 years ago

@reiver-dev Is it possible to alter the script somewhat, such that the cursor, when moving through the code, will consider two-glyph ligatures as two characters wide (and similar for three-glyph ligatures)?

reiver-dev commented 6 years ago

@Qqwy The script just creates references in reserved plane to existing ligature glyphs without any changes to glyphs. It might be possible to automatically modify ligatures, but this looks as a font change.

wedens commented 6 years ago

Is there updated "Fira Code Symbol" font with new ligatures?

ogonki-vetochki commented 5 years ago

@tonsky Yeah, I ended up figuring out what was going on! Luckily the new way I'm doing it with emacs knows how to handle things like that by using a special string beginning with a tab.

Everyone: I got it working! Here is the emacs code:

https://gist.github.com/mordocai/50783defab3c3d1650e068b4d1c91495

Linking to gist so I can update it later if necessary.

Edit: Screenshot. Also, sorry for spamming this issue so bad. I kept thinking I was going to give up for the night, but then didn't... fira-code-emacs-working

What was there?! 😢 (link to gist is broken)

To1ne commented 5 years ago

What was there?! 😢 (link to gist is broken)

@ogonki-vetochki I did an attempt to put all info on the Wiki: https://github.com/tonsky/FiraCode/wiki/Emacs-instructions

Normally everything is there. It's taken from @reiver-dev's instructions, which I guess is an improved version of the broken gist.


This issue only remains open cause the official "build" of the font does not include symbols in the private Unicode plane (as the title suggests).

rohit507 commented 5 years ago

How can we generate the fira-symbol font from the current version of fira-code?

TheAntimist commented 5 years ago

Hey, out of curiosity, what's stopping the ligature glyphs from being moved to the private area? Is there any blocking issue?

@tonsky Has there been any update to this request? It'd be great if we could get this for the latest release of FiraCode.

tonsky commented 5 years ago

I’ll plan it for the next update

TheAntimist commented 5 years ago

@tonsky Thanks, glad to hear that. I found out only recently, I believe that emacs27 is adding support for HarfBuzz, and also possibly proper ligature support too. [1] Not sure if this change should be made, after finding that out.

[1] https://www.reddit.com/r/emacs/comments/byddvm/emacsdevel_harfbuzz_is_now_available_on_master/eqi90r8/?context=1

clembu commented 5 years ago

emacs27 is still a long way though it feels

wedens commented 5 years ago

And ligatures support is unlikely to be implemented until emacs28 https://www.reddit.com/r/emacs/comments/dcryg1/tab_support_landed_in_emacs_master/f2kevco/

DogLooksGood commented 4 years ago

Just given a try, almost everything looks great, but the some symbol like .- will only work when it is the whole word, it won't work in something like .-a.