diff options
author | Yee Cheng Chin <ychin.git@gmail.com> | 2023-10-05 20:54:21 +0200 |
---|---|---|
committer | Christian Brabandt <cb@256bit.org> | 2023-10-05 20:54:21 +0200 |
commit | 290b887e8cc2c0d3dfc7f315b2052472c7c589cc (patch) | |
tree | 1b5285384cc6ed9e3a0bce9051d1e4b201196161 /src/os_mswin.c | |
parent | ea746f9e862092aef3d4e95c64d116759b9fabe0 (diff) |
patch 9.0.1991: no cmdline completion for setting the fontv9.0.1991
Problem: no cmdline completion for setting the font
Solution: enable it on Win32 and GTK builds
Add guifont cmdline completion (for Windows and GTK)
For Windows, auto-complete will only suggest monospace fonts as that's
the only types allowed. Will also suggest font options after the colon,
including suggesting the current font size for convenience, and misc
charset and quality options like `cANSI` and `qCLEARTYPE`.
For GTK, auto-complete will suggest only monospace fonts for `guifont`
but will include all fonts for `guifontwide`. The completion code
doesn't currently suggest the current font size, as the GTK guifont
format does not have a clear delimiter (':' for other platforms).
closes: #13264
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
Diffstat (limited to 'src/os_mswin.c')
-rw-r--r-- | src/os_mswin.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/os_mswin.c b/src/os_mswin.c index aa5fe5243e..46f73752f9 100644 --- a/src/os_mswin.c +++ b/src/os_mswin.c @@ -2819,6 +2819,32 @@ points_to_pixels(WCHAR *str, WCHAR **end, int vertical, long_i pprinter_dc) return pixels; } +/* + * Convert pixel into point size. This is a reverse of points_to_pixels. + */ + static double +pixels_to_points(int pixels, int vertical, long_i pprinter_dc) +{ + double points = 0; + HWND hwnd = (HWND)0; + HDC hdc; + HDC printer_dc = (HDC)pprinter_dc; + + if (printer_dc == NULL) + { + hwnd = GetDesktopWindow(); + hdc = GetWindowDC(hwnd); + } + else + hdc = printer_dc; + + points = pixels * 72.0 / GetDeviceCaps(hdc, vertical ? LOGPIXELSY : LOGPIXELSX); + if (printer_dc == NULL) + ReleaseDC(hwnd, hdc); + + return points; +} + static int CALLBACK font_enumproc( ENUMLOGFONTW *elf, @@ -2890,6 +2916,100 @@ init_logfont(LOGFONTW *lf) } /* + * Call back for EnumFontFamiliesW in expand_font_enumproc. + * + */ + static int CALLBACK +expand_font_enumproc( + ENUMLOGFONTW *elf, + NEWTEXTMETRICW *ntm UNUSED, + DWORD type UNUSED, + LPARAM lparam) +{ + LOGFONTW *lf = (LOGFONTW*)elf; + +# ifndef FEAT_PROPORTIONAL_FONTS + // Ignore non-monospace fonts without further ado + if ((ntm->tmPitchAndFamily & 1) != 0) + return 1; +# endif + + // Filter only on ANSI. Otherwise will see a lot of random fonts that we + // usually don't want. + if (lf->lfCharSet != ANSI_CHARSET) + return 1; + + int (*add_match)(char_u *) = (int (*)(char_u *))lparam; + + WCHAR *faceNameW = lf->lfFaceName; + char_u *faceName = utf16_to_enc(faceNameW, NULL); + if (!faceName) + return 0; + + add_match(faceName); + vim_free(faceName); + + return 1; +} + +/* + * Cmdline expansion for setting 'guifont'. Will enumerate through all + * monospace fonts for completion. If used after ':', will expand to possible + * font configuration options like font sizes. + * + * This function has "gui" in its name because in some platforms (GTK) font + * handling is done by the GUI code, whereas in Windows it's part of the + * platform code. + */ + void +gui_mch_expand_font(optexpand_T *args, void *param UNUSED, int (*add_match)(char_u *val)) +{ + expand_T *xp = args->oe_xp; + if (xp->xp_pattern > args->oe_set_arg && *(xp->xp_pattern-1) == ':') + { + char buf[30]; + + // Always fill in with the current font size as first option for + // convenience. We simply round to the closest integer for simplicity. + int font_height = (int)round( + pixels_to_points(-current_font_height, TRUE, (long_i)NULL)); + vim_snprintf(buf, ARRAY_LENGTH(buf), "h%d", font_height); + add_match((char_u *)buf); + + // Note: Keep this in sync with get_logfont(). Don't include 'c' and + // 'q' as we fill in all the values below. + static char *(p_gfn_win_opt_values[]) = { + "h" , "w" , "W" , "b" , "i" , "u" , "s"}; + for (size_t i = 0; i < ARRAY_LENGTH(p_gfn_win_opt_values); i++) + add_match((char_u *)p_gfn_win_opt_values[i]); + + struct charset_pair *cp; + for (cp = charset_pairs; cp->name != NULL; ++cp) + { + vim_snprintf(buf, ARRAY_LENGTH(buf), "c%s", cp->name); + add_match((char_u *)buf); + } + struct quality_pair *qp; + for (qp = quality_pairs; qp->name != NULL; ++qp) + { + vim_snprintf(buf, ARRAY_LENGTH(buf), "q%s", qp->name); + add_match((char_u *)buf); + } + return; + } + + HWND hwnd = GetDesktopWindow(); + HDC hdc = GetWindowDC(hwnd); + + EnumFontFamiliesW(hdc, + NULL, + (FONTENUMPROCW)expand_font_enumproc, + (LPARAM)add_match); + + ReleaseDC(hwnd, hdc); +} + +/* * Compare a UTF-16 string and an ASCII string literally. * Only works all the code points are inside ASCII range. */ @@ -2995,6 +3115,7 @@ get_logfont( { switch (*p++) { + // Note: Keep this in sync with gui_mch_expand_font(). case L'h': lf->lfHeight = - points_to_pixels(p, &p, TRUE, (long_i)printer_dc); break; |