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

Ligature support #601

Closed
lf- opened this issue Oct 10, 2016 · 71 comments
Closed

Ligature support #601

lf- opened this issue Oct 10, 2016 · 71 comments

Comments

@lf-
Copy link

lf- commented Oct 10, 2016

It would be really nice to be able to use ligatures in fonts like Iosevka and Fira Code with mintty.

Currently, it seems that ligatures are not displayed.

@mintty
Copy link
Owner

mintty commented Oct 10, 2016

This may be beyond the Windows API currently used for text output (ExtTextOut), see #430 and #438 (comment).
Please describe more precisely what you are missing and what you see (e.g. rendered "fl" desired to be ligature ?).

@lf-
Copy link
Author

lf- commented Oct 10, 2016

Fira Code has some crazy ligatures for programming while remaining a
monospace font. -> is a ligature, so is ==.

The issue is that the raw characters are displayed and not the ligatures.

@mintty
Copy link
Owner

mintty commented Oct 10, 2016

So you are not asking about any Unicode ligatures but rather font-specific ligatures.
I am not aware which Windows API, if any, would be able to handle them implicitly.
So it might be necessary to handle font information explicitly in mintty to achieve that.
You are welcome to make a proposal how to implement that.

@mintty
Copy link
Owner

mintty commented Oct 11, 2016

This functionality may be available with the Uniscribe API.
Handling the complexity of that API is however beyond my current ambition to enhance mintty.

@mintty
Copy link
Owner

mintty commented Oct 18, 2016

So here's your homework :):

  • Either find any application with source code that implements this, find how it detects which character pairs have ligatures (mapping them to font glyphs).
  • Or find out how the TrueType cmap tables can be retrieved using the Windows API and which table contains the ligature information.

@mintty
Copy link
Owner

mintty commented Oct 20, 2016

@be5invis: taking over this issue here...

You cannot enable ligatures unless you switch from GDI to DirectWrite or FreeType.

FreeType is an external library, and DirectWrite as well as Uniscribe are of deterring complexity. I've experimented with Uniscribe, though, and it does not seem to support ligatures (so I guess notepad uses DirectWrite...).

But: The information must be available somewhere in the font file. And using a mapping table like
('-', '>', '⟶') mintty could output those glyphs by glyph index rather than character code, like it does for right-to-left text already.

@be5invis
Copy link

@mintty Uniscribe does not support enabling arbitrary OpenType feature tag unless it is one of the “required” tags for typesetting complex scripts (like Devanagari).

@mintty
Copy link
Owner

mintty commented Oct 20, 2016

@be5invis Thanks for the confirmation.
What about the ligature information; isn't it available as a "table" in TrueType? Any idea how to access it?

@be5invis
Copy link

@mintty It’s a feature located in GSUB table, and it is corresponded to a list of lookups. For most programming fonts, the feature is tagged as calt.

@mintty
Copy link
Owner

mintty commented Oct 20, 2016

Hmm, using a ttfdump tool, Iosevka doesn't seem to have any calt entries, and Fira Code has only 16 of them, looking as mysterious as this:

'calt'
FeatureT07b6
                      ; FeatureRecord[17]
...
Feature FeatureT07b6
NULL
3
25
26
27

Probably not worth the effort...

@be5invis
Copy link

be5invis commented Oct 20, 2016

@mintty To avoid some compatibility issues under Linux, Iosevka Term turned off ligatures by default.
A feature is (usually) an array of lookup indexes, indicates if this feature is enabled, which of the lookups should be set to active.

@mintty
Copy link
Owner

mintty commented Oct 20, 2016

"By default" means the information is not contained in the font?

Whatever, I think I'll just close this issue unless someone enthusiastic about the feature will

  • demonstrate how it would be useful for at least a few fonts, and not for just 16 characters of one strange font (just look at the ugly 'm' of Fira Code!)
  • provide code how to retrieve a suitable mapping table from a TrueType font (starting with the GDI function GetFontData) because I'm not going to dig into the incredibly over-engineered insanity of the TrueType format myself (that person would gain a place on the mintty credits page, of course)

@be5invis
Copy link

@mintty Iosevka Term does not have any ligature data, while Iosevka does.

In most cases, the calt is implemented as a contextual substitution, which means that it will try to match a glyph sequence, and apply some other lookups (usually a single substitution, or a multiple-to-one substitution) to the specified position of the match. It is really hard to interpret it, especially you are on GDI.

@mintty
Copy link
Owner

mintty commented Oct 20, 2016

  • provide code how to retrieve a suitable mapping table from a TrueType font

or make an implementation proposal to use DirectWrite, see #430

@k-takata
Copy link
Contributor

DirectWrite has GDI compatible mode. If you use it, you don't need to switch all graphics code to Direct2D.
Vim 8.0 also uses it: https://github.com/vim/vim/blob/master/src/gui_dwrite.cpp

@mintty mintty mentioned this issue Nov 15, 2016
@mintty
Copy link
Owner

mintty commented Nov 15, 2016

In referring issue #605, I tried to evaluate Uniscribe for this purpose.
About DirectWrite, thanks to @k-takata for referring to that example, but I'm not going to reverse-engineer 900 lines of code to understand that nightmare of an API, sorry.
If anyone comes up with a half-way working demo solution using either Uniscribe or DirectWrite, that will help.

@riedel
Copy link

riedel commented Oct 1, 2017

Maybe @koron can help figuring this out for mintty, too. Would also be a major break-though for vim users (like me) that rather use the command line on windows (ie. cygwin). Sorry for bumping this issue: still one year later there seems to be no actual terminal (that can e.g. run tmux) on windows with ligature support.

@k-takata
Copy link
Contributor

k-takata commented Oct 1, 2017

Mintty already uses Uniscribe. I don't think there is additional benefit by using DirectWrite with GDI-compatible mode.

@mintty
Copy link
Owner

mintty commented Oct 1, 2017

I think @riedel was referring to ligature support, not DirectWrite.
Uniscribe does not seem to provide it, at least not implicitly.

@k-takata
Copy link
Contributor

k-takata commented Oct 1, 2017

Oh, I misunderstood that Uniscribe provides (some kind of) ligature support.

@riedel
Copy link

riedel commented Oct 2, 2017

@k-takata: you are right: tt seems that uniscribe supports ligatures, but not the type of OpenType ligatures eg. used by Fira Code.

This uniscribe tutorial shows that ScriptStingOut does not work: https://www.catch22.net/tuts/introduction-uniscribe .

https://maxradi.us/documents/uniscribe/ talks about font-specific ligature and how to use the more complex workflow using ScriptShape to compute ligatures, but I think this also does not apply to Opentype ligatures. Butit seems unlikely that this API level works any better.

Edit 2: This slightly more complex API seems to do the trick and works with Fira Code: https://www.catch22.net/tuts/drawing-styled-text-uniscribe

Edit 1: Windows offers some OpenType specific uniscribe functions: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317792(v=vs.85).aspx

@riedel
Copy link

riedel commented Oct 28, 2017

I accidentally just saw that sometimes ligatures are actually working:

firacode

@mintty
Copy link
Owner

mintty commented Oct 28, 2017

What's the actual output rendered here? Can you provide a screen log please (e.g. mintty -l)?

@riedel
Copy link

riedel commented Nov 11, 2017

I ran mintty -l x.txt sh -c "head -204 Developer_Space%2FStandards.mw|tail -1", which gives you only the relevant line. I confirmed that it renders the ligature (only in the beginning but not the end of the line)

This is the output:
x.txt

I was on the train writing a document at the time and wasn't looking any further. Now I looked into it because it worked for none of the other lines, which seemed strange: it seems that the long dash (hex sequence 0xe28094) in the line triggers rendering the ligatures (others ligatures from fira code work as well). Should be easy to replicate...

@mintty
Copy link
Owner

mintty commented Nov 11, 2017

This is a miracle of Uniscribe, I don't think mintty has control over it. However, some observations:

  • with -o FontRender=textout, no ligatures are applied
  • both a wrapped line (longer than the screen width) and the em dash are needed to trigger the leading ligature
  • if the line is shortened to screen width, there is a break before the dash, i.e. mintty outputs the line in chunks (as can be seen with #define debug_win_text in wintext.c), and no ligature is applied if the chunk is only "=== Information technology "

@mintty
Copy link
Owner

mintty commented Dec 3, 2018

They are not really special, but somewhat ambiguous if ligatures are available e.g. for <= which could become either or . However, if there is ever a choice between such alternatives, it would be made either by the font or by the Windows framework (Uniscribe), not by mintty.

@mintty
Copy link
Owner

mintty commented Dec 3, 2018

Actually, the previous comment applies e.g. to <= but not to <-. The subtle background is that - has a different bidi class, so mintty breaks its output there, in order to make sure right-to-left output is properly separated. If that's your use case, please state that explicitly, and maybe provide some more test cases for which you are missing ligatures. However, I don't see right now how that could be handled easily.

@scfrazer
Copy link

scfrazer commented Dec 5, 2019

I understand there are good reasons not to do ligatures for things like '=>' because of all the use cases you want to support, but I would like to have them in a private fork for my personal use. I am building mintty myself and have poked around in the code trying to figure out how to enable the extra ligatures I'd like, but I'm not having much luck. It seems like it should be in src/term.c somewhere, but the changes I have tried so far (including turning on verbose debug output) haven't worked. Can you point me in the right direction? Thanks!

@mintty
Copy link
Owner

mintty commented Dec 5, 2019

As a special hack for <-, -> and other combinations with -, you could try to disable line
{0x002D, 0x002D, ES},
in file bidiclasses.t. If that's what you want, we could consider to reduce the number of cases of setting break_run in term.c, particularly depending on bidi_class in lines that do not set has_rtl.

@scfrazer
Copy link

scfrazer commented Dec 5, 2019

Thanks, but removing that line didn't seem to change things. I pulled the latest code, did 'make clean && make', I assume that's all that is needed. I'm sure the font family supports ligatures for '->' ... if I open the test file I am using in Notepad the arrow is displayed.

@mintty
Copy link
Owner

mintty commented Dec 6, 2019

I verified that "<-" is in fact handed over to Uniscribe for output in one bunch, even without that patch, actually.
Maybe some parameters to the Uniscribe functions (wintext.c) would make a difference?

@chiefjester
Copy link

hey, @mintty 👋 Mintty is awsome! I've been trying your terminal out and it mostly checks all my list for a terminal. The last is Ligature Support which it seems that mintty actually supports.

I try to edit the shortcut
C:\Users\username\AppData\Local\wsltty\bin\mintty.exe -o Padding=200 -o LigaturesSupport=2 --WSL= --configdir="C:\Users\username\AppData\Roaming\wsltty" -~ -

Am I doing it correctly? I'm using Cascadia Code which supports ligature, but it seems that it doesn't work.

@mintty
Copy link
Owner

mintty commented Dec 25, 2019

The release page says:

As in 1911.20, this release includes Cascadia Mono, a version of Cascadia that doesn't have ligatures

@chiefjester
Copy link

Hi @mintty, thanks for getting back with me. Happy Holidays! 🤗 I'm not using Cascadia Mono, I'm using Cascadia Code which does include ligatures.

As you see in the release, there are six assets,

  1. Cascadia -> with ligatures
  2. Cascadia Mono -> without ligatures
  3. Cascadia Mono PL -> without ligatures but with patched with powerline.
  4. Cascadia PL -> with ligatures patched with powerlines
  5. Source Code in .zip format
  6. Source Code in tar.gz format

I'm using no. 1.
Alt text

@Biswa96
Copy link
Contributor

Biswa96 commented Dec 26, 2019

Install Cascadia Code, set it default in mintty, run this:

mintty.exe -o LigaturesSupport=1 -e wslbridge2.exe

Works in my case.

@mintty
Copy link
Owner

mintty commented Dec 26, 2019

Yes, it works. If you experience any special cases that don't, describe them.

@chiefjester
Copy link

chiefjester commented Dec 27, 2019

If I use what @Biswa96 suggested I get an error:
Alt text

I tried playing with the settings thru the shortcut:
C:\Users\username\AppData\Local\wsltty\bin\mintty.exe -o Padding=200 -o LigaturesSupport=1 --WSL= --configdir="C:\Users\username\AppData\Roaming\wsltty" -~ -

It somewhat works with that configuration but it's missing converting some ligatures.

For eg.:
=> and -> doesn't work/transform.

Alt text

edit: I just realized I'm using wsltty. But it does use mintty under the hood.

@chiefjester
Copy link

I tried using Fira Code, which doesn't work either. I've also tried: LigaturesSupport=2 (which I found in this PR f35aa2a)

Using Fira Code:
Alt text

@mintty
Copy link
Owner

mintty commented Dec 27, 2019

OK, your report was it doesn't work. As you see in your line (foo == true), it does work.
Please check the discussion above for specific combinations that are not combined into a ligature.
I might add a summary to the documentation.

@chiefjester
Copy link

oh okay @mintty sorry about that, so basically mintty has partial support of ligatures? Looking forward to the summary thanks again for the great work. 🙏🏻

@scfrazer
Copy link

I verified that "<-" is in fact handed over to Uniscribe for output in one bunch, even without that patch, actually.
Maybe some parameters to the Uniscribe functions (wintext.c) would make a difference?

Sorry for the slow response, life got in the way.

I finally got it to work! I played around with the Uniscribe parameters as you suggested, and the extra ligatures I wanted appeared when I passed in some different flags for the SCRIPT_CONTROL parameter in ScriptStringAnalyse:

  SCRIPT_CONTROL sctrl;
  ZeroMemory(&sctrl, sizeof(SCRIPT_CONTROL));
  sctrl.fMergeNeutralItems = 1;
  HRESULT hr = ScriptStringAnalyse(hdc, psz, cch, 0, -1,
    // could | SSA_FIT and use `width` (from win_text) instead of MAXLONG
    // to justify to monospace cell widths;
    // SSA_LINK is needed for Hangul and default-size CJK
    SSA_GLYPHS | SSA_FALLBACK | SSA_LINK, MAXLONG,
    &sctrl, NULL, dxs, NULL, NULL, &ssa);

Is this something you would want to incorporate, or should I maintain my own fork?

@BrianInglis
Copy link

Add another bit setting to enable this in LigaturesSupport?

@mintty
Copy link
Owner

mintty commented Feb 16, 2020

Thanks for digging this out. No forks, please, I'll add that to the code. But it can only be an option, due to the ambiguity discussed before, see the marked case in the screenshot:
grafik
Any idea how to tackle this (and other?) cases?
Should it be a distinct option or a bitmask variation as Brian suggested?

@mintty mintty reopened this Feb 16, 2020
@scfrazer
Copy link

Thanks for adding it as an option, I didn't want to have to keep up with all your releases.

Regarding the ambiguity, I imagine the common case of, say, '<=' is less-than-or-equal-to, not double-arrow-pointing-left. The only way I see around it is if you think it is worthwhile to write code to scan blocks, potentially break them up, and feed them to Uniscribe with different options. I suggest starting out with everything on or off, and see if many people ask for fine-grained control. FWIW, all the other programs I have tried go the less-than-or-equal-to glyph route.

For the option, you could hedge your bet about people wanting more control and have another option that is a bitmask. One bit for 'all ligatures on', and in the future other bits could be 'double-arrow-pointing-left on'.

@mintty
Copy link
Owner

mintty commented Feb 16, 2020

I wouldn't know how to persuade Uniscribe to render <= as left-arrow.

The current option is about interactive line rendering support (i.e. rendering while typing), which isn't yet perfect actually.
The new option would be about the range of ligatures to enable, so a bit different - maybe it should be a separate option Ligatures then.

@mintty
Copy link
Owner

mintty commented Feb 25, 2020

Released 3.1.4.

@mintty mintty closed this as completed Feb 25, 2020
@ghost
Copy link

ghost commented Feb 25, 2020

Nice, is wsltty going to be updated? (Also you forgot to actually release 3.1.0.3.)

@mintty
Copy link
Owner

mintty commented Feb 25, 2020

There is a bug with crash potential in the wslbridge gateway. Waiting for its fix.

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

No branches or pull requests