diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gui_gtk_x11.c | 56 | ||||
-rw-r--r-- | src/optiondefs.h | 16 | ||||
-rw-r--r-- | src/optionstr.c | 123 | ||||
-rw-r--r-- | src/os_mswin.c | 121 | ||||
-rw-r--r-- | src/proto/gui_gtk_x11.pro | 1 | ||||
-rw-r--r-- | src/proto/optionstr.pro | 1 | ||||
-rw-r--r-- | src/proto/os_mswin.pro | 1 | ||||
-rw-r--r-- | src/testdir/test_gui.vim | 50 | ||||
-rw-r--r-- | src/version.c | 2 |
9 files changed, 362 insertions, 9 deletions
diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c index 3fd6f3a904..4b3f53ef91 100644 --- a/src/gui_gtk_x11.c +++ b/src/gui_gtk_x11.c @@ -5316,6 +5316,62 @@ gui_mch_free_font(GuiFont font) } /* + * Cmdline expansion for setting 'guifont' / 'guifontwide'. Will enumerate + * through all fonts for completion. When setting 'guifont' it will only show + * monospace fonts as it's unlikely other fonts would be useful. + */ + void +gui_mch_expand_font(optexpand_T *args, void *param, int (*add_match)(char_u *val)) +{ + PangoFontFamily **font_families = NULL; + int n_families = 0; + int wide = *(int *)param; + + if (args->oe_include_orig_val && *args->oe_opt_value == NUL && !wide) + { + // If guifont is empty, and we want to fill in the orig value, suggest + // the default so the user can modify it. + if (add_match((char_u *)DEFAULT_FONT) != OK) + return; + } + + pango_context_list_families( + gui.text_context, + &font_families, + &n_families); + + for (int i = 0; i < n_families; i++) + { + if (!wide && !pango_font_family_is_monospace(font_families[i])) + continue; + + const char* fam_name = pango_font_family_get_name(font_families[i]); + if (input_conv.vc_type != CONV_NONE) + { + char_u *buf = string_convert(&input_conv, (char_u*)fam_name, NULL); + if (buf != NULL) + { + if (add_match(buf) != OK) + { + vim_free(buf); + break; + } + vim_free(buf); + } + else + break; + } + else + { + if (add_match((char_u *)fam_name) != OK) + break; + } + } + + g_free(font_families); +} + +/* * Return the Pixel value (color) for the given color name. * * Return INVALCOLOR for error. diff --git a/src/optiondefs.h b/src/optiondefs.h index f850d19b1c..c4810e7d5d 100644 --- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -1164,9 +1164,13 @@ static struct vimoption options[] = {(char_u *)NULL, (char_u *)0L} #endif SCTX_INIT}, - {"guifont", "gfn", P_STRING|P_VI_DEF|P_RCLR|P_ONECOMMA|P_NODUP, + {"guifont", "gfn", P_STRING|P_VI_DEF|P_RCLR|P_ONECOMMA|P_NODUP +#if !defined(FEAT_GUI_GTK) + |P_COLON +#endif + , #ifdef FEAT_GUI - (char_u *)&p_guifont, PV_NONE, did_set_guifont, NULL, + (char_u *)&p_guifont, PV_NONE, did_set_guifont, expand_set_guifont, {(char_u *)"", (char_u *)0L} #else (char_u *)NULL, PV_NONE, NULL, NULL, @@ -1183,10 +1187,14 @@ static struct vimoption options[] = {(char_u *)NULL, (char_u *)0L} #endif SCTX_INIT}, - {"guifontwide", "gfw", P_STRING|P_VI_DEF|P_RCLR|P_ONECOMMA|P_NODUP, + {"guifontwide", "gfw", P_STRING|P_VI_DEF|P_RCLR|P_ONECOMMA|P_NODUP +#if !defined(FEAT_GUI_GTK) + |P_COLON +#endif + , #if defined(FEAT_GUI) (char_u *)&p_guifontwide, PV_NONE, - did_set_guifontwide, NULL, + did_set_guifontwide, expand_set_guifont, {(char_u *)"", (char_u *)0L} #else (char_u *)NULL, PV_NONE, NULL, NULL, diff --git a/src/optionstr.c b/src/optionstr.c index 135cb9af68..6b40dcd706 100644 --- a/src/optionstr.c +++ b/src/optionstr.c @@ -731,7 +731,8 @@ did_set_option_listflag(char_u *val, char_u *flags, char *errbuf) } /* - * Expand an option that accepts a list of string values. + * Expand an option that accepts a list of fixed string values with known + * number of items. */ static int expand_set_opt_string( @@ -801,10 +802,11 @@ static char_u *set_opt_callback_orig_option = NULL; static char_u *((*set_opt_callback_func)(expand_T *, int)); /* - * Callback used by expand_set_opt_generic to also include the original value. + * Callback used by expand_set_opt_generic to also include the original value + * as the first item. */ static char_u * -expand_set_opt_callback(expand_T *xp, int idx) +expand_set_opt_generic_cb(expand_T *xp, int idx) { if (idx == 0) { @@ -817,7 +819,8 @@ expand_set_opt_callback(expand_T *xp, int idx) } /* - * Expand an option with a callback that iterates through a list of possible names. + * Expand an option with a callback that iterates through a list of possible + * names using an index. */ static int expand_set_opt_generic( @@ -838,7 +841,7 @@ expand_set_opt_generic( args->oe_regmatch, matches, numMatches, - expand_set_opt_callback, + expand_set_opt_generic_cb, FALSE); set_opt_callback_orig_option = NULL; @@ -846,6 +849,95 @@ expand_set_opt_generic( return ret; } +static garray_T *expand_cb_ga; +static optexpand_T *expand_cb_args; + +/* + * Callback provided to a function in expand_set_opt_callback. Will perform + * regex matching against the value and add to the list. + * + * Returns OK usually. Returns FAIL if it failed to allocate memory, and the + * caller should terminate the enumeration. + */ + static int +expand_set_opt_callback_cb(char_u *val) +{ + regmatch_T *regmatch = expand_cb_args->oe_regmatch; + expand_T *xp = expand_cb_args->oe_xp; + garray_T *ga = expand_cb_ga; + char_u *str; + + if (val == NULL || *val == NUL) + return OK; + + if (xp->xp_pattern[0] != NUL && + !vim_regexec(regmatch, val, (colnr_T)0)) + return OK; + + str = vim_strsave_escaped(val, (char_u *)" \t\\"); + + if (str == NULL) + return FAIL; + + if (ga_grow(ga, 1) == FAIL) + { + vim_free(str); + return FAIL; + } + + ((char_u **)ga->ga_data)[ga->ga_len] = str; + ++ga->ga_len; + return OK; +} + +/* + * Expand an option with a provided function that takes a callback. The + * function will enumerate through all options and call the callback to add it + * to the list. + * + * "func" is the enumerator function that will generate the list of options. + * "func_params" is a single parameter that will be passed to func. + */ + static int +expand_set_opt_callback( + optexpand_T *args, + void (*func)(optexpand_T *, void* params, int (*cb)(char_u *val)), + void *func_params, + int *numMatches, + char_u ***matches) +{ + garray_T ga; + int include_orig_val = args->oe_include_orig_val; + char_u *option_val = args->oe_opt_value; + + ga_init2(&ga, sizeof(char *), 30); + + if (include_orig_val && *option_val != NUL) + { + char_u *p = vim_strsave(option_val); + if (p == NULL) + return FAIL; + if (ga_grow(&ga, 1) == FAIL) + { + vim_free(p); + return FAIL; + } + ((char_u **)ga.ga_data)[ga.ga_len] = p; + ++ga.ga_len; + } + + expand_cb_ga = &ga; + expand_cb_args = args; + + func(args, func_params, expand_set_opt_callback_cb); + + expand_cb_ga = NULL; + expand_cb_args = NULL; + + *matches = ga.ga_data; + *numMatches = ga.ga_len; + return OK; +} /* * Expand an option which is a list of flags. @@ -2237,6 +2329,27 @@ did_set_guifont(optset_T *args UNUSED) return errmsg; } +/* + * Expand the 'guifont' option. Only when GUI is being used. Each platform has + * specific behaviors. + */ + int +expand_set_guifont(optexpand_T *args, int *numMatches, char_u ***matches) +{ + if (!gui.in_use) + return FAIL; + +# if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK) + char_u **varp = (char_u **)args->oe_varp; + int wide = (varp == &p_guifontwide); + + return expand_set_opt_callback( + args, gui_mch_expand_font, &wide, numMatches, matches); +# else + return FAIL; +# endif +} + # if defined(FEAT_XFONTSET) || defined(PROTO) /* * The 'guifontset' option is changed. 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; diff --git a/src/proto/gui_gtk_x11.pro b/src/proto/gui_gtk_x11.pro index 3fa2ac96d6..459cdb9532 100644 --- a/src/proto/gui_gtk_x11.pro +++ b/src/proto/gui_gtk_x11.pro @@ -37,6 +37,7 @@ int gui_mch_init_font(char_u *font_name, int fontset); GuiFont gui_mch_get_font(char_u *name, int report_error); char_u *gui_mch_get_fontname(GuiFont font, char_u *name); void gui_mch_free_font(GuiFont font); +void gui_mch_expand_font(optexpand_T *args, void *param, int (*cb)(char_u *val)); guicolor_T gui_mch_get_color(char_u *name); guicolor_T gui_mch_get_rgb_color(int r, int g, int b); void gui_mch_set_fg_color(guicolor_T color); diff --git a/src/proto/optionstr.pro b/src/proto/optionstr.pro index 48cccea8cc..88034fcec5 100644 --- a/src/proto/optionstr.pro +++ b/src/proto/optionstr.pro @@ -152,6 +152,7 @@ int expand_set_foldclose(optexpand_T *args, int *numMatches, char_u ***matches); int expand_set_foldmethod(optexpand_T *args, int *numMatches, char_u ***matches); int expand_set_foldopen(optexpand_T *args, int *numMatches, char_u ***matches); int expand_set_formatoptions(optexpand_T *args, int *numMatches, char_u ***matches); +int expand_set_guifont(optexpand_T *args, int *numMatches, char_u ***matches); int expand_set_guioptions(optexpand_T *args, int *numMatches, char_u ***matches); int expand_set_highlight(optexpand_T *args, int *numMatches, char_u ***matches); int expand_set_jumpoptions(optexpand_T *args, int *numMatches, char_u ***matches); diff --git a/src/proto/os_mswin.pro b/src/proto/os_mswin.pro index d9172ee01b..9f534e09d3 100644 --- a/src/proto/os_mswin.pro +++ b/src/proto/os_mswin.pro @@ -51,5 +51,6 @@ void serverProcessPendingMessages(void); char *charset_id2name(int id); char *quality_id2name(DWORD id); int get_logfont(LOGFONTW *lf, char_u *name, HDC printer_dc, int verbose); +void gui_mch_expand_font(optexpand_T *args, void *param, int (*cb)(char_u *val)); void channel_init_winsock(void); /* vim: set ft=c : */ diff --git a/src/testdir/test_gui.vim b/src/testdir/test_gui.vim index acc72f8395..e7f7c6d830 100644 --- a/src/testdir/test_gui.vim +++ b/src/testdir/test_gui.vim @@ -580,6 +580,56 @@ func Test_set_guifontwide() endif endfunc +func Test_expand_guifont() + if has('gui_win32') + let guifont_saved = &guifont + let guifontwide_saved = &guifontwide + + " Test recalling existing option, and suggesting current font size + set guifont=Courier\ New:h11:cANSI + call assert_equal('Courier\ New:h11:cANSI', getcompletion('set guifont=', 'cmdline')[0]) + call assert_equal('h11', getcompletion('set guifont=Lucida\ Console:', 'cmdline')[0]) + + " Test auto-completion working for font names + call assert_equal(['Courier\ New'], getcompletion('set guifont=Couri*ew$', 'cmdline')) + call assert_equal(['Courier\ New'], getcompletion('set guifontwide=Couri*ew$', 'cmdline')) + + " Make sure non-monospace fonts are filtered out + call assert_equal([], getcompletion('set guifont=Arial', 'cmdline')) + call assert_equal([], getcompletion('set guifontwide=Arial', 'cmdline')) + + " Test auto-completion working for font options + call assert_notequal(-1, index(getcompletion('set guifont=Courier\ New:', 'cmdline'), 'b')) + call assert_equal(['cDEFAULT'], getcompletion('set guifont=Courier\ New:cD*T', 'cmdline')) + call assert_equal(['qCLEARTYPE'], getcompletion('set guifont=Courier\ New:qC*TYPE', 'cmdline')) + + let &guifontwide = guifontwide_saved + let &guifont = guifont_saved + elseif has('gui_gtk') + let guifont_saved = &guifont + let guifontwide_saved = &guifontwide + + " Test recalling default and existing option + set guifont= + call assert_equal('Monospace\ 10', getcompletion('set guifont=', 'cmdline')[0]) + set guifont=Monospace\ 9 + call assert_equal('Monospace\ 9', getcompletion('set guifont=', 'cmdline')[0]) + + " Test auto-completion working for font names + call assert_equal(['Monospace'], getcompletion('set guifont=Mono*pace$', 'cmdline')) + call assert_equal(['Monospace'], getcompletion('set guifontwide=Mono*pace$', 'cmdline')) + + " Make sure non-monospace fonts are filtered out only in 'guifont' + call assert_equal([], getcompletion('set guifont=Sans$', 'cmdline')) + call assert_equal(['Sans'], getcompletion('set guifontwide=Sans$', 'cmdline')) + + let &guifontwide = guifontwide_saved + let &guifont = guifont_saved + else + call assert_equal([], getcompletion('set guifont=', 'cmdline')) + endif +endfunc + func Test_set_guiligatures() CheckX11BasedGui diff --git a/src/version.c b/src/version.c index 0f73dc25ae..9b1c0b4e92 100644 --- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1991, +/**/ 1990, /**/ 1989, |