@@ -149,25 +149,33 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict, int atcursor)
149149 if (get_lambda_tv (& ptr , & tv , TRUE) == OK )
150150 {
151151 wp -> w_popup_timer = create_timer (nr , 0 );
152- wp -> w_popup_timer -> tr_callback .cb_name =
153- vim_strsave (partial_name (tv .vval .v_partial ));
154- func_ref (wp -> w_popup_timer -> tr_callback .cb_name );
155- wp -> w_popup_timer -> tr_callback .cb_partial = tv .vval .v_partial ;
152+ wp -> w_popup_timer -> tr_callback = get_callback (& tv );
153+ clear_tv (& tv );
156154 }
157155 }
158156#endif
159157
160158 // Option values resulting in setting an option.
161- str = dict_get_string (dict , (char_u * )"highlight" , TRUE );
159+ str = dict_get_string (dict , (char_u * )"highlight" , FALSE );
162160 if (str != NULL )
163161 set_string_option_direct_in_win (wp , (char_u * )"wincolor" , -1 ,
164162 str , OPT_FREE |OPT_LOCAL , 0 );
163+
165164 di = dict_find (dict , (char_u * )"wrap" , -1 );
166165 if (di != NULL )
167166 {
168167 nr = dict_get_number (dict , (char_u * )"wrap" );
169168 wp -> w_p_wrap = nr != 0 ;
170169 }
170+
171+ di = dict_find (dict , (char_u * )"filter" , -1 );
172+ if (di != NULL )
173+ {
174+ callback_T callback = get_callback (& di -> di_tv );
175+
176+ if (callback .cb_name != NULL )
177+ set_callback (& wp -> w_filter_cb , & callback );
178+ }
171179}
172180
173181/*
@@ -759,4 +767,109 @@ not_in_popup_window()
759767 return FALSE;
760768}
761769
770+ /*
771+ * Reset all the POPF_HANDLED flags in global popup windows and popup windows
772+ * in the current tab.
773+ */
774+ void
775+ popup_reset_handled ()
776+ {
777+ win_T * wp ;
778+
779+ for (wp = first_popupwin ; wp != NULL ; wp = wp -> w_next )
780+ wp -> w_popup_flags &= ~POPF_HANDLED ;
781+ for (wp = curtab -> tp_first_popupwin ; wp != NULL ; wp = wp -> w_next )
782+ wp -> w_popup_flags &= ~POPF_HANDLED ;
783+ }
784+
785+ /*
786+ * Find the next visible popup where POPF_HANDLED is not set.
787+ * Must have called popup_reset_handled() first.
788+ * When "lowest" is TRUE find the popup with the lowest zindex, otherwise the
789+ * popup with the highest zindex.
790+ */
791+ win_T *
792+ find_next_popup (int lowest )
793+ {
794+ win_T * wp ;
795+ win_T * found_wp ;
796+ int found_zindex ;
797+
798+ found_zindex = lowest ? INT_MAX : 0 ;
799+ found_wp = NULL ;
800+ for (wp = first_popupwin ; wp != NULL ; wp = wp -> w_next )
801+ if ((wp -> w_popup_flags & (POPF_HANDLED |POPF_HIDDEN )) == 0
802+ && (lowest ? wp -> w_zindex < found_zindex
803+ : wp -> w_zindex > found_zindex ))
804+ {
805+ found_zindex = wp -> w_zindex ;
806+ found_wp = wp ;
807+ }
808+ for (wp = curtab -> tp_first_popupwin ; wp != NULL ; wp = wp -> w_next )
809+ if ((wp -> w_popup_flags & (POPF_HANDLED |POPF_HIDDEN )) == 0
810+ && (lowest ? wp -> w_zindex < found_zindex
811+ : wp -> w_zindex > found_zindex ))
812+ {
813+ found_zindex = wp -> w_zindex ;
814+ found_wp = wp ;
815+ }
816+
817+ if (found_wp != NULL )
818+ found_wp -> w_popup_flags |= POPF_HANDLED ;
819+ return found_wp ;
820+ }
821+
822+ /*
823+ * Invoke the filter callback for window "wp" with typed character "c".
824+ * Uses the global "mod_mask" for modifiers.
825+ * Returns the return value of the filter.
826+ * Careful: The filter may make "wp" invalid!
827+ */
828+ static int
829+ invoke_popup_filter (win_T * wp , int c )
830+ {
831+ int res ;
832+ typval_T rettv ;
833+ int dummy ;
834+ typval_T argv [3 ];
835+ char_u buf [NUMBUFLEN ];
836+
837+ argv [0 ].v_type = VAR_NUMBER ;
838+ argv [0 ].vval .v_number = (varnumber_T )wp -> w_id ;
839+
840+ // Convert the number to a string, so that the function can use:
841+ // if a:c == "\<F2>"
842+ buf [special_to_buf (c , mod_mask , TRUE, buf )] = NUL ;
843+ argv [1 ].v_type = VAR_STRING ;
844+ argv [1 ].vval .v_string = vim_strsave (buf );
845+
846+ argv [2 ].v_type = VAR_UNKNOWN ;
847+
848+ call_callback (& wp -> w_filter_cb , -1 ,
849+ & rettv , 2 , argv , NULL , 0L , 0L , & dummy , TRUE, NULL );
850+ res = tv_get_number (& rettv );
851+ vim_free (argv [1 ].vval .v_string );
852+ clear_tv (& rettv );
853+ return res ;
854+ }
855+
856+ /*
857+ * Called when "c" was typed: invoke popup filter callbacks.
858+ * Returns TRUE when the character was consumed,
859+ */
860+ int
861+ popup_do_filter (int c )
862+ {
863+ int res = FALSE;
864+ win_T * wp ;
865+
866+ popup_reset_handled ();
867+
868+ while (!res && (wp = find_next_popup (FALSE)) != NULL )
869+ if (wp -> w_filter_cb .cb_name != NULL )
870+ res = invoke_popup_filter (wp , c );
871+
872+ return res ;
873+ }
874+
762875#endif // FEAT_TEXT_PROP
0 commit comments