diff --git a/Filelist b/Filelist index 37f1d8c77a..fd8ff05e50 100644 --- a/Filelist +++ b/Filelist @@ -158,7 +158,9 @@ SRC_ALL = \ src/testdir/gen_opt_test.vim \ src/testdir/README.txt \ src/testdir/Make_all.mak \ - src/testdir/*.in \ + src/testdir/dotest.in \ + src/testdir/test1.in \ + src/testdir/test77a.in \ src/testdir/*.py \ src/testdir/lsan-suppress.txt \ src/testdir/sautest/autoload/*.vim \ @@ -177,9 +179,8 @@ SRC_ALL = \ src/testdir/summarize.vim \ src/testdir/term_util.vim \ src/testdir/view_util.vim \ - src/testdir/test[0-9]*.ok \ - src/testdir/test[0-9]*a.ok \ - src/testdir/test49.vim \ +- src/testdir/test1.ok \ + src/testdir/test77a.ok \ src/testdir/test83-tags? \ src/testdir/test77a.com \ src/testdir/test_*.vim \ @@ -641,13 +642,11 @@ SRC_HAIKU = \ SRC_MAC = \ src/INSTALLmac.txt \ src/dehqx.py \ - src/gui_mac.c \ src/os_mac_rsrc/*.icns \ src/os_mac.h \ src/os_mac.rsr.hqx \ src/os_mac_conv.c \ src/os_macosx.m \ - src/proto/gui_mac.pro \ src/proto/os_mac_conv.pro \ # source files for VMS (in the extra archive) diff --git a/runtime/doc/tabpage.txt b/runtime/doc/tabpage.txt index 1d8c2082f2..65ae599967 100644 --- a/runtime/doc/tabpage.txt +++ b/runtime/doc/tabpage.txt @@ -142,6 +142,7 @@ something else. :tabclose + " close the next tab page :tabclose 3 " close the third tab page :tabclose $ " close the last tab page + :tabclose # " close the last accessed tab page < *:tabo* *:tabonly* :tabo[nly][!] Close all other tab pages. @@ -170,6 +171,8 @@ something else. " one :tabonly 1 " close all tab pages except the first one :tabonly $ " close all tab pages except the last one + :tabonly # " close all tab pages except the last + " accessed one SWITCHING TO ANOTHER TAB PAGE: @@ -192,6 +195,7 @@ gt *i_CTRL-* *i_* :+2tabnext " go to the two next tab page :1tabnext " go to the first tab page :$tabnext " go to the last tab page + :tabnext # " go to the last accessed tab page :tabnext $ " as above :tabnext - " go to the previous tab page :tabnext -1 " as above @@ -255,6 +259,8 @@ REORDERING TAB PAGES: :tabmove " move the tab page to the last :$tabmove " as above :tabmove $ " as above + :tabmove # " move the tab page after the last accessed + " tab page :tabm[ove] +[N] :tabm[ove] -[N] diff --git a/runtime/doc/testing.txt b/runtime/doc/testing.txt index f1173a1f0b..1147673d59 100644 --- a/runtime/doc/testing.txt +++ b/runtime/doc/testing.txt @@ -20,18 +20,11 @@ and for testing plugins. Vim can be tested after building it, usually with "make test". The tests are located in the directory "src/testdir". -There are several types of tests added over time: - test33.in oldest, don't add any of these - test_something.in old style tests - test_something.vim new style tests - *new-style-testing* -New tests should be added as new style tests. These use functions such as -|assert_equal()| to keep the test commands and the expected result in one -place. - *old-style-testing* -In some cases an old style test needs to be used. E.g. when testing Vim -without the |+eval| feature. +New tests should be added as new style tests. The test scripts are named +test_.vim (replace with the feature under test). These use +functions such as |assert_equal()| to keep the test commands and the expected +result in one place. Find more information in the file src/testdir/README.txt. diff --git a/src/INSTALLmac.txt b/src/INSTALLmac.txt index e957682a14..ac122c351b 100644 --- a/src/INSTALLmac.txt +++ b/src/INSTALLmac.txt @@ -16,7 +16,7 @@ Summary ---------------------------------------------------------------------------- 1 MacOS X - 1.1. Carbon interface + 1.1. Terminal version 1.2. X (Athena, GTK, Motif) or plain text. MacOS Classic is no longer supported. If you really want it use Vim 6.4. @@ -27,9 +27,9 @@ MacOS Classic is no longer supported. If you really want it use Vim 6.4. 1.0 Considerations - Only '/' supported as path separator. + Only '/' is supported as path separator. -1.1 Carbon interface (default) +1.1 Terminal version (default) You can compile vim with the standard Unix routine: cd .../src @@ -37,14 +37,7 @@ MacOS Classic is no longer supported. If you really want it use Vim 6.4. make test sudo make install - "make" will create a working Vim.app application bundle in the src - directory. You can move this bundle (the Vim.app directory) anywhere - you want. Or use "make install" to move it to /Applications. - - You need at least Xcode 1.5 to compile Vim 7.0. - - Configure will create a universal binary if possible. This requires - installing the universal SDK (currently for 10.4). + You need at least Xcode 1.5. To overrule the architecture do this before running make: @@ -53,17 +46,16 @@ MacOS Classic is no longer supported. If you really want it use Vim 6.4. ./configure --with-mac-arch=ppc -1.2 X-Windows or Plain Text +1.2 X-Windows - If you do not want the Carbon interface, you must explicitly tell - configure to use a different GUI. + You must explicitly tell configure to use a GUI. cd .../src ./configure --disable-darwin --enable-gui=gtk2 make; make install - NOTE: The following GUI options are supported: - no (for text), motif, athena, nextaw + NOTE: The following GUI options are possible (but might not work): + no (for terminal only), motif, athena, nextaw gtk, gtk2, gnome, gnome2, NOTE: You need to first install XFree86 and XDarwin. diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index 9c3deb62d3..8ac39e22b5 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -1326,14 +1326,6 @@ MAIN_TARGET = $(VIM).exe # Target to run individual tests. VIMTESTTARGET = $(VIM).exe -OLD_TEST_OUTFILES = \ - $(SCRIPTS_FIRST) \ - $(SCRIPTS_ALL) \ - $(SCRIPTS_MORE1) \ - $(SCRIPTS_MORE4) \ - $(SCRIPTS_WIN32) \ - $(SCRIPTS_GUI) - all: $(MAIN_TARGET) \ vimrun.exe \ install.exe \ @@ -1485,9 +1477,9 @@ testclean: $(MAKE) /NOLOGO -f Make_dos.mak clean cd .. -# Run individual OLD style test. +# Run test1 to bootstrap tests # These do not depend on the executable, compile it when needed. -$(OLD_TEST_OUTFILES:.out=): +$(SCRIPTS_FIRST:.out=): cd testdir - if exist $@.out del $@.out $(MAKE) /NOLOGO -f Make_dos.mak VIMPROG=..\$(VIMTESTTARGET) nolog diff --git a/src/Makefile b/src/Makefile index 09697f93fb..f9e5431979 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1373,24 +1373,6 @@ PHOTONGUI_MAN_TARGETS = yes PHOTONGUI_TESTTARGET = gui PHOTONGUI_BUNDLE = -# CARBON GUI -CARBONGUI_SRC = gui.c gui_mac.c -CARBONGUI_OBJ = objects/gui.o objects/gui_mac.o -CARBONGUI_DEFS = -DFEAT_GUI_MAC -fno-common -fpascal-strings \ - -Wall -Wno-unknown-pragmas \ - -mdynamic-no-pic -pipe -CARBONGUI_IPATH = -I. -Iproto -CARBONGUI_LIBS_DIR = -CARBONGUI_LIBS1 = -framework Carbon -CARBONGUI_LIBS2 = -CARBONGUI_INSTALL = install_macosx -CARBONGUI_TARGETS = -CARBONGUI_MAN_TARGETS = -CARBONGUI_TESTTARGET = gui -CARBONGUI_BUNDLE = gui_bundle -APPDIR = $(VIMNAME).app -CARBONGUI_TESTARG = VIMPROG=../$(APPDIR)/Contents/MacOS/$(VIMTARGET) - ### Haiku GUI HAIKUGUI_SRC = gui.c gui_haiku.cc HAIKUGUI_OBJ = objects/gui.o objects/gui_haiku.o @@ -2276,8 +2258,6 @@ test check: unittests $(TERM_TEST) scripttests # # This will produce a lot of garbage on your screen, including a few error # messages. Don't worry about that. -# If there is a real error, there will be a difference between "testXX.out" and -# a "testXX.ok" file. # If everything is alright, the final message will be "ALL DONE". If not you # get "TEST FAILURE". # @@ -2328,9 +2308,9 @@ test_libvterm: CC="$(CC)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)"; \ fi -# Run individual OLD style test. -# These do not depend on the executable, compile it when needed. -test1 test49: +# Run test1, used to bootstrap tests. +# This does not depend on the executable, compile first it when needed. +test1: cd testdir; rm -f $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTESTTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) # Run individual NEW style test. diff --git a/src/auto/configure b/src/auto/configure index e8c8af39ff..33e3f145c7 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -833,7 +833,6 @@ enable_gtk3_check enable_motif_check enable_athena_check enable_nextaw_check -enable_carbon_check enable_macvim_check enable_gtktest with_gnome_includes @@ -1505,7 +1504,6 @@ Optional Features: --enable-motif-check If auto-select GUI, check for Motif default=yes --enable-athena-check If auto-select GUI, check for Athena default=yes --enable-nextaw-check If auto-select GUI, check for neXtaw default=yes - --enable-carbon-check If auto-select GUI, check for Carbon default=yes --enable-macvim-check If auto-select GUI, check for MacVim default=yes --disable-gtktest Do not try to compile and run a test GTK program --disable-icon-cache-update update disabled @@ -4796,7 +4794,11 @@ rm -f core conftest.err conftest.$ac_objext \ OS_EXTRA_OBJ="objects/os_macosx.o objects/os_mac_conv.o" CPPFLAGS="$CPPFLAGS -DMACOS_X_DARWIN" - # On IRIX 5.3, sys/types and inttypes.h are conflicting. + SAVE_CPPFLAGS=$CPPFLAGS + SAVE_CFLAGS=$CFLAGS + CPPFLAGS="$CPPFLAGS -ObjC" + CFLAGS="$CFLAGS -ObjC" + # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : @@ -4813,18 +4815,7 @@ fi done -ac_fn_c_check_header_mongrel "$LINENO" "Carbon/Carbon.h" "ac_cv_header_Carbon_Carbon_h" "$ac_includes_default" -if test "x$ac_cv_header_Carbon_Carbon_h" = xyes; then : - CARBON=yes -fi - - - - SAVE_CPPFLAGS=$CPPFLAGS - SAVE_CFLAGS=$CFLAGS - CPPFLAGS="$CPPFLAGS -ObjC" - CFLAGS="$CFLAGS -ObjC" - ac_fn_c_check_header_mongrel "$LINENO" "Cocoa/Cocoa.h" "ac_cv_header_Cocoa_Cocoa_h" "$ac_includes_default" +ac_fn_c_check_header_mongrel "$LINENO" "Cocoa/Cocoa.h" "ac_cv_header_Cocoa_Cocoa_h" "$ac_includes_default" if test "x$ac_cv_header_Cocoa_Cocoa_h" = xyes; then : COCOA=yes fi @@ -4833,11 +4824,9 @@ fi CPPFLAGS=$SAVE_CPPFLAGS CFLAGS=$SAVE_CFLAGS - if test "x$CARBON" = "xyes" -o "x$COCOA" = "xyes"; then - if test -z "$with_x" -a "X$enable_gui" != Xmotif -a "X$enable_gui" != Xathena -a "X$enable_gui" != Xgtk2 -a "X$enable_gui" != Xgtk3; then - with_x=no - fi - fi + if test -z "$with_x" -a "X$enable_gui" != Xmotif -a "X$enable_gui" != Xathena -a "X$enable_gui" != Xgtk2 -a "X$enable_gui" != Xgtk3; then + with_x=no + fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 @@ -9318,7 +9307,6 @@ SKIP_ATHENA=YES SKIP_NEXTAW=YES SKIP_PHOTON=YES SKIP_HAIKU=YES -SKIP_CARBON=YES SKIP_MACVIM=YES GUITYPE=NONE @@ -9355,29 +9343,20 @@ $as_echo "Sorry, $enable_gui GUI is not supported" >&6; } esac elif test "x$MACOS_X" = "xyes" -a "x$with_x" = "xno" ; then - SKIP_CARBON= SKIP_MACVIM= case "$enable_gui_canon" in no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no GUI support" >&5 $as_echo "no GUI support" >&6; } - SKIP_CARBON=YES - SKIP_MACVIM=YES ;; - yes|""|auto) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes/auto - automatic GUI support" >&5 -$as_echo "yes/auto - automatic GUI support" >&6; } - gui_auto=yes - SKIP_CARBON=YES ;; - carbon) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Carbon GUI support" >&5 -$as_echo "Carbon GUI support" >&6; } SKIP_MACVIM=YES ;; + yes|""|auto) { $as_echo "$as_me:${as_lineno-$LINENO}: result: automatic GUI support" >&5 +$as_echo "automatic GUI support" >&6; } + gui_auto=yes ;; macvim) { $as_echo "$as_me:${as_lineno-$LINENO}: result: MacVim GUI support" >&5 -$as_echo "MacVim GUI support" >&6; } - SKIP_CARBON=YES ;; +$as_echo "MacVim GUI support" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Sorry, $enable_gui GUI is not supported" >&5 $as_echo "Sorry, $enable_gui GUI is not supported" >&6; } - SKIP_CARBON=YES SKIP_MACVIM=YES ;; esac - else case "$enable_gui_canon" in @@ -9390,9 +9369,8 @@ $as_echo "yes/auto - automatic GUI support" >&6; } SKIP_GNOME= SKIP_MOTIF= SKIP_ATHENA= - SKIP_NEXTAW= SKIP_MACVIM= - SKIP_CARBON=;; + SKIP_NEXTAW=;; gtk2) { $as_echo "$as_me:${as_lineno-$LINENO}: result: GTK+ 2.x GUI support" >&5 $as_echo "GTK+ 2.x GUI support" >&6; } SKIP_GTK2=;; @@ -9522,23 +9500,6 @@ $as_echo "$enable_nextaw_check" >&6; }; fi fi -if test "x$SKIP_CARBON" != "xYES" -a "$enable_gui_canon" != "carbon"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for Carbon" >&5 -$as_echo_n "checking whether or not to look for Carbon... " >&6; } - # Check whether --enable-carbon-check was given. -if test "${enable_carbon_check+set}" = set; then : - enableval=$enable_carbon_check; -else - enable_carbon_check="yes" -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_carbon_check" >&5 -$as_echo "$enable_carbon_check" >&6; }; - if test "x$enable_carbon_check" = "xno"; then - SKIP_CARBON=YES - fi -fi - if test "x$SKIP_MACVIM" != "xYES" -a "$enable_gui_canon" != "macvim"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for MacVim" >&5 $as_echo_n "checking whether or not to look for MacVim... " >&6; } @@ -14993,11 +14954,7 @@ fi if test "$MACOS_X" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we need macOS frameworks" >&5 $as_echo_n "checking whether we need macOS frameworks... " >&6; } - if test "$GUITYPE" = "CARBONGUI"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, we need Carbon" >&5 -$as_echo "yes, we need Carbon" >&6; } - LIBS="$LIBS -framework Carbon" - elif test "$MACOS_X_DARWIN" = "yes"; then + if test "$MACOS_X_DARWIN" = "yes"; then if test "$features" = "tiny"; then OS_EXTRA_SRC=`echo "$OS_EXTRA_SRC" | sed -e 's+os_macosx.m++'` OS_EXTRA_OBJ=`echo "$OS_EXTRA_OBJ" | sed -e 's+objects/os_macosx.o++'` diff --git a/src/configure.ac b/src/configure.ac index 1c49d5409e..088364180a 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -294,11 +294,6 @@ if test "`(uname) 2>/dev/null`" = Darwin; then dnl Removed -no-cpp-precomp, only for very old compilers. CPPFLAGS="$CPPFLAGS -DMACOS_X_DARWIN" - dnl If Carbon or Cocoa is found, assume we don't want - dnl X11 unless it was specifically asked for (--with-x) - dnl or Motif, Athena or GTK GUI is used. - AC_CHECK_HEADER(Carbon/Carbon.h, CARBON=yes) - SAVE_CPPFLAGS=$CPPFLAGS SAVE_CFLAGS=$CFLAGS CPPFLAGS="$CPPFLAGS -ObjC" @@ -307,11 +302,11 @@ if test "`(uname) 2>/dev/null`" = Darwin; then CPPFLAGS=$SAVE_CPPFLAGS CFLAGS=$SAVE_CFLAGS - if test "x$CARBON" = "xyes" -o "x$COCOA" = "xyes"; then - if test -z "$with_x" -a "X$enable_gui" != Xmotif -a "X$enable_gui" != Xathena -a "X$enable_gui" != Xgtk2 -a "X$enable_gui" != Xgtk3; then - with_x=no - fi - fi + dnl Assume we don't want X11 unless it was specifically asked for + dnl (--with-x) or Motif, Athena or GTK GUI is used. + if test -z "$with_x" -a "X$enable_gui" != Xmotif -a "X$enable_gui" != Xathena -a "X$enable_gui" != Xgtk2 -a "X$enable_gui" != Xgtk3; then + with_x=no + fi fi else AC_MSG_RESULT(no) @@ -2483,7 +2478,6 @@ SKIP_ATHENA=YES SKIP_NEXTAW=YES SKIP_PHOTON=YES SKIP_HAIKU=YES -SKIP_CARBON=YES SKIP_MACVIM=YES GUITYPE=NONE @@ -2511,24 +2505,16 @@ elif test "x$QNX" = "xyes" -a "x$with_x" = "xno" ; then esac elif test "x$MACOS_X" = "xyes" -a "x$with_x" = "xno" ; then - SKIP_CARBON= SKIP_MACVIM= case "$enable_gui_canon" in no) AC_MSG_RESULT(no GUI support) - SKIP_CARBON=YES SKIP_MACVIM=YES ;; - yes|""|auto) AC_MSG_RESULT(yes/auto - automatic GUI support) - gui_auto=yes - SKIP_CARBON=YES ;; - carbon) AC_MSG_RESULT(Carbon GUI support) - SKIP_MACVIM=YES ;; - macvim) AC_MSG_RESULT(MacVim GUI support) - SKIP_CARBON=YES ;; + yes|""|auto) AC_MSG_RESULT(automatic GUI support) + gui_auto=yes ;; + macvim) AC_MSG_RESULT(MacVim GUI support) ;; *) AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported]) - SKIP_CARBON=YES SKIP_MACVIM=YES ;; esac - else case "$enable_gui_canon" in @@ -2539,9 +2525,8 @@ else SKIP_GNOME= SKIP_MOTIF= SKIP_ATHENA= - SKIP_NEXTAW= SKIP_MACVIM= - SKIP_CARBON=;; + SKIP_NEXTAW=;; gtk2) AC_MSG_RESULT(GTK+ 2.x GUI support) SKIP_GTK2=;; gnome2) AC_MSG_RESULT(GNOME 2.x GUI support) @@ -2628,17 +2613,6 @@ if test "x$SKIP_NEXTAW" != "xYES" -a "$enable_gui_canon" != "nextaw"; then fi fi -if test "x$SKIP_CARBON" != "xYES" -a "$enable_gui_canon" != "carbon"; then - AC_MSG_CHECKING(whether or not to look for Carbon) - AC_ARG_ENABLE(carbon-check, - [ --enable-carbon-check If auto-select GUI, check for Carbon [default=yes]], - , enable_carbon_check="yes") - AC_MSG_RESULT($enable_carbon_check); - if test "x$enable_carbon_check" = "xno"; then - SKIP_CARBON=YES - fi -fi - if test "x$SKIP_MACVIM" != "xYES" -a "$enable_gui_canon" != "macvim"; then AC_MSG_CHECKING(whether or not to look for MacVim) AC_ARG_ENABLE(macvim-check, @@ -4552,10 +4526,7 @@ fi if test "$MACOS_X" = "yes"; then AC_MSG_CHECKING([whether we need macOS frameworks]) - if test "$GUITYPE" = "CARBONGUI"; then - AC_MSG_RESULT([yes, we need Carbon]) - LIBS="$LIBS -framework Carbon" - elif test "$MACOS_X_DARWIN" = "yes"; then + if test "$MACOS_X_DARWIN" = "yes"; then if test "$features" = "tiny"; then dnl Since no FEAT_CLIPBOARD, no longer need for os_macosx.m. OS_EXTRA_SRC=`echo "$OS_EXTRA_SRC" | sed -e 's+os_macosx.m++'` diff --git a/src/eval.c b/src/eval.c index abdf076d26..99554e7e26 100644 --- a/src/eval.c +++ b/src/eval.c @@ -192,7 +192,10 @@ eval_to_bool( *error = FALSE; if (!skip) { - retval = (tv_get_number_chk(&tv, error) != 0); + if (in_vim9script()) + retval = tv2bool(&tv); + else + retval = (tv_get_number_chk(&tv, error) != 0); clear_tv(&tv); } } @@ -3098,7 +3101,8 @@ eval7( // Apply prefixed "-" and "+" now. Matters especially when // "->" follows. - if (ret == OK && evaluate && end_leader > start_leader) + if (ret == OK && evaluate && end_leader > start_leader + && rettv->v_type != VAR_BLOB) ret = eval7_leader(rettv, TRUE, start_leader, &end_leader); break; @@ -3281,7 +3285,10 @@ eval7_leader( f = rettv->vval.v_float; else #endif - val = tv_get_number_chk(rettv, &error); + if (in_vim9script() && end_leader[-1] == '!') + val = tv2bool(rettv); + else + val = tv_get_number_chk(rettv, &error); if (error) { clear_tv(rettv); diff --git a/src/evalfunc.c b/src/evalfunc.c index 70e60d74cf..1cbfe1726f 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -3927,13 +3927,7 @@ f_has(typval_T *argvars, typval_T *rettv) 0 #endif }, - {"gui_mac", -#ifdef FEAT_GUI_MAC - 1 -#else - 0 -#endif - }, + {"gui_mac", 0}, {"gui_macvim", #ifdef FEAT_GUI_MACVIM 1 diff --git a/src/ex_docmd.c b/src/ex_docmd.c index e7960d7cee..4a9c80923a 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -5418,6 +5418,15 @@ get_tabpage_arg(exarg_T *eap) { if (STRCMP(p, "$") == 0) tab_number = LAST_TAB_NR; + else if (STRCMP(p, "#") == 0) + if (valid_tabpage(lastused_tabpage)) + tab_number = tabpage_index(lastused_tabpage); + else + { + eap->errmsg = ex_errmsg(e_invargval, eap->arg); + tab_number = 0; + goto theend; + } else if (p == p_save || *p_save == '-' || *p != NUL || tab_number > LAST_TAB_NR) { diff --git a/src/feature.h b/src/feature.h index a94cabb0e0..27e34f2fd5 100644 --- a/src/feature.h +++ b/src/feature.h @@ -641,7 +641,6 @@ && (defined(FEAT_GUI_GTK) \ || (defined(FEAT_GUI_MOTIF) && defined(HAVE_XM_NOTEBOOK_H)) \ || defined(FEAT_GUI_MACVIM) \ - || defined(FEAT_GUI_MAC) \ || defined(FEAT_GUI_HAIKU) \ || (defined(FEAT_GUI_MSWIN) \ && (!defined(_MSC_VER) || _MSC_VER > 1020))) @@ -655,9 +654,8 @@ #if defined(FEAT_NORMAL) # define FEAT_BROWSE_CMD # if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) \ - || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU) || defined(FEAT_GUI_PHOTON) \ || defined(FEAT_GUI_MACVIM) \ - || defined(FEAT_GUI_MAC) + || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU) || defined(FEAT_GUI_PHOTON) # define FEAT_BROWSE # endif #endif @@ -667,8 +665,7 @@ * there is no terminal version, and on Windows we can't figure out how to * fork one off with :gui. */ -#if (defined(FEAT_GUI_MSWIN) && !defined(VIMDLL)) \ - || (defined(FEAT_GUI_MAC) && !defined(MACOS_X_DARWIN)) +#if defined(FEAT_GUI_MSWIN) && !defined(VIMDLL) # define ALWAYS_USE_GUI #endif @@ -683,9 +680,8 @@ || defined(FEAT_GUI_GTK) \ || defined(FEAT_GUI_PHOTON) \ || defined(FEAT_GUI_HAIKU) \ - || defined(FEAT_GUI_MSWIN) \ || defined(FEAT_GUI_MACVIM) \ - || defined(FEAT_GUI_MAC) + || defined(FEAT_GUI_MSWIN) # define FEAT_CON_DIALOG # define FEAT_GUI_DIALOG # else @@ -701,7 +697,7 @@ #if defined(FEAT_GUI_DIALOG) && \ (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) \ || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MSWIN) \ - || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) \ + || defined(FEAT_GUI_PHOTON) \ || defined(FEAT_GUI_MACVIM) \ || defined(FEAT_GUI_HAIKU)) # define FEAT_GUI_TEXTDIALOG @@ -717,11 +713,6 @@ # define FEAT_TERMGUICOLORS #endif -// Mac specific thing: Codewarrior interface. -#ifdef FEAT_GUI_MAC -# define FEAT_CW_EDITOR -#endif - /* * +vartabs 'vartabstop' and 'varsofttabstop' options. */ @@ -1109,8 +1100,7 @@ #endif #if defined(FEAT_MZSCHEME) && (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK) \ - || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) \ - || defined(FEAT_GUI_MAC)) + || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)) # define MZSCHEME_GUI_THREADS #endif diff --git a/src/fileio.c b/src/fileio.c index 7d1c52b80c..35bc567aaa 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -403,11 +403,6 @@ readfile( */ swap_mode = (st.st_mode & 0644) | 0600; #endif -#ifdef FEAT_CW_EDITOR - // Get the FSSpec on MacOS - // TODO: Update it properly when the buffer name changes - (void)GetFSSpecFromPath(curbuf->b_ffname, &curbuf->b_FSSpec); -#endif #ifdef VMS curbuf->b_fab_rfm = st.st_fab_rfm; curbuf->b_fab_rat = st.st_fab_rat; @@ -3390,7 +3385,6 @@ shorten_fnames(int force) #if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \ || defined(FEAT_GUI_MACVIM) \ || defined(FEAT_GUI_MSWIN) \ - || defined(FEAT_GUI_MAC) \ || defined(FEAT_GUI_HAIKU) \ || defined(PROTO) /* diff --git a/src/globals.h b/src/globals.h index 4f1cbdb9f6..5579edc82f 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1573,7 +1573,7 @@ EXTERN char e_failed[] INIT(= N_("E472: Command failed")); #if defined(FEAT_GUI) && defined(FEAT_XFONTSET) EXTERN char e_fontset[] INIT(= N_("E234: Unknown fontset: %s")); #endif -#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MAC) \ +#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) \ || defined(FEAT_GUI_MACVIM) \ || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_HAIKU) EXTERN char e_font[] INIT(= N_("E235: Unknown font: %s")); @@ -1811,10 +1811,6 @@ EXTERN char e_colon_required[] INIT(= N_("E1050: Colon required before a range") EXTERN char e_alloc_color[] INIT(= N_("E254: Cannot allocate color %s")); #endif -#ifdef FEAT_GUI_MAC -EXTERN short disallow_gui INIT(= FALSE); -#endif - EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM")); EXTERN char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP")); diff --git a/src/gui.c b/src/gui.c index 0ba4d862c1..bf9ad3e3ce 100644 --- a/src/gui.c +++ b/src/gui.c @@ -56,7 +56,7 @@ static int disable_flush = 0; // If > 0, gui_mch_flush() is disabled. * this makes the thumb indicate the part of the text that is shown. Motif * can't do this. */ -#if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MAC) +#if defined(FEAT_GUI_ATHENA) # define SCROLL_PAST_END #endif @@ -855,7 +855,7 @@ gui_exit(int rc) #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_MSWIN) \ || defined(FEAT_GUI_MACVIM) \ - || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(PROTO) + || defined(FEAT_GUI_PHOTON) || defined(PROTO) # define NEED_GUI_UPDATE_SCREEN 1 /* * Called when the GUI shell is closed by the user. If there are no changed @@ -1398,7 +1398,7 @@ gui_position_components(int total_width UNUSED) #endif # if defined(FEAT_GUI_TABLINE) && (defined(FEAT_GUI_MSWIN) \ - || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_MAC)) + || defined(FEAT_GUI_MOTIF)) if (gui_has_tabline()) text_area_y += gui.tabline_height; #endif diff --git a/src/gui.h b/src/gui.h index 292a838ab4..1426611cc5 100644 --- a/src/gui.h +++ b/src/gui.h @@ -39,25 +39,6 @@ # include #endif -#ifdef FEAT_GUI_MAC -# include -/*# include */ -# include -# include -# include -# include -# if !(defined (TARGET_API_MAC_CARBON) && (TARGET_API_MAC_CARBON)) -# include -# endif -# include -/*# include */ -# include -# include -/* -# include -# include */ -#endif - #ifdef FEAT_GUI_PHOTON # include # include @@ -68,7 +49,7 @@ * On some systems scrolling needs to be done right away instead of in the * main loop. */ -#if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK) \ +#if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK) \ || defined(FEAT_GUI_MACVIM) # define USE_ON_FLY_SCROLL #endif @@ -79,7 +60,6 @@ #if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \ || defined(FEAT_GUI_MSWIN) \ || defined(FEAT_GUI_MACVIM) \ - || defined(FEAT_GUI_MAC) \ || defined(FEAT_GUI_HAIKU) # define HAVE_DROP_FILE #endif @@ -213,9 +193,6 @@ typedef struct GuiScrollbar #if FEAT_GUI_HAIKU VimScrollBar *id; // Pointer to real scroll bar #endif -#ifdef FEAT_GUI_MAC - ControlHandle id; // A handle to the scrollbar -#endif #ifdef FEAT_GUI_PHOTON PtWidget_t *id; #endif @@ -444,7 +421,7 @@ typedef struct Gui #if defined(FEAT_GUI_TABLINE) \ && (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_MOTIF) \ - || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_HAIKU)) + || defined(FEAT_GUI_HAIKU)) int tabline_height; #endif @@ -482,14 +459,6 @@ typedef struct Gui int vdcmp; // Vim Direct Communication Message Port #endif -#ifdef FEAT_GUI_MAC - WindowPtr VimWindow; - MenuHandle MacOSHelpMenu; // Help menu provided by the MacOS - int MacOSHelpItems; // Nr of help-items supplied by MacOS - WindowPtr wid; // Window id of text area - int visibility; // Is window partially/fully obscured? -#endif - #ifdef FEAT_GUI_PHOTON PtWidget_t *vimWindow; // PtWindow PtWidget_t *vimTextArea; // PtRaw @@ -612,6 +581,6 @@ typedef enum # endif #endif // FEAT_GUI_GTK -#if defined(UNIX) && !(defined(FEAT_GUI_MAC) || defined(FEAT_GUI_MACVIM)) +#if defined(UNIX) && !defined(FEAT_GUI_MACVIM) # define GUI_MAY_FORK #endif diff --git a/src/gui_mac.c b/src/gui_mac.c deleted file mode 100644 index 1d74beb999..0000000000 --- a/src/gui_mac.c +++ /dev/null @@ -1,6716 +0,0 @@ -/* vi:set ts=8 sts=4 sw=4 noet: - * - * VIM - Vi IMproved by Bram Moolenaar - * GUI/Motif support by Robert Webb - * Macintosh port by Dany St-Amant - * and Axel Kielhorn - * Port to MPW by Bernhard Pruemmer - * Initial Carbon port by Ammon Skidmore - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. - */ - -/* - * NOTES: - Vim 7+ does not support classic MacOS. Please use Vim 6.x - * - Comments mentioning FAQ refer to the book: - * "Macworld Mac Programming FAQs" from "IDG Books" - */ - -/* - * TODO: Change still to merge from the macvim's iDisk - * - * error_ga, mch_errmsg, Navigation's changes in gui_mch_browse - * uses of MenuItemIndex, changes in gui_mch_set_shellsize, - * ScrapManager error handling. - * Comments about function remaining to Carbonize. - * - */ - -/* - * TODO (Jussi) - * * Clipboard does not work (at least some cases) - * * ATSU font rendering has some problems - * * Investigate and remove dead code (there is still lots of that) - */ - -#include // included first to avoid CR problems -#include "vim.h" - -#define USE_CARBONIZED -#define USE_AEVENT // Enable AEVENT -#undef USE_OFFSETED_WINDOW // Debugging feature: start Vim window OFFSETed - -// Compile as CodeWarrior External Editor -#if defined(FEAT_CW_EDITOR) && !defined(USE_AEVENT) -# define USE_AEVENT // Need Apple Event Support -#endif - -// Vim's Scrap flavor. -#define VIMSCRAPFLAVOR 'VIM!' -#define SCRAPTEXTFLAVOR kScrapFlavorTypeUnicode - -static EventHandlerUPP mouseWheelHandlerUPP = NULL; -SInt32 gMacSystemVersion; - -#ifdef MACOS_CONVERT -# define USE_CARBONKEYHANDLER - -static int im_is_active = FALSE; -# if 0 - // TODO: Implement me! -static int im_start_row = 0; -static int im_start_col = 0; -# endif - -# define NR_ELEMS(x) (sizeof(x) / sizeof(x[0])) - -static TSMDocumentID gTSMDocument; - -static void im_on_window_switch(int active); -static EventHandlerUPP keyEventHandlerUPP = NULL; -static EventHandlerUPP winEventHandlerUPP = NULL; - -static pascal OSStatus gui_mac_handle_window_activate( - EventHandlerCallRef nextHandler, EventRef theEvent, void *data); - -static pascal OSStatus gui_mac_handle_text_input( - EventHandlerCallRef nextHandler, EventRef theEvent, void *data); - -static pascal OSStatus gui_mac_update_input_area( - EventHandlerCallRef nextHandler, EventRef theEvent); - -static pascal OSStatus gui_mac_unicode_key_event( - EventHandlerCallRef nextHandler, EventRef theEvent); - -#endif - - -// Include some file. TODO: move into os_mac.h -#include -#include -#include -#ifdef USE_AEVENT -# include -# include -#endif -# include -#if UNIVERSAL_INTERFACES_VERSION >= 0x0330 -# include -# include // Navigation only part of ?? -#endif - -// Help Manager (balloon.h, HM prefixed functions) are not supported -// under Carbon (Jussi) -# if 0 -// New Help Interface for Mac, not implemented yet. -# include -# endif - -/* - * These seem to be rectangle options. Why are they not found in - * headers? (Jussi) - */ -#define kNothing 0 -#define kCreateEmpty 2 //1 -#define kCreateRect 2 -#define kDestroy 3 - -/* - * Dany: Don't like those... - */ -#define topLeft(r) (((Point*)&(r))[0]) -#define botRight(r) (((Point*)&(r))[1]) - - -// Time of last mouse click, to detect double-click -static long lastMouseTick = 0; - -// ??? -static RgnHandle cursorRgn; -static RgnHandle dragRgn; -static Rect dragRect; -static short dragRectEnbl; -static short dragRectControl; - -// This variable is set when waiting for an event, which is the only moment -// scrollbar dragging can be done directly. It's not allowed while commands -// are executed, because it may move the cursor and that may cause unexpected -// problems (e.g., while ":s" is working). -static int allow_scrollbar = FALSE; - -// Last mouse click caused contextual menu, (to provide proper release) -static short clickIsPopup; - -// Feedback Action for Scrollbar -ControlActionUPP gScrollAction; -ControlActionUPP gScrollDrag; - -// Keeping track of which scrollbar is being dragged -static ControlHandle dragged_sb = NULL; - -// Vector of char_u --> control index for hotkeys in dialogs -static short *gDialogHotKeys; - -static struct -{ - FMFontFamily family; - FMFontSize size; - FMFontStyle style; - Boolean isPanelVisible; -} gFontPanelInfo = { 0, 0, 0, false }; - -#ifdef MACOS_CONVERT -# define USE_ATSUI_DRAWING -int p_macatsui_last; -ATSUStyle gFontStyle; -ATSUStyle gWideFontStyle; -Boolean gIsFontFallbackSet; -UInt32 useAntialias_cached = 0x0; -#endif - -// Colors Macros -#define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b) -#define Red(c) ((c & 0x00FF0000) >> 16) -#define Green(c) ((c & 0x0000FF00) >> 8) -#define Blue(c) ((c & 0x000000FF) >> 0) - -// Key mapping - -#define vk_Esc 0x35 // -> 1B - -#define vk_F1 0x7A // -> 10 -#define vk_F2 0x78 //0x63 -#define vk_F3 0x63 //0x76 -#define vk_F4 0x76 //0x60 -#define vk_F5 0x60 //0x61 -#define vk_F6 0x61 //0x62 -#define vk_F7 0x62 //0x63 ? -#define vk_F8 0x64 -#define vk_F9 0x65 -#define vk_F10 0x6D -#define vk_F11 0x67 -#define vk_F12 0x6F -#define vk_F13 0x69 -#define vk_F14 0x6B -#define vk_F15 0x71 - -#define vk_Clr 0x47 // -> 1B (ESC) -#define vk_Enter 0x4C // -> 03 - -#define vk_Space 0x31 // -> 20 -#define vk_Tab 0x30 // -> 09 -#define vk_Return 0x24 // -> 0D -// This is wrong for OSX, what is it for? -#define vk_Delete 0X08 // -> 08 BackSpace - -#define vk_Help 0x72 // -> 05 -#define vk_Home 0x73 // -> 01 -#define vk_PageUp 0x74 // -> 0D -#define vk_FwdDelete 0x75 // -> 7F -#define vk_End 0x77 // -> 04 -#define vk_PageDown 0x79 // -> 0C - -#define vk_Up 0x7E // -> 1E -#define vk_Down 0x7D // -> 1F -#define vk_Left 0x7B // -> 1C -#define vk_Right 0x7C // -> 1D - -#define vk_Undo vk_F1 -#define vk_Cut vk_F2 -#define vk_Copy vk_F3 -#define vk_Paste vk_F4 -#define vk_PrintScreen vk_F13 -#define vk_SCrollLock vk_F14 -#define vk_Pause vk_F15 -#define vk_NumLock vk_Clr -#define vk_Insert vk_Help - -#define KeySym char - -static struct -{ - KeySym key_sym; - char_u vim_code0; - char_u vim_code1; -} special_keys[] = -{ - {vk_Up, 'k', 'u'}, - {vk_Down, 'k', 'd'}, - {vk_Left, 'k', 'l'}, - {vk_Right, 'k', 'r'}, - - {vk_F1, 'k', '1'}, - {vk_F2, 'k', '2'}, - {vk_F3, 'k', '3'}, - {vk_F4, 'k', '4'}, - {vk_F5, 'k', '5'}, - {vk_F6, 'k', '6'}, - {vk_F7, 'k', '7'}, - {vk_F8, 'k', '8'}, - {vk_F9, 'k', '9'}, - {vk_F10, 'k', ';'}, - - {vk_F11, 'F', '1'}, - {vk_F12, 'F', '2'}, - {vk_F13, 'F', '3'}, - {vk_F14, 'F', '4'}, - {vk_F15, 'F', '5'}, - -// {XK_Help, '%', '1'}, -// {XK_Undo, '&', '8'}, -// {XK_BackSpace, 'k', 'b'}, -// {vk_Delete, 'k', 'b'}, - {vk_Insert, 'k', 'I'}, - {vk_FwdDelete, 'k', 'D'}, - {vk_Home, 'k', 'h'}, - {vk_End, '@', '7'}, -// {XK_Prior, 'k', 'P'}, -// {XK_Next, 'k', 'N'}, -// {XK_Print, '%', '9'}, - - {vk_PageUp, 'k', 'P'}, - {vk_PageDown, 'k', 'N'}, - - // End of list marker: - {(KeySym)0, 0, 0} -}; - -/* - * ------------------------------------------------------------ - * Forward declaration (for those needed) - * ------------------------------------------------------------ - */ - -#ifdef USE_AEVENT -OSErr HandleUnusedParms(const AppleEvent *theAEvent); -#endif - -#ifdef FEAT_GUI_TABLINE -static void initialise_tabline(void); -static WindowRef drawer = NULL; // TODO: put into gui.h -#endif - -#ifdef USE_ATSUI_DRAWING -static void gui_mac_set_font_attributes(GuiFont font); -#endif - -/* - * ------------------------------------------------------------ - * Conversion Utility - * ------------------------------------------------------------ - */ - -/* - * C2Pascal_save - * - * Allocate memory and convert the C-String passed in - * into a pascal string - * - */ - - char_u * -C2Pascal_save(char_u *Cstring) -{ - char_u *PascalString; - int len; - - if (Cstring == NULL) - return NULL; - - len = STRLEN(Cstring); - - if (len > 255) // Truncate if necessary - len = 255; - - PascalString = alloc(len + 1); - if (PascalString != NULL) - { - mch_memmove(PascalString + 1, Cstring, len); - PascalString[0] = len; - } - - return PascalString; -} - -/* - * C2Pascal_save_and_remove_backslash - * - * Allocate memory and convert the C-String passed in - * into a pascal string. Also remove the backslash at the same time - * - */ - - char_u * -C2Pascal_save_and_remove_backslash(char_u *Cstring) -{ - char_u *PascalString; - int len; - char_u *p, *c; - - len = STRLEN(Cstring); - - if (len > 255) // Truncate if necessary - len = 255; - - PascalString = alloc(len + 1); - if (PascalString != NULL) - { - for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++) - { - if ((*c == '\\') && (c[1] != 0)) - c++; - *p = *c; - p++; - len++; - } - PascalString[0] = len; - } - - return PascalString; -} - -/* - * Convert the modifiers of an Event into vim's modifiers (mouse) - */ - - int_u -EventModifiers2VimMouseModifiers(EventModifiers macModifiers) -{ - int_u vimModifiers = 0x00; - - if (macModifiers & (shiftKey | rightShiftKey)) - vimModifiers |= MOUSE_SHIFT; - if (macModifiers & (controlKey | rightControlKey)) - vimModifiers |= MOUSE_CTRL; - if (macModifiers & (optionKey | rightOptionKey)) - vimModifiers |= MOUSE_ALT; -#if 0 - // Not yet supported - if (macModifiers & (cmdKey)) // There's no rightCmdKey - vimModifiers |= MOUSE_CMD; -#endif - return (vimModifiers); -} - -/* - * Convert the modifiers of an Event into vim's modifiers (keys) - */ - - static int_u -EventModifiers2VimModifiers(EventModifiers macModifiers) -{ - int_u vimModifiers = 0x00; - - if (macModifiers & (shiftKey | rightShiftKey)) - vimModifiers |= MOD_MASK_SHIFT; - if (macModifiers & (controlKey | rightControlKey)) - vimModifiers |= MOD_MASK_CTRL; - if (macModifiers & (optionKey | rightOptionKey)) - vimModifiers |= MOD_MASK_ALT; -#ifdef USE_CMD_KEY - if (macModifiers & (cmdKey)) // There's no rightCmdKey - vimModifiers |= MOD_MASK_CMD; -#endif - return (vimModifiers); -} - -/* - * Convert a string representing a point size into pixels. The string should - * be a positive decimal number, with an optional decimal point (eg, "12", or - * "10.5"). The pixel value is returned, and a pointer to the next unconverted - * character is stored in *end. The flag "vertical" says whether this - * calculation is for a vertical (height) size or a horizontal (width) one. - * - * From gui_w48.c - */ - static int -points_to_pixels(char_u *str, char_u **end, int vertical) -{ - int pixels; - int points = 0; - int divisor = 0; - - while (*str) - { - if (*str == '.' && divisor == 0) - { - // Start keeping a divisor, for later - divisor = 1; - continue; - } - - if (!isdigit(*str)) - break; - - points *= 10; - points += *str - '0'; - divisor *= 10; - - ++str; - } - - if (divisor == 0) - divisor = 1; - - pixels = points/divisor; - *end = str; - return pixels; -} - -#ifdef MACOS_CONVERT -/* - * Deletes all traces of any Windows-style mnemonic text (including any - * parentheses) from a menu item and returns the cleaned menu item title. - * The caller is responsible for releasing the returned string. - */ - static CFStringRef -menu_title_removing_mnemonic(vimmenu_T *menu) -{ - CFStringRef name; - size_t menuTitleLen; - CFIndex displayLen; - CFRange mnemonicStart; - CFRange mnemonicEnd; - CFMutableStringRef cleanedName; - - menuTitleLen = STRLEN(menu->dname); - name = (CFStringRef) mac_enc_to_cfstring(menu->dname, menuTitleLen); - - if (name) - { - // Simple mnemonic-removal algorithm, assumes single parenthesized - // mnemonic character towards the end of the menu text - mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards); - displayLen = CFStringGetLength(name); - - if (mnemonicStart.location != kCFNotFound - && (mnemonicStart.location + 2) < displayLen - && CFStringGetCharacterAtIndex(name, - mnemonicStart.location + 1) == (UniChar)menu->mnemonic) - { - if (CFStringFindWithOptions(name, CFSTR(")"), - CFRangeMake(mnemonicStart.location + 1, - displayLen - mnemonicStart.location - 1), - kCFCompareBackwards, &mnemonicEnd) && - (mnemonicStart.location + 2) == mnemonicEnd.location) - { - cleanedName = CFStringCreateMutableCopy(NULL, 0, name); - if (cleanedName) - { - CFStringDelete(cleanedName, - CFRangeMake(mnemonicStart.location, - mnemonicEnd.location + 1 - - mnemonicStart.location)); - - CFRelease(name); - name = cleanedName; - } - } - } - } - - return name; -} -#endif - -/* - * Convert a list of FSSpec aliases into a list of fullpathname - * character strings. - */ - - char_u ** -new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error) -{ - char_u **fnames = NULL; - OSErr newError; - long fileCount; - FSSpec fileToOpen; - long actualSize; - AEKeyword dummyKeyword; - DescType dummyType; - - // Get number of files in list - *error = AECountItems(theList, numFiles); - if (*error) - return fnames; - - // Allocate the pointer list - fnames = ALLOC_MULT(char_u *, *numFiles); - - // Empty out the list - for (fileCount = 0; fileCount < *numFiles; fileCount++) - fnames[fileCount] = NULL; - - // Scan the list of FSSpec - for (fileCount = 1; fileCount <= *numFiles; fileCount++) - { - // Get the alias for the nth file, convert to an FSSpec - newError = AEGetNthPtr(theList, fileCount, typeFSS, - &dummyKeyword, &dummyType, - (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize); - if (newError) - { - // Caller is able to clean up - // TODO: Should be clean up or not? For safety. - return fnames; - } - - // Convert the FSSpec to a pathname - fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen); - } - - return (fnames); -} - -/* - * ------------------------------------------------------------ - * CodeWarrior External Editor Support - * ------------------------------------------------------------ - */ -#ifdef FEAT_CW_EDITOR - -/* - * Handle the Window Search event from CodeWarrior - * - * Description - * ----------- - * - * The IDE sends the Window Search AppleEvent to the editor when it - * needs to know whether a particular file is open in the editor. - * - * Event Reply - * ----------- - * - * None. Put data in the location specified in the structure received. - * - * Remarks - * ------- - * - * When the editor receives this event, determine whether the specified - * file is open. If it is, return the modification date/time for that file - * in the appropriate location specified in the structure. If the file is - * not opened, put the value fnfErr(file not found) in that location. - * - */ - -typedef struct WindowSearch WindowSearch; -struct WindowSearch // for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar -{ - FSSpec theFile; // identifies the file - long *theDate; // where to put the modification date/time -}; - - pascal OSErr -Handle_KAHL_SRCH_AE( - const AppleEvent *theAEvent, - AppleEvent *theReply, - long refCon) -{ - OSErr error = noErr; - buf_T *buf; - int foundFile = false; - DescType typeCode; - WindowSearch SearchData; - Size actualSize; - - error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize); - if (error) - return error; - - error = HandleUnusedParms(theAEvent); - if (error) - return error; - - FOR_ALL_BUFFERS(buf) - if (buf->b_ml.ml_mfp != NULL - && SearchData.theFile.parID == buf->b_FSSpec.parID - && SearchData.theFile.name[0] == buf->b_FSSpec.name[0] - && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0) - { - foundFile = true; - break; - } - - if (foundFile == false) - *SearchData.theDate = fnfErr; - else - *SearchData.theDate = buf->b_mtime; - - return error; -}; - -/* - * Handle the Modified (from IDE to Editor) event from CodeWarrior - * - * Description - * ----------- - * - * The IDE sends this event to the external editor when it wants to - * know which files that are open in the editor have been modified. - * - * Parameters None. - * ---------- - * - * Event Reply - * ----------- - * The reply for this event is: - * - * keyDirectObject typeAEList required - * each element in the list is a structure of typeChar - * - * Remarks - * ------- - * - * When building the reply event, include one element in the list for - * each open file that has been modified. - * - */ - -typedef struct ModificationInfo ModificationInfo; -struct ModificationInfo // for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList -{ - FSSpec theFile; // identifies the file - long theDate; // the date/time the file was last modified - short saved; // set this to zero when replying, unused -}; - - pascal OSErr -Handle_KAHL_MOD_AE( - const AppleEvent *theAEvent, - AppleEvent *theReply, - long refCon) -{ - OSErr error = noErr; - AEDescList replyList; - long numFiles; - ModificationInfo theFile; - buf_T *buf; - - theFile.saved = 0; - - error = HandleUnusedParms(theAEvent); - if (error) - return error; - - // Send the reply -// replyObject.descriptorType = typeNull; -// replyObject.dataHandle = nil; - -// AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) - error = AECreateList(nil, 0, false, &replyList); - if (error) - return error; - -#if 0 - error = AECountItems(&replyList, &numFiles); - - // AEPutKeyDesc(&replyList, keyAEPnject, &aDesc) - // AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType, - // sizeof(DescType)) - - // AEPutDesc -#endif - - numFiles = 0; - FOR_ALL_BUFFERS(buf) - if (buf->b_ml.ml_mfp != NULL) - { - // Add this file to the list - theFile.theFile = buf->b_FSSpec; - theFile.theDate = buf->b_mtime; -// theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; - error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile)); - }; - -#if 0 - error = AECountItems(&replyList, &numFiles); -#endif - - // We can add data only if something to reply - error = AEPutParamDesc(theReply, keyDirectObject, &replyList); - - if (replyList.dataHandle) - AEDisposeDesc(&replyList); - - return error; -}; - -/* - * Handle the Get Text event from CodeWarrior - * - * Description - * ----------- - * - * The IDE sends the Get Text AppleEvent to the editor when it needs - * the source code from a file. For example, when the user issues a - * Check Syntax or Compile command, the compiler needs access to - * the source code contained in the file. - * - * Event Reply - * ----------- - * - * None. Put data in locations specified in the structure received. - * - * Remarks - * ------- - * - * When the editor receives this event, it must set the size of the handle - * in theText to fit the data in the file. It must then copy the entire - * contents of the specified file into the memory location specified in - * theText. - * - */ - -typedef struct CW_GetText CW_GetText; -struct CW_GetText // for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar -{ - FSSpec theFile; // identifies the file - Handle theText; // the location where you return the text (must be resized properly) - long *unused; // 0 (not used) - long *theDate; // where to put the modification date/time -}; - - pascal OSErr -Handle_KAHL_GTTX_AE( - const AppleEvent *theAEvent, - AppleEvent *theReply, - long refCon) -{ - OSErr error = noErr; - buf_T *buf; - int foundFile = false; - DescType typeCode; - CW_GetText GetTextData; - Size actualSize; - char_u *line; - char_u *fullbuffer = NULL; - long linesize; - long lineStart; - long BufferSize; - long lineno; - - error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize); - - if (error) - return error; - - FOR_ALL_BUFFERS(buf) - if (buf->b_ml.ml_mfp != NULL) - if (GetTextData.theFile.parID == buf->b_FSSpec.parID) - { - foundFile = true; - break; - } - - if (foundFile) - { - BufferSize = 0; // GetHandleSize(GetTextData.theText); - for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++) - { - // Must use the right buffer - line = ml_get_buf(buf, (linenr_T) lineno, FALSE); - linesize = STRLEN(line) + 1; - lineStart = BufferSize; - BufferSize += linesize; - // Resize handle to linesize+1 to include the linefeed - SetHandleSize(GetTextData.theText, BufferSize); - if (GetHandleSize(GetTextData.theText) != BufferSize) - { - break; // Simple handling for now - } - else - { - HLock(GetTextData.theText); - fullbuffer = (char_u *) *GetTextData.theText; - STRCPY((char_u *)(fullbuffer + lineStart), line); - fullbuffer[BufferSize-1] = '\r'; - HUnlock(GetTextData.theText); - } - } - if (fullbuffer != NULL) - { - HLock(GetTextData.theText); - fullbuffer[BufferSize-1] = 0; - HUnlock(GetTextData.theText); - } - if (foundFile == false) - *GetTextData.theDate = fnfErr; - else -// *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0; - *GetTextData.theDate = buf->b_mtime; - } - - error = HandleUnusedParms(theAEvent); - - return error; -} - -/* - * - */ - -/* - * Taken from MoreAppleEvents:ProcessHelpers - */ - pascal OSErr -FindProcessBySignature( - const OSType targetType, - const OSType targetCreator, - ProcessSerialNumberPtr psnPtr) -{ - OSErr anErr = noErr; - Boolean lookingForProcess = true; - - ProcessInfoRec infoRec; - - infoRec.processInfoLength = sizeof(ProcessInfoRec); - infoRec.processName = nil; - infoRec.processAppSpec = nil; - - psnPtr->lowLongOfPSN = kNoProcess; - psnPtr->highLongOfPSN = kNoProcess; - - while (lookingForProcess) - { - anErr = GetNextProcess(psnPtr); - if (anErr != noErr) - lookingForProcess = false; - else - { - anErr = GetProcessInformation(psnPtr, &infoRec); - if ((anErr == noErr) - && (infoRec.processType == targetType) - && (infoRec.processSignature == targetCreator)) - lookingForProcess = false; - } - } - - return anErr; -}//end FindProcessBySignature - - void -Send_KAHL_MOD_AE(buf_T *buf) -{ - OSErr anErr = noErr; - AEDesc targetAppDesc = { typeNull, nil }; - ProcessSerialNumber psn = { kNoProcess, kNoProcess }; - AppleEvent theReply = { typeNull, nil }; - AESendMode sendMode; - AppleEvent theEvent = {typeNull, nil }; - AEIdleUPP idleProcUPP = nil; - ModificationInfo ModData; - - - anErr = FindProcessBySignature('APPL', 'CWIE', &psn); - if (anErr == noErr) - { - anErr = AECreateDesc(typeProcessSerialNumber, &psn, - sizeof(ProcessSerialNumber), &targetAppDesc); - - if (anErr == noErr) - { - anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc, - kAutoGenerateReturnID, kAnyTransactionID, &theEvent); - } - - AEDisposeDesc(&targetAppDesc); - - // Add the parms - ModData.theFile = buf->b_FSSpec; - ModData.theDate = buf->b_mtime; - - if (anErr == noErr) - anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData)); - - if (idleProcUPP == nil) - sendMode = kAENoReply; - else - sendMode = kAEWaitReply; - - if (anErr == noErr) - anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil); - if (anErr == noErr && sendMode == kAEWaitReply) - { -// anErr = AEHGetHandlerError(&theReply); - } - (void) AEDisposeDesc(&theReply); - } -} -#endif // FEAT_CW_EDITOR - -/* - * ------------------------------------------------------------ - * Apple Event Handling procedure - * ------------------------------------------------------------ - */ -#ifdef USE_AEVENT - -/* - * Handle the Unused parms of an AppleEvent - */ - - OSErr -HandleUnusedParms(const AppleEvent *theAEvent) -{ - OSErr error; - long actualSize; - DescType dummyType; - AEKeyword missedKeyword; - - // Get the "missed keyword" attribute from the AppleEvent. - error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr, - typeKeyword, &dummyType, - (Ptr)&missedKeyword, sizeof(missedKeyword), - &actualSize); - - // If the descriptor isn't found, then we got the required parameters. - if (error == errAEDescNotFound) - { - error = noErr; - } - else - { -#if 0 - // Why is this removed? - error = errAEEventNotHandled; -#endif - } - - return error; -} - - -/* - * Handle the ODoc AppleEvent - * - * Deals with all files dragged to the application icon. - * - */ - -typedef struct SelectionRange SelectionRange; -struct SelectionRange // for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar -{ - short unused1; // 0 (not used) - short lineNum; // line to select (<0 to specify range) - long startRange; // start of selection range (if line < 0) - long endRange; // end of selection range (if line < 0) - long unused2; // 0 (not used) - long theDate; // modification date/time -}; - -static long drop_numFiles; -static short drop_gotPosition; -static SelectionRange drop_thePosition; - - static void -drop_callback(void *cookie UNUSED) -{ - // TODO: Handle the goto/select line more cleanly - if ((drop_numFiles == 1) & (drop_gotPosition)) - { - if (drop_thePosition.lineNum >= 0) - { - lnum = drop_thePosition.lineNum + 1; - // oap->motion_type = MLINE; - // setpcmark(); - if (lnum < 1L) - lnum = 1L; - else if (lnum > curbuf->b_ml.ml_line_count) - lnum = curbuf->b_ml.ml_line_count; - curwin->w_cursor.lnum = lnum; - curwin->w_cursor.col = 0; - // beginline(BL_SOL | BL_FIX); - } - else - goto_byte(drop_thePosition.startRange + 1); - } - - // Update the screen display - update_screen(NOT_VALID); - - // Select the text if possible - if (drop_gotPosition) - { - VIsual_active = TRUE; - VIsual_select = FALSE; - VIsual = curwin->w_cursor; - if (drop_thePosition.lineNum < 0) - { - VIsual_mode = 'v'; - goto_byte(drop_thePosition.endRange); - } - else - { - VIsual_mode = 'V'; - VIsual.col = 0; - } - } -} - -/* - * The IDE uses the optional keyAEPosition parameter to tell the ed- - * itor the selection range. If lineNum is zero or greater, scroll the text - * to the specified line. If lineNum is less than zero, use the values in - * startRange and endRange to select the specified characters. Scroll - * the text to display the selection. If lineNum, startRange, and - * endRange are all negative, there is no selection range specified. - */ - pascal OSErr -HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) -{ - /* - * TODO: Clean up the code with convert the AppleEvent into - * a ":args" - */ - OSErr error = noErr; -// OSErr firstError = noErr; -// short numErrors = 0; - AEDesc theList; - DescType typeCode; - long numFiles; - // long fileCount; - char_u **fnames; -// char_u fname[256]; - Size actualSize; - SelectionRange thePosition; - short gotPosition = false; - long lnum; - - // the direct object parameter is the list of aliases to files (one or more) - error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList); - if (error) - return error; - - - error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize); - if (error == noErr) - gotPosition = true; - if (error == errAEDescNotFound) - error = noErr; - if (error) - return error; - -/* - error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition); - - if (^error) then - { - if (thePosition.lineNum >= 0) - { - // Goto this line - } - else - { - // Set the range char wise - } - } - */ - - reset_VIsual(); - fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error); - - if (error) - { - // TODO: empty fnames[] first - vim_free(fnames); - return (error); - } - - if (starting > 0) - { - int i; - char_u *p; - int fnum = -1; - - // these are the initial files dropped on the Vim icon - for (i = 0 ; i < numFiles; i++) - { - if (ga_grow(&global_alist.al_ga, 1) == FAIL - || (p = vim_strsave(fnames[i])) == NULL) - mch_exit(2); - else - alist_add(&global_alist, p, 2); - if (fnum == -1) - fnum = GARGLIST[GARGCOUNT - 1].ae_fnum; - } - - // If the file name was already in the buffer list we need to switch - // to it. - if (curbuf->b_fnum != fnum) - { - char_u cmd[30]; - - vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum); - do_cmdline_cmd(cmd); - } - - // Change directory to the location of the first file. - if (GARGCOUNT > 0 - && vim_chdirfile(alist_name(&GARGLIST[0]), "drop") == OK) - shorten_fnames(TRUE); - - goto finished; - } - - // Handle the drop, :edit to get to the file - drop_numFiles = numFiles; - drop_gotPosition = gotPosition; - drop_thePosition = thePosition; - handle_drop(numFiles, fnames, FALSE, drop_callback, NULL); - - setcursor(); - out_flush(); - - // Fake mouse event to wake from stall - PostEvent(mouseUp, 0); - -finished: - AEDisposeDesc(&theList); // dispose what we allocated - - error = HandleUnusedParms(theAEvent); - return error; -} - -/* - * - */ - pascal OSErr -Handle_aevt_oapp_AE( - const AppleEvent *theAEvent, - AppleEvent *theReply, - long refCon) -{ - OSErr error = noErr; - - error = HandleUnusedParms(theAEvent); - return error; -} - -/* - * - */ - pascal OSErr -Handle_aevt_quit_AE( - const AppleEvent *theAEvent, - AppleEvent *theReply, - long refCon) -{ - OSErr error = noErr; - - error = HandleUnusedParms(theAEvent); - if (error) - return error; - - // Need to fake a :confirm qa - do_cmdline_cmd((char_u *)"confirm qa"); - - return error; -} - -/* - * - */ - pascal OSErr -Handle_aevt_pdoc_AE( - const AppleEvent *theAEvent, - AppleEvent *theReply, - long refCon) -{ - OSErr error = noErr; - - error = HandleUnusedParms(theAEvent); - - return error; -} - -/* - * Handling of unknown AppleEvent - * - * (Just get rid of all the parms) - */ - pascal OSErr -Handle_unknown_AE( - const AppleEvent *theAEvent, - AppleEvent *theReply, - long refCon) -{ - OSErr error = noErr; - - error = HandleUnusedParms(theAEvent); - - return error; -} - - -/* - * Install the various AppleEvent Handlers - */ - OSErr -InstallAEHandlers(void) -{ - OSErr error; - - // install open application handler - error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, - NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false); - if (error) - return error; - - // install quit application handler - error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, - NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false); - if (error) - return error; - - // install open document handler - error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, - NewAEEventHandlerUPP(HandleODocAE), 0, false); - if (error) - return error; - - // install print document handler - error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, - NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false); - -// Install Core Suite -#if 0 - error = AEInstallEventHandler(kAECoreSuite, kAEClone, - NewAEEventHandlerUPP(Handle_unknown_AE), nil, false); - - error = AEInstallEventHandler(kAECoreSuite, kAEClose, - NewAEEventHandlerUPP(Handle_unknown_AE), nil, false); - - error = AEInstallEventHandler(kAECoreSuite, kAECountElements, - NewAEEventHandlerUPP(Handle_unknown_AE), nil, false); - - error = AEInstallEventHandler(kAECoreSuite, kAECreateElement, - NewAEEventHandlerUPP(Handle_unknown_AE), nil, false); - - error = AEInstallEventHandler(kAECoreSuite, kAEDelete, - NewAEEventHandlerUPP(Handle_unknown_AE), nil, false); - - error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist, - NewAEEventHandlerUPP(Handle_unknown_AE), nil, false); - - error = AEInstallEventHandler(kAECoreSuite, kAEGetData, - NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false); - - error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize, - NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false); - - error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo, - NewAEEventHandlerUPP(Handle_unknown_AE), nil, false); - - error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo, - NewAEEventHandlerUPP(Handle_unknown_AE), nil, false); - - error = AEInstallEventHandler(kAECoreSuite, kAEMove, - NewAEEventHandlerUPP(Handle_unknown_AE), nil, false); - - error = AEInstallEventHandler(kAECoreSuite, kAESave, - NewAEEventHandlerUPP(Handle_unknown_AE), nil, false); - - error = AEInstallEventHandler(kAECoreSuite, kAESetData, - NewAEEventHandlerUPP(Handle_unknown_AE), nil, false); -#endif - -#ifdef FEAT_CW_EDITOR - /* - * Bind codewarrior support handlers - */ - error = AEInstallEventHandler('KAHL', 'GTTX', - NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false); - if (error) - return error; - error = AEInstallEventHandler('KAHL', 'SRCH', - NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false); - if (error) - return error; - error = AEInstallEventHandler('KAHL', 'MOD ', - NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false); -#endif - - return error; - -} -#endif // USE_AEVENT - - -/* - * Callback function, installed by InstallFontPanelHandler(), below, - * to handle Font Panel events. - */ - static OSStatus -FontPanelHandler( - EventHandlerCallRef inHandlerCallRef, - EventRef inEvent, - void *inUserData) -{ - if (GetEventKind(inEvent) == kEventFontPanelClosed) - { - gFontPanelInfo.isPanelVisible = false; - return noErr; - } - - if (GetEventKind(inEvent) == kEventFontSelection) - { - OSStatus status; - FMFontFamily newFamily; - FMFontSize newSize; - FMFontStyle newStyle; - - // Retrieve the font family ID number. - status = GetEventParameter(inEvent, kEventParamFMFontFamily, - /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL, - /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL, - &newFamily); - if (status == noErr) - gFontPanelInfo.family = newFamily; - - // Retrieve the font size. - status = GetEventParameter(inEvent, kEventParamFMFontSize, - typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize); - if (status == noErr) - gFontPanelInfo.size = newSize; - - // Retrieve the font style (bold, etc.). Currently unused. - status = GetEventParameter(inEvent, kEventParamFMFontStyle, - typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle); - if (status == noErr) - gFontPanelInfo.style = newStyle; - } - return noErr; -} - - - static void -InstallFontPanelHandler(void) -{ - EventTypeSpec eventTypes[2]; - EventHandlerUPP handlerUPP; - // EventHandlerRef handlerRef; - - eventTypes[0].eventClass = kEventClassFont; - eventTypes[0].eventKind = kEventFontSelection; - eventTypes[1].eventClass = kEventClassFont; - eventTypes[1].eventKind = kEventFontPanelClosed; - - handlerUPP = NewEventHandlerUPP(FontPanelHandler); - - InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes, - /*userData=*/NULL, /*handlerRef=*/NULL); -} - - -/* - * Fill the buffer pointed to by outName with the name and size - * of the font currently selected in the Font Panel. - */ -#define FONT_STYLE_BUFFER_SIZE 32 - static void -GetFontPanelSelection(char_u *outName) -{ - Str255 buf; - ByteCount fontNameLen = 0; - ATSUFontID fid; - char_u styleString[FONT_STYLE_BUFFER_SIZE]; - - if (!outName) - return; - - if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr) - { - // Canonicalize localized font names - if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family, - gFontPanelInfo.style, &fid, NULL) != noErr) - return; - - // Request font name with Mac encoding (otherwise we could - // get an unwanted utf-16 name) - if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform, - kFontNoScriptCode, kFontNoLanguageCode, - 255, (char *)outName, &fontNameLen, NULL) != noErr) - return; - - // Only encode font size, because style (bold, italic, etc) is - // already part of the font full name - vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d", - gFontPanelInfo.size/*, - ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""), - ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""), - ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/); - - if ((fontNameLen + STRLEN(styleString)) < 255) - STRCPY(outName + fontNameLen, styleString); - } - else - { - *outName = NUL; - } -} - - -/* - * ------------------------------------------------------------ - * Unfiled yet - * ------------------------------------------------------------ - */ - -/* - * gui_mac_get_menu_item_index - * - * Returns the index inside the menu where - */ - short // Should we return MenuItemIndex? -gui_mac_get_menu_item_index(vimmenu_T *pMenu) -{ - short index; - short itemIndex = -1; - vimmenu_T *pBrother; - - // Only menu without parent are the: - // -menu in the menubar - // -popup menu - // -toolbar (guess) - // - // Which are not items anyway. - if (pMenu->parent) - { - // Start from the Oldest Brother - pBrother = pMenu->parent->children; - index = 1; - while ((pBrother) && (itemIndex == -1)) - { - if (pBrother == pMenu) - itemIndex = index; - index++; - pBrother = pBrother->next; - } - } - return itemIndex; -} - - static vimmenu_T * -gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu) -{ - short index; - vimmenu_T *pChildMenu; - vimmenu_T *pElder = pMenu->parent; - - - // Only menu without parent are the: - // -menu in the menubar - // -popup menu - // -toolbar (guess) - // - // Which are not items anyway. - - if ((pElder) && (pElder->submenu_id == menuID)) - { - for (index = 1; (index != itemIndex) && (pMenu != NULL); index++) - pMenu = pMenu->next; - } - else - { - for (; pMenu != NULL; pMenu = pMenu->next) - { - if (pMenu->children != NULL) - { - pChildMenu = gui_mac_get_vim_menu - (menuID, itemIndex, pMenu->children); - if (pChildMenu) - { - pMenu = pChildMenu; - break; - } - } - } - } - return pMenu; -} - -/* - * ------------------------------------------------------------ - * MacOS Feedback procedures - * ------------------------------------------------------------ - */ - pascal - void -gui_mac_drag_thumb(ControlHandle theControl, short partCode) -{ - scrollbar_T *sb; - int value, dragging; - ControlHandle theControlToUse; - int dont_scroll_save = dont_scroll; - - theControlToUse = dragged_sb; - - sb = gui_find_scrollbar((long) GetControlReference(theControlToUse)); - - if (sb == NULL) - return; - - // Need to find value by diff between Old Poss New Pos - value = GetControl32BitValue(theControlToUse); - dragging = (partCode != 0); - - // When "allow_scrollbar" is FALSE still need to remember the new - // position, but don't actually scroll by setting "dont_scroll". - dont_scroll = !allow_scrollbar; - gui_drag_scrollbar(sb, value, dragging); - dont_scroll = dont_scroll_save; -} - - pascal - void -gui_mac_scroll_action(ControlHandle theControl, short partCode) -{ - // TODO: have live support - scrollbar_T *sb, *sb_info; - long data; - long value; - int page; - int dragging = FALSE; - int dont_scroll_save = dont_scroll; - - sb = gui_find_scrollbar((long)GetControlReference(theControl)); - - if (sb == NULL) - return; - - if (sb->wp != NULL) // Left or right scrollbar - { - /* - * Careful: need to get scrollbar info out of first (left) scrollbar - * for window, but keep real scrollbar too because we must pass it to - * gui_drag_scrollbar(). - */ - sb_info = &sb->wp->w_scrollbars[0]; - - if (sb_info->size > 5) - page = sb_info->size - 2; // use two lines of context - else - page = sb_info->size; - } - else // Bottom scrollbar - { - sb_info = sb; - page = curwin->w_width - 5; - } - - switch (partCode) - { - case kControlUpButtonPart: data = -1; break; - case kControlDownButtonPart: data = 1; break; - case kControlPageDownPart: data = page; break; - case kControlPageUpPart: data = -page; break; - default: data = 0; break; - } - - value = sb_info->value + data; -// if (value > sb_info->max) -// value = sb_info->max; -// else if (value < 0) -// value = 0; - - // When "allow_scrollbar" is FALSE still need to remember the new - // position, but don't actually scroll by setting "dont_scroll". - dont_scroll = !allow_scrollbar; - gui_drag_scrollbar(sb, value, dragging); - dont_scroll = dont_scroll_save; - - out_flush(); - gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max); - -#if 0 - if (sb_info->wp != NULL) - { - win_T *wp; - int sb_num; - - sb_num = 0; - for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp)) - sb_num++; - - if (wp != NULL) - { - current_scrollbar = sb_num; - scrollbar_value = value; - gui_do_scroll(); - gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max); - } - } -#endif -} - -/* - * ------------------------------------------------------------ - * MacOS Click Handling procedures - * ------------------------------------------------------------ - */ - - -/* - * Handle a click inside the window, it may happens in the - * scrollbar or the contents. - * - * TODO: Add support for potential TOOLBAR - */ - void -gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow) -{ - Point thePoint; - int_u vimModifiers; - short thePortion; - ControlHandle theControl; - int vimMouseButton; - short dblClick; - - thePoint = theEvent->where; - GlobalToLocal(&thePoint); - SelectWindow(whichWindow); - - thePortion = FindControl(thePoint, whichWindow, &theControl); - - if (theControl != NUL) - { - // We hit a scrollbar - - if (thePortion != kControlIndicatorPart) - { - dragged_sb = theControl; - TrackControl(theControl, thePoint, gScrollAction); - dragged_sb = NULL; - } - else - { - dragged_sb = theControl; -#if 1 - TrackControl(theControl, thePoint, gScrollDrag); -#else - TrackControl(theControl, thePoint, NULL); -#endif - // pass 0 as the part to tell gui_mac_drag_thumb, that the mouse - // button has been released - gui_mac_drag_thumb(theControl, 0); // Should it be thePortion ? (Dany) - dragged_sb = NULL; - } - } - else - { - // We are inside the contents - - // Convert the CTRL, OPTION, SHIFT and CMD key - vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers); - - // Defaults to MOUSE_LEFT as there's only one mouse button - vimMouseButton = MOUSE_LEFT; - - // Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT - // TODO: NEEDED? - clickIsPopup = FALSE; - - if (mouse_model_popup() && IsShowContextualMenuClick(theEvent)) - { - vimMouseButton = MOUSE_RIGHT; - vimModifiers &= ~MOUSE_CTRL; - clickIsPopup = TRUE; - } - - // Is it a double click ? - dblClick = ((theEvent->when - lastMouseTick) < GetDblTime()); - - // Send the mouse click to Vim - gui_send_mouse_event(vimMouseButton, thePoint.h, - thePoint.v, dblClick, vimModifiers); - - // Create the rectangle around the cursor to detect - // the mouse dragging -#if 0 - // TODO: Do we need to this even for the contextual menu? - // It may be require for popup_setpos, but for popup? - if (vimMouseButton == MOUSE_LEFT) -#endif - { - SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)), - FILL_Y(Y_2_ROW(thePoint.v)), - FILL_X(X_2_COL(thePoint.h)+1), - FILL_Y(Y_2_ROW(thePoint.v)+1)); - - dragRectEnbl = TRUE; - dragRectControl = kCreateRect; - } - } -} - -/* - * Handle the click in the titlebar (to move the window) - */ - void -gui_mac_doInDragClick(Point where, WindowPtr whichWindow) -{ - Rect movingLimits; - Rect *movingLimitsPtr = &movingLimits; - - // TODO: may try to prevent move outside screen? - movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits); - DragWindow(whichWindow, where, movingLimitsPtr); -} - -/* - * Handle the click in the grow box - */ - void -gui_mac_doInGrowClick(Point where, WindowPtr whichWindow) -{ - - long newSize; - unsigned short newWidth; - unsigned short newHeight; - Rect resizeLimits; - Rect *resizeLimitsPtr = &resizeLimits; - Rect NewContentRect; - - resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits); - - // Set the minimum size - // TODO: Should this come from Vim? - resizeLimits.top = 100; - resizeLimits.left = 100; - - newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect); - newWidth = NewContentRect.right - NewContentRect.left; - newHeight = NewContentRect.bottom - NewContentRect.top; - gui_resize_shell(newWidth, newHeight); - gui_mch_set_bg_color(gui.back_pixel); - gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH); -} - -/* - * Handle the click in the zoom box - */ - static void -gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow) -{ - Rect r; - Point p; - short thePart; - - // ideal width is current - p.h = Columns * gui.char_width + 2 * gui.border_offset; - if (gui.which_scrollbars[SBAR_LEFT]) - p.h += gui.scrollbar_width; - if (gui.which_scrollbars[SBAR_RIGHT]) - p.h += gui.scrollbar_width; - // ideal height is as high as we can get - p.v = 15 * 1024; - - thePart = IsWindowInStandardState(whichWindow, &p, &r) - ? inZoomIn : inZoomOut; - - if (!TrackBox(whichWindow, theEvent->where, thePart)) - return; - - // use returned width - p.h = r.right - r.left; - // adjust returned height - p.v = r.bottom - r.top - 2 * gui.border_offset; - if (gui.which_scrollbars[SBAR_BOTTOM]) - p.v -= gui.scrollbar_height; - p.v -= p.v % gui.char_height; - p.v += 2 * gui.border_width; - if (gui.which_scrollbars[SBAR_BOTTOM]) - p.v += gui.scrollbar_height; - - ZoomWindowIdeal(whichWindow, thePart, &p); - - GetWindowBounds(whichWindow, kWindowContentRgn, &r); - gui_resize_shell(r.right - r.left, r.bottom - r.top); - gui_mch_set_bg_color(gui.back_pixel); - gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH); -} - -/* - * ------------------------------------------------------------ - * MacOS Event Handling procedure - * ------------------------------------------------------------ - */ - -/* - * Handle the Update Event - */ - - void -gui_mac_doUpdateEvent(EventRecord *event) -{ - WindowPtr whichWindow; - GrafPtr savePort; - RgnHandle updateRgn; - Rect updateRect; - Rect *updateRectPtr; - Rect rc; - Rect growRect; - RgnHandle saveRgn; - - - updateRgn = NewRgn(); - if (updateRgn == NULL) - return; - - // This could be done by the caller as we - // don't require anything else out of the event - whichWindow = (WindowPtr) event->message; - - // Save Current Port - GetPort(&savePort); - - // Select the Window's Port - SetPortWindowPort(whichWindow); - - // Let's update the window - BeginUpdate(whichWindow); - // Redraw the biggest rectangle covering the area - // to be updated. - GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn); -# if 0 - // Would be more appropriate to use the following but doesn't - // seem to work under MacOS X (Dany) - GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn); -# endif - - // Use the HLock useless in Carbon? Is it harmful? - HLock((Handle) updateRgn); - - updateRectPtr = GetRegionBounds(updateRgn, &updateRect); -# if 0 - // Code from original Carbon Port (using GetWindowRegion. - // I believe the UpdateRgn is already in local (Dany) - GlobalToLocal(&topLeft(updateRect)); // preCarbon? - GlobalToLocal(&botRight(updateRect)); -# endif - // Update the content (i.e. the text) - gui_redraw(updateRectPtr->left, updateRectPtr->top, - updateRectPtr->right - updateRectPtr->left, - updateRectPtr->bottom - updateRectPtr->top); - // Clear the border areas if needed - gui_mch_set_bg_color(gui.back_pixel); - if (updateRectPtr->left < FILL_X(0)) - { - SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows)); - EraseRect(&rc); - } - if (updateRectPtr->top < FILL_Y(0)) - { - SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0)); - EraseRect(&rc); - } - if (updateRectPtr->right > FILL_X(Columns)) - { - SetRect(&rc, FILL_X(Columns), 0, - FILL_X(Columns) + gui.border_offset, FILL_Y(Rows)); - EraseRect(&rc); - } - if (updateRectPtr->bottom > FILL_Y(Rows)) - { - SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset, - FILL_Y(Rows) + gui.border_offset); - EraseRect(&rc); - } - HUnlock((Handle) updateRgn); - DisposeRgn(updateRgn); - - // Update scrollbars - DrawControls(whichWindow); - - // Update the GrowBox - // Taken from FAQ 33-27 - saveRgn = NewRgn(); - GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect); - GetClip(saveRgn); - ClipRect(&growRect); - DrawGrowIcon(whichWindow); - SetClip(saveRgn); - DisposeRgn(saveRgn); - EndUpdate(whichWindow); - - // Restore original Port - SetPort(savePort); -} - -/* - * Handle the activate/deactivate event - * (apply to a window) - */ - void -gui_mac_doActivateEvent(EventRecord *event) -{ - WindowPtr whichWindow; - - whichWindow = (WindowPtr) event->message; - // Dim scrollbars - if (whichWindow == gui.VimWindow) - { - ControlRef rootControl; - GetRootControl(gui.VimWindow, &rootControl); - if ((event->modifiers) & activeFlag) - ActivateControl(rootControl); - else - DeactivateControl(rootControl); - } - - // Activate - gui_focus_change((event->modifiers) & activeFlag); -} - - -/* - * Handle the suspend/resume event - * (apply to the application) - */ - void -gui_mac_doSuspendEvent(EventRecord *event) -{ - // The frontmost application just changed - - // NOTE: the suspend may happen before the deactivate - // seen on MacOS X - - // May not need to change focus as the window will - // get an activate/deactivate event - if (event->message & 1) - // Resume - gui_focus_change(TRUE); - else - // Suspend - gui_focus_change(FALSE); -} - -/* - * Handle the key - */ -#ifdef USE_CARBONKEYHANDLER - static pascal OSStatus -gui_mac_handle_window_activate( - EventHandlerCallRef nextHandler, - EventRef theEvent, - void *data) -{ - UInt32 eventClass = GetEventClass(theEvent); - UInt32 eventKind = GetEventKind(theEvent); - - if (eventClass == kEventClassWindow) - { - switch (eventKind) - { - case kEventWindowActivated: - im_on_window_switch(TRUE); - return noErr; - - case kEventWindowDeactivated: - im_on_window_switch(FALSE); - return noErr; - } - } - - return eventNotHandledErr; -} - - static pascal OSStatus -gui_mac_handle_text_input( - EventHandlerCallRef nextHandler, - EventRef theEvent, - void *data) -{ - UInt32 eventClass = GetEventClass(theEvent); - UInt32 eventKind = GetEventKind(theEvent); - - if (eventClass != kEventClassTextInput) - return eventNotHandledErr; - - if ((kEventTextInputUpdateActiveInputArea != eventKind) && - (kEventTextInputUnicodeForKeyEvent != eventKind) && - (kEventTextInputOffsetToPos != eventKind) && - (kEventTextInputPosToOffset != eventKind) && - (kEventTextInputGetSelectedText != eventKind)) - return eventNotHandledErr; - - switch (eventKind) - { - case kEventTextInputUpdateActiveInputArea: - return gui_mac_update_input_area(nextHandler, theEvent); - case kEventTextInputUnicodeForKeyEvent: - return gui_mac_unicode_key_event(nextHandler, theEvent); - - case kEventTextInputOffsetToPos: - case kEventTextInputPosToOffset: - case kEventTextInputGetSelectedText: - break; - } - - return eventNotHandledErr; -} - - static pascal -OSStatus gui_mac_update_input_area( - EventHandlerCallRef nextHandler, - EventRef theEvent) -{ - return eventNotHandledErr; -} - -static int dialog_busy = FALSE; // TRUE when gui_mch_dialog() wants the - // keys - -# define INLINE_KEY_BUFFER_SIZE 80 - static pascal OSStatus -gui_mac_unicode_key_event( - EventHandlerCallRef nextHandler, - EventRef theEvent) -{ - // Multibyte-friendly key event handler - OSStatus err = -1; - UInt32 actualSize; - UniChar *text; - char_u result[INLINE_KEY_BUFFER_SIZE]; - short len = 0; - UInt32 key_sym; - char charcode; - int key_char; - UInt32 modifiers, vimModifiers; - size_t encLen; - char_u *to = NULL; - Boolean isSpecial = FALSE; - int i; - EventRef keyEvent; - - // Mask the mouse (as per user setting) - if (p_mh) - ObscureCursor(); - - // Don't use the keys when the dialog wants them. - if (dialog_busy) - return eventNotHandledErr; - - if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText, - typeUnicodeText, NULL, 0, &actualSize, NULL)) - return eventNotHandledErr; - - text = alloc(actualSize); - if (!text) - return eventNotHandledErr; - - err = GetEventParameter(theEvent, kEventParamTextInputSendText, - typeUnicodeText, NULL, actualSize, NULL, text); - require_noerr(err, done); - - err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent, - typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent); - require_noerr(err, done); - - err = GetEventParameter(keyEvent, kEventParamKeyModifiers, - typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); - require_noerr(err, done); - - err = GetEventParameter(keyEvent, kEventParamKeyCode, - typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym); - require_noerr(err, done); - - err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes, - typeChar, NULL, sizeof(char), NULL, &charcode); - require_noerr(err, done); - -#ifndef USE_CMD_KEY - if (modifiers & cmdKey) - goto done; // Let system handle Cmd+... -#endif - - key_char = charcode; - vimModifiers = EventModifiers2VimModifiers(modifiers); - - // Find the special key (eg., for cursor keys) - if (actualSize <= sizeof(UniChar) && - ((text[0] < 0x20) || (text[0] == 0x7f))) - { - for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i) - if (special_keys[i].key_sym == key_sym) - { - key_char = TO_SPECIAL(special_keys[i].vim_code0, - special_keys[i].vim_code1); - key_char = simplify_key(key_char, - (int *)&vimModifiers); - isSpecial = TRUE; - break; - } - } - - // Intercept CMD-. and CTRL-c - if (((modifiers & controlKey) && key_char == 'c') || - ((modifiers & cmdKey) && key_char == '.')) - got_int = TRUE; - - if (!isSpecial) - { - // remove SHIFT for keys that are already shifted, e.g., - // '(' and '*' - if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char)) - vimModifiers &= ~MOD_MASK_SHIFT; - - // remove CTRL from keys that already have it - if (key_char < 0x20) - vimModifiers &= ~MOD_MASK_CTRL; - - // don't process unicode characters here - if (!IS_SPECIAL(key_char)) - { - // Following code to simplify and consolidate vimModifiers - // taken liberally from gui_w48.c - key_char = simplify_key(key_char, (int *)&vimModifiers); - - // Unify modifiers somewhat. No longer use ALT to set the 8th bit. - key_char = extract_modifiers(key_char, (int *)&vimModifiers, - FALSE, NULL); - if (key_char == CSI) - key_char = K_CSI; - - if (IS_SPECIAL(key_char)) - isSpecial = TRUE; - } - } - - if (vimModifiers) - { - result[len++] = CSI; - result[len++] = KS_MODIFIER; - result[len++] = vimModifiers; - } - - if (isSpecial && IS_SPECIAL(key_char)) - { - result[len++] = CSI; - result[len++] = K_SECOND(key_char); - result[len++] = K_THIRD(key_char); - } - else - { - encLen = actualSize; - to = mac_utf16_to_enc(text, actualSize, &encLen); - if (to) - { - // This is basically add_to_input_buf_csi() - for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i) - { - result[len++] = to[i]; - if (to[i] == CSI) - { - result[len++] = KS_EXTRA; - result[len++] = (int)KE_CSI; - } - } - vim_free(to); - } - } - - add_to_input_buf(result, len); - err = noErr; - -done: - vim_free(text); - if (err == noErr) - { - // Fake event to wake up WNE (required to get - // key repeat working - PostEvent(keyUp, 0); - return noErr; - } - - return eventNotHandledErr; -} -#else - void -gui_mac_doKeyEvent(EventRecord *theEvent) -{ - // TODO: add support for COMMAND KEY - long menu; - unsigned char string[20]; - short num, i; - short len = 0; - KeySym key_sym; - int key_char; - int modifiers; - int simplify = FALSE; - - // Mask the mouse (as per user setting) - if (p_mh) - ObscureCursor(); - - // Get the key code and its ASCII representation - key_sym = ((theEvent->message & keyCodeMask) >> 8); - key_char = theEvent->message & charCodeMask; - num = 1; - - // Intercept CTRL-C - if (theEvent->modifiers & controlKey) - { - if (key_char == Ctrl_C && ctrl_c_interrupts) - got_int = TRUE; - else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0 - && (key_char == '2' || key_char == '6')) - { - // CTRL-^ and CTRL-@ don't work in the normal way. - if (key_char == '2') - key_char = Ctrl_AT; - else - key_char = Ctrl_HAT; - theEvent->modifiers = 0; - } - } - - // Intercept CMD-. - if (theEvent->modifiers & cmdKey) - if (key_char == '.') - got_int = TRUE; - - // Handle command key as per menu - // TODO: should override be allowed? Require YAO or could use 'winaltkey' - if (theEvent->modifiers & cmdKey) - // Only accept CMD alone or with CAPLOCKS and the mouse button. - // Why the mouse button? - if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0) - { - menu = MenuKey(key_char); - if (HiWord(menu)) - { - gui_mac_handle_menu(menu); - return; - } - } - - // Convert the modifiers - modifiers = EventModifiers2VimModifiers(theEvent->modifiers); - - - // Handle special keys. -#if 0 - // Why has this been removed? - if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey))) -#endif - { - // Find the special key (for non-printable keyt_char) - if ((key_char < 0x20) || (key_char == 0x7f)) - for (i = 0; special_keys[i].key_sym != (KeySym)0; i++) - if (special_keys[i].key_sym == key_sym) - { -# if 0 - // We currently don't have not so special key - if (special_keys[i].vim_code1 == NUL) - key_char = special_keys[i].vim_code0; - else -# endif - key_char = TO_SPECIAL(special_keys[i].vim_code0, - special_keys[i].vim_code1); - simplify = TRUE; - break; - } - } - - // For some keys the modifier is included in the char itself. - if (simplify || key_char == TAB || key_char == ' ') - key_char = simplify_key(key_char, &modifiers); - - // Add the modifier to the input bu if needed - // Do not want SHIFT-A or CTRL-A with modifier - if (!IS_SPECIAL(key_char) - && key_sym != vk_Space - && key_sym != vk_Tab - && key_sym != vk_Return - && key_sym != vk_Enter - && key_sym != vk_Esc) - { -#if 1 - // Clear modifiers when only one modifier is set - if ((modifiers == MOD_MASK_SHIFT) - || (modifiers == MOD_MASK_CTRL) - || (modifiers == MOD_MASK_ALT)) - modifiers = 0; -#else - if (modifiers & MOD_MASK_CTRL) - modifiers = modifiers & ~MOD_MASK_CTRL; - if (modifiers & MOD_MASK_ALT) - modifiers = modifiers & ~MOD_MASK_ALT; - if (modifiers & MOD_MASK_SHIFT) - modifiers = modifiers & ~MOD_MASK_SHIFT; -#endif - } - if (modifiers) - { - string[len++] = CSI; - string[len++] = KS_MODIFIER; - string[len++] = modifiers; - } - - if (IS_SPECIAL(key_char)) - { - string[len++] = CSI; - string[len++] = K_SECOND(key_char); - string[len++] = K_THIRD(key_char); - } - else - { - // Convert characters when needed (e.g., from MacRoman to latin1). - // This doesn't work for the NUL byte. - if (input_conv.vc_type != CONV_NONE && key_char > 0) - { - char_u from[2], *to; - int l; - - from[0] = key_char; - from[1] = NUL; - l = 1; - to = string_convert(&input_conv, from, &l); - if (to != NULL) - { - for (i = 0; i < l && len < 19; i++) - { - if (to[i] == CSI) - { - string[len++] = KS_EXTRA; - string[len++] = KE_CSI; - } - else - string[len++] = to[i]; - } - vim_free(to); - } - else - string[len++] = key_char; - } - else - string[len++] = key_char; - } - - if (len == 1 && string[0] == CSI) - { - // Turn CSI into K_CSI. - string[ len++ ] = KS_EXTRA; - string[ len++ ] = KE_CSI; - } - - add_to_input_buf(string, len); -} -#endif - -/* - * Handle MouseClick - */ - void -gui_mac_doMouseDownEvent(EventRecord *theEvent) -{ - short thePart; - WindowPtr whichWindow; - - thePart = FindWindow(theEvent->where, &whichWindow); - -#ifdef FEAT_GUI_TABLINE - // prevent that the vim window size changes if it's activated by a - // click into the tab pane - if (whichWindow == drawer) - return; -#endif - - switch (thePart) - { - case (inDesk): - // TODO: what to do? - break; - - case (inMenuBar): - gui_mac_handle_menu(MenuSelect(theEvent->where)); - break; - - case (inContent): - gui_mac_doInContentClick(theEvent, whichWindow); - break; - - case (inDrag): - gui_mac_doInDragClick(theEvent->where, whichWindow); - break; - - case (inGrow): - gui_mac_doInGrowClick(theEvent->where, whichWindow); - break; - - case (inGoAway): - if (TrackGoAway(whichWindow, theEvent->where)) - gui_shell_closed(); - break; - - case (inZoomIn): - case (inZoomOut): - gui_mac_doInZoomClick(theEvent, whichWindow); - break; - } -} - -/* - * Handle MouseMoved - * [this event is a moving in and out of a region] - */ - void -gui_mac_doMouseMovedEvent(EventRecord *event) -{ - Point thePoint; - int_u vimModifiers; - - thePoint = event->where; - GlobalToLocal(&thePoint); - vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers); - - if (!Button()) - gui_mouse_moved(thePoint.h, thePoint.v); - else - if (!clickIsPopup) - gui_send_mouse_event(MOUSE_DRAG, thePoint.h, - thePoint.v, FALSE, vimModifiers); - - // Reset the region from which we move in and out - SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)), - FILL_Y(Y_2_ROW(thePoint.v)), - FILL_X(X_2_COL(thePoint.h)+1), - FILL_Y(Y_2_ROW(thePoint.v)+1)); - - if (dragRectEnbl) - dragRectControl = kCreateRect; - -} - -/* - * Handle the mouse release - */ - void -gui_mac_doMouseUpEvent(EventRecord *theEvent) -{ - Point thePoint; - int_u vimModifiers; - - // TODO: Properly convert the Contextual menu mouse-up - // Potential source of the double menu - lastMouseTick = theEvent->when; - dragRectEnbl = FALSE; - dragRectControl = kCreateEmpty; - thePoint = theEvent->where; - GlobalToLocal(&thePoint); - - vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers); - if (clickIsPopup) - { - vimModifiers &= ~MOUSE_CTRL; - clickIsPopup = FALSE; - } - gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers); -} - - static pascal OSStatus -gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent, - void *data) -{ - Point point; - Rect bounds; - UInt32 mod; - SInt32 delta; - int_u vim_mod; - EventMouseWheelAxis axis; - - if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis, - typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis) - && axis != kEventMouseWheelAxisY) - goto bail; // Vim only does up-down scrolling - - if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta, - typeSInt32, NULL, sizeof(SInt32), NULL, &delta)) - goto bail; - if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation, - typeQDPoint, NULL, sizeof(Point), NULL, &point)) - goto bail; - if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers, - typeUInt32, NULL, sizeof(UInt32), NULL, &mod)) - goto bail; - - vim_mod = 0; - if (mod & shiftKey) - vim_mod |= MOUSE_SHIFT; - if (mod & controlKey) - vim_mod |= MOUSE_CTRL; - if (mod & optionKey) - vim_mod |= MOUSE_ALT; - - if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds)) - { - point.h -= bounds.left; - point.v -= bounds.top; - } - - gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5, - point.h, point.v, FALSE, vim_mod); - - // post a bogus event to wake up WaitNextEvent - PostEvent(keyUp, 0); - - return noErr; - -bail: - /* - * when we fail give any additional callback handler a chance to perform - * its actions - */ - return CallNextEventHandler(nextHandler, theEvent); -} - - void -gui_mch_mousehide(int hide) -{ - // TODO -} - -#if 0 - -/* - * This would be the normal way of invoking the contextual menu - * but the Vim API doesn't seem to a support a request to get - * the menu that we should display - */ - void -gui_mac_handle_contextual_menu(EventRecord *event) -{ -/* - * Clone PopUp to use menu - * Create a object descriptor for the current selection - * Call the procedure - */ - -// Call to Handle Popup - OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem); - - if (status != noErr) - return; - - if (CntxType == kCMMenuItemSelected) - { - // Handle the menu CntxMenuID, CntxMenuItem - // The submenu can be handle directly by gui_mac_handle_menu - // But what about the current menu, is the many changed by ContextualMenuSelect - gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem); - } - else if (CntxMenuID == kCMShowHelpSelected) - { - // Should come up with the help - } - -} -#endif - -/* - * Handle menubar selection - */ - void -gui_mac_handle_menu(long menuChoice) -{ - short menu = HiWord(menuChoice); - short item = LoWord(menuChoice); - vimmenu_T *theVimMenu = root_menu; - - if (menu == 256) // TODO: use constant or gui.xyz - { - if (item == 1) - gui_mch_beep(); // TODO: Popup dialog or do :intro - } - else if (item != 0) - { - theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu); - - if (theVimMenu) - gui_menu_cb(theVimMenu); - } - HiliteMenu(0); -} - -/* - * Dispatch the event to proper handler - */ - - void -gui_mac_handle_event(EventRecord *event) -{ - OSErr error; - - // Handle contextual menu right now (if needed) - if (IsShowContextualMenuClick(event)) - { -# if 0 - gui_mac_handle_contextual_menu(event); -# else - gui_mac_doMouseDownEvent(event); -# endif - return; - } - - // Handle normal event - switch (event->what) - { -#ifndef USE_CARBONKEYHANDLER - case (keyDown): - case (autoKey): - gui_mac_doKeyEvent(event); - break; -#endif - case (keyUp): - // We don't care about when the key is released - break; - - case (mouseDown): - gui_mac_doMouseDownEvent(event); - break; - - case (mouseUp): - gui_mac_doMouseUpEvent(event); - break; - - case (updateEvt): - gui_mac_doUpdateEvent(event); - break; - - case (diskEvt): - // We don't need special handling for disk insertion - break; - - case (activateEvt): - gui_mac_doActivateEvent(event); - break; - - case (osEvt): - switch ((event->message >> 24) & 0xFF) - { - case (0xFA): // mouseMovedMessage - gui_mac_doMouseMovedEvent(event); - break; - case (0x01): // suspendResumeMessage - gui_mac_doSuspendEvent(event); - break; - } - break; - -#ifdef USE_AEVENT - case (kHighLevelEvent): - // Someone's talking to us, through AppleEvents - error = AEProcessAppleEvent(event); // TODO: Error Handling - break; -#endif - } -} - -/* - * ------------------------------------------------------------ - * Unknown Stuff - * ------------------------------------------------------------ - */ - - - GuiFont -gui_mac_find_font(char_u *font_name) -{ - char_u c; - char_u *p; - char_u pFontName[256]; - Str255 systemFontname; - short font_id; - short size=9; - GuiFont font; -#if 0 - char_u *fontNamePtr; -#endif - - for (p = font_name; ((*p != 0) && (*p != ':')); p++) - ; - - c = *p; - *p = 0; - -#if 1 - STRCPY(&pFontName[1], font_name); - pFontName[0] = STRLEN(font_name); - *p = c; - - // Get the font name, minus the style suffix (:h, etc) - char_u fontName[256]; - char_u *styleStart = vim_strchr(font_name, ':'); - size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName); - vim_strncpy(fontName, font_name, fontNameLen); - - ATSUFontID fontRef; - FMFontStyle fontStyle; - font_id = 0; - - if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName, - kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode, - &fontRef) == noErr) - { - if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr) - font_id = 0; - } - - if (font_id == 0) - { - /* - * Try again, this time replacing underscores in the font name - * with spaces (:set guifont allows the two to be used - * interchangeably; the Font Manager doesn't). - */ - int i, changed = FALSE; - - for (i = pFontName[0]; i > 0; --i) - { - if (pFontName[i] == '_') - { - pFontName[i] = ' '; - changed = TRUE; - } - } - if (changed) - if (ATSUFindFontFromName(&pFontName[1], pFontName[0], - kFontFullName, kFontNoPlatformCode, kFontNoScriptCode, - kFontNoLanguageCode, &fontRef) == noErr) - { - if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr) - font_id = 0; - } - } - -#else - // name = C2Pascal_save(menu->dname); - fontNamePtr = C2Pascal_save_and_remove_backslash(font_name); - - GetFNum(fontNamePtr, &font_id); -#endif - - - if (font_id == 0) - { - // Oups, the system font was it the one the user want - - if (FMGetFontFamilyName(systemFont, systemFontname) != noErr) - return NOFONT; - if (!EqualString(pFontName, systemFontname, false, false)) - return NOFONT; - } - if (*p == ':') - { - p++; - // Set the values found after ':' - while (*p) - { - switch (*p++) - { - case 'h': - size = points_to_pixels(p, &p, TRUE); - break; - /* - * TODO: Maybe accept width and styles - */ - } - while (*p == ':') - p++; - } - } - - if (size < 1) - size = 1; // Avoid having a size of 0 with system font - - font = (size << 16) + ((long) font_id & 0xFFFF); - - return font; -} - -/* - * ------------------------------------------------------------ - * GUI_MCH functionality - * ------------------------------------------------------------ - */ - -/* - * Parse the GUI related command-line arguments. Any arguments used are - * deleted from argv, and *argc is decremented accordingly. This is called - * when vim is started, whether or not the GUI has been started. - */ - void -gui_mch_prepare(int *argc, char **argv) -{ - // TODO: Move most of this stuff toward gui_mch_init -#ifdef USE_EXE_NAME - FSSpec applDir; -# ifndef USE_FIND_BUNDLE_PATH - short applVRefNum; - long applDirID; - Str255 volName; -# else - ProcessSerialNumber psn; - FSRef applFSRef; -# endif -#endif - -#if 0 - InitCursor(); - - RegisterAppearanceClient(); - -#ifdef USE_AEVENT - (void) InstallAEHandlers(); -#endif - - pomme = NewMenu(256, "\p\024"); // 0x14= = Apple Menu - - AppendMenu(pomme, "\pAbout VIM"); - - InsertMenu(pomme, 0); - - DrawMenuBar(); - - -#ifndef USE_OFFSETED_WINDOW - SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11); -#else - SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11); -#endif - - - CreateNewWindow(kDocumentWindowClass, - kWindowResizableAttribute | kWindowCollapseBoxAttribute, - &windRect, &gui.VimWindow); - SetPortWindowPort(gui.VimWindow); - - gui.char_width = 7; - gui.char_height = 11; - gui.char_ascent = 6; - gui.num_rows = 24; - gui.num_cols = 80; - gui.in_focus = TRUE; // For the moment -> syn. of front application - - gScrollAction = NewControlActionUPP(gui_mac_scroll_action); - gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb); - - dragRectEnbl = FALSE; - dragRgn = NULL; - dragRectControl = kCreateEmpty; - cursorRgn = NewRgn(); -#endif -#ifdef USE_EXE_NAME -# ifndef USE_FIND_BUNDLE_PATH - HGetVol(volName, &applVRefNum, &applDirID); - // TN2015: mention a possible bad VRefNum - FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir); -# else - // OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr) - // of TN2015 - (void)GetCurrentProcess(&psn); - // if (err != noErr) return err; - - (void)GetProcessBundleLocation(&psn, &applFSRef); - // if (err != noErr) return err; - - (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL); - - // This technique returns NIL when we disallow_gui -# endif - exe_name = FullPathFromFSSpec_save(applDir); -#endif -} - -#ifndef ALWAYS_USE_GUI -/* - * Check if the GUI can be started. Called before gvimrc is sourced. - * Return OK or FAIL. - */ - int -gui_mch_init_check(void) -{ - // TODO: For MacOS X find a way to return FAIL, if the user logged in - // using the >console - if (disallow_gui) // see main.c for reason to disallow - return FAIL; - return OK; -} -#endif - - static OSErr -receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag) -{ - int x, y; - int_u modifiers; - char_u **fnames = NULL; - int count; - int i, j; - - // Get drop position, modifiers and count of items - { - Point point; - SInt16 mouseUpModifiers; - UInt16 countItem; - - GetDragMouse(theDrag, &point, NULL); - GlobalToLocal(&point); - x = point.h; - y = point.v; - GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers); - modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers); - CountDragItems(theDrag, &countItem); - count = countItem; - } - - fnames = ALLOC_MULT(char_u *, count); - if (fnames == NULL) - return dragNotAcceptedErr; - - // Get file names dropped - for (i = j = 0; i < count; ++i) - { - DragItemRef item; - OSErr err; - Size size; - FlavorType type = flavorTypeHFS; - HFSFlavor hfsFlavor; - - fnames[i] = NULL; - GetDragItemReferenceNumber(theDrag, i + 1, &item); - err = GetFlavorDataSize(theDrag, item, type, &size); - if (err != noErr || size > sizeof(hfsFlavor)) - continue; - err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0); - if (err != noErr) - continue; - fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec); - } - count = j; - - gui_handle_drop(x, y, modifiers, fnames, count); - - // Fake mouse event to wake from stall - PostEvent(mouseUp, 0); - - return noErr; -} - -/* - * Initialise the GUI. Create all the windows, set up all the call-backs - * etc. - */ - int -gui_mch_init(void) -{ - // TODO: Move most of this stuff toward gui_mch_init - Rect windRect; - MenuHandle pomme; - EventHandlerRef mouseWheelHandlerRef; - EventTypeSpec eventTypeSpec; - ControlRef rootControl; - - if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr) - gMacSystemVersion = 0x1000; // TODO: Default to minimum sensible value - -#if 1 - InitCursor(); - - RegisterAppearanceClient(); - -#ifdef USE_AEVENT - (void) InstallAEHandlers(); -#endif - - pomme = NewMenu(256, "\p\024"); // 0x14= = Apple Menu - - AppendMenu(pomme, "\pAbout VIM"); - - InsertMenu(pomme, 0); - - DrawMenuBar(); - - -#ifndef USE_OFFSETED_WINDOW - SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11); -#else - SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11); -#endif - - gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true, - zoomDocProc, - (WindowPtr)-1L, true, 0); - CreateRootControl(gui.VimWindow, &rootControl); - InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler, - gui.VimWindow, NULL); - SetPortWindowPort(gui.VimWindow); - - gui.char_width = 7; - gui.char_height = 11; - gui.char_ascent = 6; - gui.num_rows = 24; - gui.num_cols = 80; - gui.in_focus = TRUE; // For the moment -> syn. of front application - - gScrollAction = NewControlActionUPP(gui_mac_scroll_action); - gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb); - - // Install Carbon event callbacks. - (void)InstallFontPanelHandler(); - - dragRectEnbl = FALSE; - dragRgn = NULL; - dragRectControl = kCreateEmpty; - cursorRgn = NewRgn(); -#endif - // Display any pending error messages - display_errors(); - - // Get background/foreground colors from system - // TODO: do the appropriate call to get real defaults - gui.norm_pixel = 0x00000000; - gui.back_pixel = 0x00FFFFFF; - - // Get the colors from the "Normal" group (set in syntax.c or in a vimrc - // file). - set_normal_colors(); - - /* - * Check that none of the colors are the same as the background color. - * Then store the current values as the defaults. - */ - gui_check_colors(); - gui.def_norm_pixel = gui.norm_pixel; - gui.def_back_pixel = gui.back_pixel; - - // Get the colors for the highlight groups (gui_check_colors() might have - // changed them) - highlight_gui_started(); - - /* - * Setting the gui constants - */ -#ifdef FEAT_MENU - gui.menu_height = 0; -#endif - gui.scrollbar_height = gui.scrollbar_width = 15; // cheat 1 overlap - gui.border_offset = gui.border_width = 2; - - // If Quartz-style text anti aliasing is available (see - // gui_mch_draw_string() below), enable it for all font sizes. - vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1"); - - eventTypeSpec.eventClass = kEventClassMouse; - eventTypeSpec.eventKind = kEventMouseWheelMoved; - mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel); - if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1, - &eventTypeSpec, NULL, &mouseWheelHandlerRef)) - { - mouseWheelHandlerRef = NULL; - DisposeEventHandlerUPP(mouseWheelHandlerUPP); - mouseWheelHandlerUPP = NULL; - } - -#ifdef USE_CARBONKEYHANDLER - InterfaceTypeList supportedServices = { kUnicodeDocument }; - NewTSMDocument(1, supportedServices, &gTSMDocument, 0); - - // We don't support inline input yet, use input window by default - UseInputWindow(gTSMDocument, TRUE); - - // Should we activate the document by default? - // ActivateTSMDocument(gTSMDocument); - - EventTypeSpec textEventTypes[] = { - { kEventClassTextInput, kEventTextInputUpdateActiveInputArea }, - { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, - { kEventClassTextInput, kEventTextInputPosToOffset }, - { kEventClassTextInput, kEventTextInputOffsetToPos }, - }; - - keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input); - if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP, - NR_ELEMS(textEventTypes), - textEventTypes, NULL, NULL)) - { - DisposeEventHandlerUPP(keyEventHandlerUPP); - keyEventHandlerUPP = NULL; - } - - EventTypeSpec windowEventTypes[] = { - { kEventClassWindow, kEventWindowActivated }, - { kEventClassWindow, kEventWindowDeactivated }, - }; - - // Install window event handler to support TSMDocument activate and - // deactivate - winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate); - if (noErr != InstallWindowEventHandler(gui.VimWindow, - winEventHandlerUPP, - NR_ELEMS(windowEventTypes), - windowEventTypes, NULL, NULL)) - { - DisposeEventHandlerUPP(winEventHandlerUPP); - winEventHandlerUPP = NULL; - } -#endif - -#ifdef FEAT_GUI_TABLINE - /* - * Create the tabline - */ - initialise_tabline(); -#endif - - // TODO: Load bitmap if using TOOLBAR - return OK; -} - -/* - * Called when the foreground or background color has been changed. - */ - void -gui_mch_new_colors(void) -{ - // TODO: - // This proc is called when Normal is set to a value - // so what must be done? I don't know -} - -/* - * Open the GUI window which was created by a call to gui_mch_init(). - */ - int -gui_mch_open(void) -{ - ShowWindow(gui.VimWindow); - - if (gui_win_x != -1 && gui_win_y != -1) - gui_mch_set_winpos(gui_win_x, gui_win_y); - - /* - * Make the GUI the foreground process (in case it was launched - * from the Terminal or via :gui). - */ - { - ProcessSerialNumber psn; - if (GetCurrentProcess(&psn) == noErr) - SetFrontProcess(&psn); - } - - return OK; -} - -#ifdef USE_ATSUI_DRAWING - static void -gui_mac_dispose_atsui_style(void) -{ - if (p_macatsui && gFontStyle) - ATSUDisposeStyle(gFontStyle); - if (p_macatsui && gWideFontStyle) - ATSUDisposeStyle(gWideFontStyle); -} -#endif - - void -gui_mch_exit(int rc) -{ - // TODO: find out all what is missing here? - DisposeRgn(cursorRgn); - -#ifdef USE_CARBONKEYHANDLER - if (keyEventHandlerUPP) - DisposeEventHandlerUPP(keyEventHandlerUPP); -#endif - - if (mouseWheelHandlerUPP != NULL) - DisposeEventHandlerUPP(mouseWheelHandlerUPP); - -#ifdef USE_ATSUI_DRAWING - gui_mac_dispose_atsui_style(); -#endif - -#ifdef USE_CARBONKEYHANDLER - FixTSMDocument(gTSMDocument); - DeactivateTSMDocument(gTSMDocument); - DeleteTSMDocument(gTSMDocument); -#endif - - // Exit to shell? - exit(rc); -} - -/* - * Get the position of the top left corner of the window. - */ - int -gui_mch_get_winpos(int *x, int *y) -{ - // TODO - Rect bounds; - OSStatus status; - - // Carbon >= 1.0.2, MacOS >= 8.5 - status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds); - - if (status != noErr) - return FAIL; - *x = bounds.left; - *y = bounds.top; - return OK; -} - -/* - * Set the position of the top left corner of the window to the given - * coordinates. - */ - void -gui_mch_set_winpos(int x, int y) -{ - // TODO: Should make sure the window is move within range - // e.g.: y > ~16 [Menu bar], x > 0, x < screen width - MoveWindowStructure(gui.VimWindow, x, y); -} - - void -gui_mch_set_shellsize( - int width, - int height, - int min_width, - int min_height, - int base_width, - int base_height, - int direction) -{ - CGrafPtr VimPort; - Rect VimBound; - - if (gui.which_scrollbars[SBAR_LEFT]) - { - VimPort = GetWindowPort(gui.VimWindow); - GetPortBounds(VimPort, &VimBound); - VimBound.left = -gui.scrollbar_width; // + 1; - SetPortBounds(VimPort, &VimBound); - // GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ?? - } - else - { - VimPort = GetWindowPort(gui.VimWindow); - GetPortBounds(VimPort, &VimBound); - VimBound.left = 0; - SetPortBounds(VimPort, &VimBound); - } - - SizeWindow(gui.VimWindow, width, height, TRUE); - - gui_resize_shell(width, height); -} - -/* - * Get the screen dimensions. - * Allow 10 pixels for horizontal borders, 40 for vertical borders. - * Is there no way to find out how wide the borders really are? - * TODO: Add live update of those value on suspend/resume. - */ - void -gui_mch_get_screen_dimensions(int *screen_w, int *screen_h) -{ - GDHandle dominantDevice = GetMainDevice(); - Rect screenRect = (**dominantDevice).gdRect; - - *screen_w = screenRect.right - 10; - *screen_h = screenRect.bottom - 40; -} - - -/* - * Open the Font Panel and wait for the user to select a font and - * close the panel. Then fill the buffer pointed to by font_name with - * the name and size of the selected font and return the font's handle, - * or NOFONT in case of an error. - */ - static GuiFont -gui_mac_select_font(char_u *font_name) -{ - GuiFont selected_font = NOFONT; - OSStatus status; - FontSelectionQDStyle curr_font; - - // Initialize the Font Panel with the current font. - curr_font.instance.fontFamily = gui.norm_font & 0xFFFF; - curr_font.size = (gui.norm_font >> 16); - // TODO: set fontStyle once styles are supported in gui_mac_find_font() - curr_font.instance.fontStyle = 0; - curr_font.hasColor = false; - curr_font.version = 0; // version number of the style structure - status = SetFontInfoForSelection(kFontSelectionQDType, - /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL); - - gFontPanelInfo.family = curr_font.instance.fontFamily; - gFontPanelInfo.style = curr_font.instance.fontStyle; - gFontPanelInfo.size = curr_font.size; - - // Pop up the Font Panel. - status = FPShowHideFontPanel(); - if (status == noErr) - { - /* - * The Font Panel is modeless. We really need it to be modal, - * so we spin in an event loop until the panel is closed. - */ - gFontPanelInfo.isPanelVisible = true; - while (gFontPanelInfo.isPanelVisible) - { - EventRecord e; - WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL); - } - - GetFontPanelSelection(font_name); - selected_font = gui_mac_find_font(font_name); - } - return selected_font; -} - -#ifdef USE_ATSUI_DRAWING - static void -gui_mac_create_atsui_style(void) -{ - if (p_macatsui && gFontStyle == NULL) - { - if (ATSUCreateStyle(&gFontStyle) != noErr) - gFontStyle = NULL; - } - if (p_macatsui && gWideFontStyle == NULL) - { - if (ATSUCreateStyle(&gWideFontStyle) != noErr) - gWideFontStyle = NULL; - } - - p_macatsui_last = p_macatsui; -} -#endif - -/* - * Initialise vim to use the font with the given name. Return FAIL if the font - * could not be loaded, OK otherwise. - */ - int -gui_mch_init_font(char_u *font_name, int fontset) -{ - // TODO: Add support for bold italic underline proportional etc... - Str255 suggestedFont = "\pMonaco"; - int suggestedSize = 10; - FontInfo font_info; - short font_id; - GuiFont font; - char_u used_font_name[512]; - -#ifdef USE_ATSUI_DRAWING - gui_mac_create_atsui_style(); -#endif - - if (font_name == NULL) - { - // First try to get the suggested font - GetFNum(suggestedFont, &font_id); - - if (font_id == 0) - { - // Then pickup the standard application font - font_id = GetAppFont(); - STRCPY(used_font_name, "default"); - } - else - STRCPY(used_font_name, "Monaco"); - font = (suggestedSize << 16) + ((long) font_id & 0xFFFF); - } - else if (STRCMP(font_name, "*") == 0) - { - char_u *new_p_guifont; - - font = gui_mac_select_font(used_font_name); - if (font == NOFONT) - return FAIL; - - // Set guifont to the name of the selected font. - new_p_guifont = alloc(STRLEN(used_font_name) + 1); - if (new_p_guifont != NULL) - { - STRCPY(new_p_guifont, used_font_name); - vim_free(p_guifont); - p_guifont = new_p_guifont; - // Replace spaces in the font name with underscores. - for ( ; *new_p_guifont; ++new_p_guifont) - { - if (*new_p_guifont == ' ') - *new_p_guifont = '_'; - } - } - } - else - { - font = gui_mac_find_font(font_name); - vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1); - - if (font == NOFONT) - return FAIL; - } - - gui.norm_font = font; - - hl_set_font_name(used_font_name); - - TextSize(font >> 16); - TextFont(font & 0xFFFF); - - GetFontInfo(&font_info); - - gui.char_ascent = font_info.ascent; - gui.char_width = p_columnspace + CharWidth('_'); - gui.char_height = font_info.ascent + font_info.descent + p_linespace; - -#ifdef USE_ATSUI_DRAWING - if (p_macatsui && gFontStyle) - gui_mac_set_font_attributes(font); -#endif - - return OK; -} - -/* - * Adjust gui.char_height (after 'linespace' was changed). - */ - int -gui_mch_adjust_charheight(void) -{ - FontInfo font_info; - - GetFontInfo(&font_info); - gui.char_height = font_info.ascent + font_info.descent + p_linespace; - gui.char_ascent = font_info.ascent + p_linespace / 2; - return OK; -} - -/* - * Adjust gui.char_width (after 'columnspace' was changed). - */ - int -gui_mch_adjust_charwidth(void) -{ - gui.char_width = p_columnspace + CharWidth('_'); - return OK; -} - -/* - * Get a font structure for highlighting. - */ - GuiFont -gui_mch_get_font(char_u *name, int giveErrorIfMissing) -{ - GuiFont font; - - font = gui_mac_find_font(name); - - if (font == NOFONT) - { - if (giveErrorIfMissing) - semsg(_(e_font), name); - return NOFONT; - } - /* - * TODO : Accept only monospace - */ - - return font; -} - -#if defined(FEAT_EVAL) || defined(PROTO) -/* - * Return the name of font "font" in allocated memory. - * Don't know how to get the actual name, thus use the provided name. - */ - char_u * -gui_mch_get_fontname(GuiFont font, char_u *name) -{ - if (name == NULL) - return NULL; - return vim_strsave(name); -} -#endif - -#ifdef USE_ATSUI_DRAWING - static void -gui_mac_set_font_attributes(GuiFont font) -{ - ATSUFontID fontID; - Fixed fontSize; - Fixed fontWidth; - - fontID = font & 0xFFFF; - fontSize = Long2Fix(font >> 16); - fontWidth = Long2Fix(gui.char_width); - - ATSUAttributeTag attribTags[] = - { - kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag, - kATSUMaxATSUITagValue + 1 - }; - - ByteCount attribSizes[] = - { - sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth), - sizeof(font) - }; - - ATSUAttributeValuePtr attribValues[] = - { - &fontID, &fontSize, &fontWidth, &font - }; - - if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr) - { - if (ATSUSetAttributes(gFontStyle, - (sizeof attribTags) / sizeof(ATSUAttributeTag), - attribTags, attribSizes, attribValues) != noErr) - { -# ifndef NDEBUG - fprintf(stderr, "couldn't set font style\n"); -# endif - ATSUDisposeStyle(gFontStyle); - gFontStyle = NULL; - } - - if (has_mbyte) - { - // FIXME: we should use a more mbyte sensitive way to support - // wide font drawing - fontWidth = Long2Fix(gui.char_width * 2); - - if (ATSUSetAttributes(gWideFontStyle, - (sizeof attribTags) / sizeof(ATSUAttributeTag), - attribTags, attribSizes, attribValues) != noErr) - { - ATSUDisposeStyle(gWideFontStyle); - gWideFontStyle = NULL; - } - } - } -} -#endif - -/* - * Set the current text font. - */ - void -gui_mch_set_font(GuiFont font) -{ -#ifdef USE_ATSUI_DRAWING - GuiFont currFont; - ByteCount actualFontByteCount; - - if (p_macatsui && gFontStyle) - { - // Avoid setting same font again - if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1, - sizeof(font), &currFont, &actualFontByteCount) == noErr - && actualFontByteCount == (sizeof font)) - { - if (currFont == font) - return; - } - - gui_mac_set_font_attributes(font); - } - - if (p_macatsui && !gIsFontFallbackSet) - { - // Setup automatic font substitution. The user's guifontwide - // is tried first, then the system tries other fonts. -#if 0 - ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag }; - ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) }; - ATSUCreateFontFallbacks(&gFontFallbacks); - ATSUSetObjFontFallbacks(gFontFallbacks, ); -#endif - if (gui.wide_font) - { - ATSUFontID fallbackFonts; - gIsFontFallbackSet = TRUE; - - if (FMGetFontFromFontFamilyInstance( - (gui.wide_font & 0xFFFF), - 0, - &fallbackFonts, - NULL) == noErr) - { - ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID), - &fallbackFonts, - kATSUSequentialFallbacksPreferred); - } -// ATSUAttributeValuePtr fallbackValues[] = { }; - } - } -#endif - TextSize(font >> 16); - TextFont(font & 0xFFFF); -} - -/* - * If a font is not going to be used, free its structure. - */ - void -gui_mch_free_font(GuiFont font) -{ - /* - * Free font when "font" is not 0. - * Nothing to do in the current implementation, since - * nothing is allocated for each font used. - */ -} - -/* - * Return the Pixel value (color) for the given color name. This routine was - * pretty much taken from example code in the Silicon Graphics OSF/Motif - * Programmer's Guide. - * Return INVALCOLOR when failed. - */ - guicolor_T -gui_mch_get_color(char_u *name) -{ - // TODO: Add support for the new named color of MacOS 8 - RGBColor MacColor; - - if (STRICMP(name, "hilite") == 0) - { - LMGetHiliteRGB(&MacColor); - return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8)); - } - return gui_get_color_cmn(name); -} - - guicolor_T -gui_mch_get_rgb_color(int r, int g, int b) -{ - return gui_get_rgb_color_cmn(r, g, b); -} - -/* - * Set the current text foreground color. - */ - void -gui_mch_set_fg_color(guicolor_T color) -{ - RGBColor TheColor; - - TheColor.red = Red(color) * 0x0101; - TheColor.green = Green(color) * 0x0101; - TheColor.blue = Blue(color) * 0x0101; - - RGBForeColor(&TheColor); -} - -/* - * Set the current text background color. - */ - void -gui_mch_set_bg_color(guicolor_T color) -{ - RGBColor TheColor; - - TheColor.red = Red(color) * 0x0101; - TheColor.green = Green(color) * 0x0101; - TheColor.blue = Blue(color) * 0x0101; - - RGBBackColor(&TheColor); -} - -RGBColor specialColor; - -/* - * Set the current text special color. - */ - void -gui_mch_set_sp_color(guicolor_T color) -{ - specialColor.red = Red(color) * 0x0101; - specialColor.green = Green(color) * 0x0101; - specialColor.blue = Blue(color) * 0x0101; -} - -/* - * Draw undercurl at the bottom of the character cell. - */ - static void -draw_undercurl(int flags, int row, int col, int cells) -{ - int x; - int offset; - const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 }; - int y = FILL_Y(row + 1) - 1; - - RGBForeColor(&specialColor); - - offset = val[FILL_X(col) % 8]; - MoveTo(FILL_X(col), y - offset); - - for (x = FILL_X(col); x < FILL_X(col + cells); ++x) - { - offset = val[x % 8]; - LineTo(x, y - offset); - } -} - - - static void -draw_string_QD(int row, int col, char_u *s, int len, int flags) -{ - char_u *tofree = NULL; - - if (output_conv.vc_type != CONV_NONE) - { - tofree = string_convert(&output_conv, s, &len); - if (tofree != NULL) - s = tofree; - } - - /* - * On OS X, try using Quartz-style text antialiasing. - */ - if (gMacSystemVersion >= 0x1020) - { - // Quartz antialiasing is available only in OS 10.2 and later. - UInt32 qd_flags = (p_antialias ? - kQDUseCGTextRendering | kQDUseCGTextMetrics : 0); - QDSwapTextFlags(qd_flags); - } - - /* - * When antialiasing we're using srcOr mode, we have to clear the block - * before drawing the text. - * Also needed when 'linespace' is non-zero to remove the cursor and - * underlining. - * But not when drawing transparently. - * The following is like calling gui_mch_clear_block(row, col, row, col + - * len - 1), but without setting the bg color to gui.back_pixel. - */ - if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0) - && !(flags & DRAW_TRANSP)) - { - Rect rc; - - rc.left = FILL_X(col); - rc.top = FILL_Y(row); - // Multibyte computation taken from gui_w32.c - if (has_mbyte) - { - // Compute the length in display cells. - rc.right = FILL_X(col + mb_string2cells(s, len)); - } - else - rc.right = FILL_X(col + len) + (col + len == Columns); - rc.bottom = FILL_Y(row + 1); - EraseRect(&rc); - } - - if (gMacSystemVersion >= 0x1020 && p_antialias) - { - StyleParameter face; - - face = normal; - if (flags & DRAW_BOLD) - face |= bold; - if (flags & DRAW_UNDERL) - face |= underline; - TextFace(face); - - // Quartz antialiasing works only in srcOr transfer mode. - TextMode(srcOr); - - MoveTo(TEXT_X(col), TEXT_Y(row)); - DrawText((char*)s, 0, len); - } - else - { - // Use old-style, non-antialiased QuickDraw text rendering. - TextMode(srcCopy); - TextFace(normal); - - // SelectFont(hdc, gui.currFont); - - if (flags & DRAW_TRANSP) - TextMode(srcOr); - - MoveTo(TEXT_X(col), TEXT_Y(row)); - DrawText((char *)s, 0, len); - - if (flags & DRAW_BOLD) - { - TextMode(srcOr); - MoveTo(TEXT_X(col) + 1, TEXT_Y(row)); - DrawText((char *)s, 0, len); - } - - if (flags & DRAW_UNDERL) - { - MoveTo(FILL_X(col), FILL_Y(row + 1) - 1); - LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1); - } - if (flags & DRAW_STRIKE) - { - MoveTo(FILL_X(col), FILL_Y(row + 1) - gui.char_height/2); - LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - gui.char_height/2); - } - } - - if (flags & DRAW_UNDERC) - draw_undercurl(flags, row, col, len); - - vim_free(tofree); -} - -#ifdef USE_ATSUI_DRAWING - - static void -draw_string_ATSUI(int row, int col, char_u *s, int len, int flags) -{ - // ATSUI requires utf-16 strings - UniCharCount utf16_len; - UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len); - utf16_len /= sizeof(UniChar); - - // - ATSUI automatically antialiases text (Someone) - // - for some reason it does not work... (Jussi) -#ifdef MAC_ATSUI_DEBUG - fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n", - row, col, len, len == 1 ? s[0] : ' '); -#endif - /* - * When antialiasing we're using srcOr mode, we have to clear the block - * before drawing the text. - * Also needed when 'linespace' is non-zero to remove the cursor and - * underlining. - * But not when drawing transparently. - * The following is like calling gui_mch_clear_block(row, col, row, col + - * len - 1), but without setting the bg color to gui.back_pixel. - */ - if ((flags & DRAW_TRANSP) == 0) - { - Rect rc; - - rc.left = FILL_X(col); - rc.top = FILL_Y(row); - // Multibyte computation taken from gui_w32.c - if (has_mbyte) - { - // Compute the length in display cells. - rc.right = FILL_X(col + mb_string2cells(s, len)); - } - else - rc.right = FILL_X(col + len) + (col + len == Columns); - - rc.bottom = FILL_Y(row + 1); - EraseRect(&rc); - } - - { - TextMode(srcCopy); - TextFace(normal); - - // SelectFont(hdc, gui.currFont); - if (flags & DRAW_TRANSP) - TextMode(srcOr); - - MoveTo(TEXT_X(col), TEXT_Y(row)); - - if (gFontStyle && flags & DRAW_BOLD) - { - Boolean attValue = true; - ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag }; - ByteCount attribSizes[] = { sizeof(Boolean) }; - ATSUAttributeValuePtr attribValues[] = { &attValue }; - - ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues); - } - - UInt32 useAntialias = p_antialias ? kATSStyleApplyAntiAliasing - : kATSStyleNoAntiAliasing; - if (useAntialias != useAntialias_cached) - { - ATSUAttributeTag attribTags[] = { kATSUStyleRenderingOptionsTag }; - ByteCount attribSizes[] = { sizeof(UInt32) }; - ATSUAttributeValuePtr attribValues[] = { &useAntialias }; - - if (gFontStyle) - ATSUSetAttributes(gFontStyle, 1, attribTags, - attribSizes, attribValues); - if (gWideFontStyle) - ATSUSetAttributes(gWideFontStyle, 1, attribTags, - attribSizes, attribValues); - - useAntialias_cached = useAntialias; - } - - if (has_mbyte) - { - int n, width_in_cell, last_width_in_cell; - UniCharArrayOffset offset = 0; - UniCharCount yet_to_draw = 0; - ATSUTextLayout textLayout; - ATSUStyle textStyle; - - last_width_in_cell = 1; - ATSUCreateTextLayout(&textLayout); - ATSUSetTextPointerLocation(textLayout, tofree, - kATSUFromTextBeginning, - kATSUToTextEnd, utf16_len); - /* - ATSUSetRunStyle(textLayout, gFontStyle, - kATSUFromTextBeginning, kATSUToTextEnd); */ - - // Compute the length in display cells. - for (n = 0; n < len; n += MB_BYTE2LEN(s[n])) - { - width_in_cell = (*mb_ptr2cells)(s + n); - - // probably we are switching from single byte character - // to multibyte characters (which requires more than one - // cell to draw) - if (width_in_cell != last_width_in_cell) - { -#ifdef MAC_ATSUI_DEBUG - fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n", - n, last_width_in_cell, width_in_cell, offset, yet_to_draw); -#endif - textStyle = last_width_in_cell > 1 ? gWideFontStyle - : gFontStyle; - - ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw); - offset += yet_to_draw; - yet_to_draw = 0; - last_width_in_cell = width_in_cell; - } - - yet_to_draw++; - } - - if (yet_to_draw) - { -#ifdef MAC_ATSUI_DEBUG - fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n", - n, last_width_in_cell, width_in_cell, offset, yet_to_draw); -#endif - // finish the rest style - textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle; - ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd); - } - - ATSUSetTransientFontMatching(textLayout, TRUE); - ATSUDrawText(textLayout, - kATSUFromTextBeginning, kATSUToTextEnd, - kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc); - ATSUDisposeTextLayout(textLayout); - } - else - { - ATSUTextLayout textLayout; - - if (ATSUCreateTextLayoutWithTextPtr(tofree, - kATSUFromTextBeginning, kATSUToTextEnd, - utf16_len, - (gFontStyle ? 1 : 0), &utf16_len, - (gFontStyle ? &gFontStyle : NULL), - &textLayout) == noErr) - { - ATSUSetTransientFontMatching(textLayout, TRUE); - - ATSUDrawText(textLayout, - kATSUFromTextBeginning, kATSUToTextEnd, - kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc); - - ATSUDisposeTextLayout(textLayout); - } - } - - // drawing is done, now reset bold to normal - if (gFontStyle && flags & DRAW_BOLD) - { - Boolean attValue = false; - - ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag }; - ByteCount attribSizes[] = { sizeof(Boolean) }; - ATSUAttributeValuePtr attribValues[] = { &attValue }; - - ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, - attribValues); - } - } - - if (flags & DRAW_UNDERC) - draw_undercurl(flags, row, col, len); - - vim_free(tofree); -} -#endif - - void -gui_mch_draw_string(int row, int col, char_u *s, int len, int flags) -{ -#if defined(USE_ATSUI_DRAWING) - if (p_macatsui == 0 && p_macatsui_last != 0) - // switch from macatsui to nomacatsui - gui_mac_dispose_atsui_style(); - else if (p_macatsui != 0 && p_macatsui_last == 0) - // switch from nomacatsui to macatsui - gui_mac_create_atsui_style(); - - if (p_macatsui) - draw_string_ATSUI(row, col, s, len, flags); - else -#endif - draw_string_QD(row, col, s, len, flags); -} - -/* - * Return OK if the key with the termcap name "name" is supported. - */ - int -gui_mch_haskey(char_u *name) -{ - int i; - - for (i = 0; special_keys[i].key_sym != (KeySym)0; i++) - if (name[0] == special_keys[i].vim_code0 && - name[1] == special_keys[i].vim_code1) - return OK; - return FAIL; -} - - void -gui_mch_beep(void) -{ - SysBeep(1); // Should this be 0? (????) -} - - void -gui_mch_flash(int msec) -{ - // Do a visual beep by reversing the foreground and background colors - Rect rc; - - /* - * Note: InvertRect() excludes right and bottom of rectangle. - */ - rc.left = 0; - rc.top = 0; - rc.right = gui.num_cols * gui.char_width; - rc.bottom = gui.num_rows * gui.char_height; - InvertRect(&rc); - - ui_delay((long)msec, TRUE); // wait for some msec - - InvertRect(&rc); -} - -/* - * Invert a rectangle from row r, column c, for nr rows and nc columns. - */ - void -gui_mch_invert_rectangle(int r, int c, int nr, int nc) -{ - Rect rc; - - /* - * Note: InvertRect() excludes right and bottom of rectangle. - */ - rc.left = FILL_X(c); - rc.top = FILL_Y(r); - rc.right = rc.left + nc * gui.char_width; - rc.bottom = rc.top + nr * gui.char_height; - InvertRect(&rc); -} - -/* - * Iconify the GUI window. - */ - void -gui_mch_iconify(void) -{ - // TODO: find out what could replace iconify - // -window shade? - // -hide application? -} - -#if defined(FEAT_EVAL) || defined(PROTO) -/* - * Bring the Vim window to the foreground. - */ - void -gui_mch_set_foreground(void) -{ - // TODO -} -#endif - -/* - * Draw a cursor without focus. - */ - void -gui_mch_draw_hollow_cursor(guicolor_T color) -{ - Rect rc; - - /* - * Note: FrameRect() excludes right and bottom of rectangle. - */ - rc.left = FILL_X(gui.col); - rc.top = FILL_Y(gui.row); - rc.right = rc.left + gui.char_width; - if (mb_lefthalve(gui.row, gui.col)) - rc.right += gui.char_width; - rc.bottom = rc.top + gui.char_height; - - gui_mch_set_fg_color(color); - - FrameRect(&rc); -} - -/* - * Draw part of a cursor, only w pixels wide, and h pixels high. - */ - void -gui_mch_draw_part_cursor(int w, int h, guicolor_T color) -{ - Rect rc; - -#ifdef FEAT_RIGHTLEFT - // vertical line should be on the right of current point - if (CURSOR_BAR_RIGHT) - rc.left = FILL_X(gui.col + 1) - w; - else -#endif - rc.left = FILL_X(gui.col); - rc.top = FILL_Y(gui.row) + gui.char_height - h; - rc.right = rc.left + w; - rc.bottom = rc.top + h; - - gui_mch_set_fg_color(color); - - FrameRect(&rc); -// PaintRect(&rc); -} - - - -/* - * Catch up with any queued X events. This may put keyboard input into the - * input buffer, call resize call-backs, trigger timers etc. If there is - * nothing in the X event queue (& no timers pending), then we return - * immediately. - */ - void -gui_mch_update(void) -{ - // TODO: find what to do - // maybe call gui_mch_wait_for_chars (0) - // more like look at EventQueue then - // call heart of gui_mch_wait_for_chars; - // - // if (eventther) - // gui_mac_handle_event(&event); - EventRecord theEvent; - - if (EventAvail(everyEvent, &theEvent)) - if (theEvent.what != nullEvent) - gui_mch_wait_for_chars(0); -} - -/* - * Simple wrapper to neglect more easily the time - * spent inside WaitNextEvent while profiling. - */ - - pascal - Boolean -WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn) -{ - if (((long) sleep) < -1) - sleep = 32767; - return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn); -} - -/* - * GUI input routine called by gui_wait_for_chars(). Waits for a character - * from the keyboard. - * wtime == -1 Wait forever. - * wtime == 0 This should never happen. - * wtime > 0 Wait wtime milliseconds for a character. - * Returns OK if a character was found to be available within the given time, - * or FAIL otherwise. - */ - int -gui_mch_wait_for_chars(int wtime) -{ - EventMask mask = (everyEvent); - EventRecord event; - long entryTick; - long currentTick; - long sleeppyTick; - - // If we are providing life feedback with the scrollbar, - // we don't want to try to wait for an event, or else - // there won't be any life feedback. - if (dragged_sb != NULL) - return FAIL; - // TODO: Check if FAIL is the proper return code - - entryTick = TickCount(); - - allow_scrollbar = TRUE; - - do - { -#if 0 - if (dragRectControl == kCreateEmpty) - { - dragRgn = NULL; - dragRectControl = kNothing; - } - else -#endif - if (dragRectControl == kCreateRect) - { - dragRgn = cursorRgn; - RectRgn(dragRgn, &dragRect); - dragRectControl = kNothing; - } - /* - * Don't use gui_mch_update() because then we will spin-lock until a - * char arrives, instead we use WaitNextEventWrp() to hang until an - * event arrives. No need to check for input_buf_full because we are - * returning as soon as it contains a single char. - */ - // TODO: reduce wtime accordingly??? - if (wtime > -1) - sleeppyTick = 60 * wtime / 1000; - else - sleeppyTick = 32767; - - if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn)) - { - gui_mac_handle_event(&event); - if (input_available()) - { - allow_scrollbar = FALSE; - return OK; - } - } - currentTick = TickCount(); - } - while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000)); - - allow_scrollbar = FALSE; - return FAIL; -} - -/* - * Output routines. - */ - -/* - * Flush any output to the screen - */ - void -gui_mch_flush(void) -{ - // TODO: Is anything needed here? -} - -/* - * Clear a rectangular region of the screen from text pos (row1, col1) to - * (row2, col2) inclusive. - */ - void -gui_mch_clear_block(int row1, int col1, int row2, int col2) -{ - Rect rc; - - /* - * Clear one extra pixel at the far right, for when bold characters have - * spilled over to the next column. - */ - rc.left = FILL_X(col1); - rc.top = FILL_Y(row1); - rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1); - rc.bottom = FILL_Y(row2 + 1); - - gui_mch_set_bg_color(gui.back_pixel); - EraseRect(&rc); -} - -/* - * Clear the whole text window. - */ - void -gui_mch_clear_all(void) -{ - Rect rc; - - rc.left = 0; - rc.top = 0; - rc.right = Columns * gui.char_width + 2 * gui.border_width; - rc.bottom = Rows * gui.char_height + 2 * gui.border_width; - - gui_mch_set_bg_color(gui.back_pixel); - EraseRect(&rc); -// gui_mch_set_fg_color(gui.norm_pixel); -// FrameRect(&rc); -} - -/* - * Delete the given number of lines from the given row, scrolling up any - * text further down within the scroll region. - */ - void -gui_mch_delete_lines(int row, int num_lines) -{ - Rect rc; - - // changed without checking! - rc.left = FILL_X(gui.scroll_region_left); - rc.right = FILL_X(gui.scroll_region_right + 1); - rc.top = FILL_Y(row); - rc.bottom = FILL_Y(gui.scroll_region_bot + 1); - - gui_mch_set_bg_color(gui.back_pixel); - ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil); - - gui_clear_block(gui.scroll_region_bot - num_lines + 1, - gui.scroll_region_left, - gui.scroll_region_bot, gui.scroll_region_right); -} - -/* - * Insert the given number of lines before the given row, scrolling down any - * following text within the scroll region. - */ - void -gui_mch_insert_lines(int row, int num_lines) -{ - Rect rc; - - rc.left = FILL_X(gui.scroll_region_left); - rc.right = FILL_X(gui.scroll_region_right + 1); - rc.top = FILL_Y(row); - rc.bottom = FILL_Y(gui.scroll_region_bot + 1); - - gui_mch_set_bg_color(gui.back_pixel); - - ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil); - - // Update gui.cursor_row if the cursor scrolled or copied over - if (gui.cursor_row >= gui.row - && gui.cursor_col >= gui.scroll_region_left - && gui.cursor_col <= gui.scroll_region_right) - { - if (gui.cursor_row <= gui.scroll_region_bot - num_lines) - gui.cursor_row += num_lines; - else if (gui.cursor_row <= gui.scroll_region_bot) - gui.cursor_is_valid = FALSE; - } - - gui_clear_block(row, gui.scroll_region_left, - row + num_lines - 1, gui.scroll_region_right); -} - - /* - * TODO: add a vim format to the clipboard which remember - * LINEWISE, CHARWISE, BLOCKWISE - */ - - void -clip_mch_request_selection(Clipboard_T *cbd) -{ - - Handle textOfClip; - int flavor = 0; - Size scrapSize; - ScrapFlavorFlags scrapFlags; - ScrapRef scrap = nil; - OSStatus error; - int type; - char *searchCR; - char_u *tempclip; - - - error = GetCurrentScrap(&scrap); - if (error != noErr) - return; - - error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags); - if (error == noErr) - { - error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize); - if (error == noErr && scrapSize > 1) - flavor = 1; - } - - if (flavor == 0) - { - error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags); - if (error != noErr) - return; - - error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize); - if (error != noErr) - return; - } - - ReserveMem(scrapSize); - - // In CARBON we don't need a Handle, a pointer is good - textOfClip = NewHandle(scrapSize); - - // tempclip = alloc(scrapSize+1); - HLock(textOfClip); - error = GetScrapFlavorData(scrap, - flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR, - &scrapSize, *textOfClip); - scrapSize -= flavor; - - if (flavor) - type = **textOfClip; - else - type = MAUTO; - - tempclip = alloc(scrapSize + 1); - mch_memmove(tempclip, *textOfClip + flavor, scrapSize); - tempclip[scrapSize] = 0; - -#ifdef MACOS_CONVERT - { - // Convert from utf-16 (clipboard) - size_t encLen = 0; - char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen); - - if (to != NULL) - { - scrapSize = encLen; - vim_free(tempclip); - tempclip = to; - } - } -#endif - - searchCR = (char *)tempclip; - while (searchCR != NULL) - { - searchCR = strchr(searchCR, '\r'); - if (searchCR != NULL) - *searchCR = '\n'; - } - - clip_yank_selection(type, tempclip, scrapSize, cbd); - - vim_free(tempclip); - HUnlock(textOfClip); - - DisposeHandle(textOfClip); -} - - void -clip_mch_lose_selection(Clipboard_T *cbd) -{ - /* - * TODO: Really nothing to do? - */ -} - - int -clip_mch_own_selection(Clipboard_T *cbd) -{ - return OK; -} - -/* - * Send the current selection to the clipboard. - */ - void -clip_mch_set_selection(Clipboard_T *cbd) -{ - Handle textOfClip; - long scrapSize; - int type; - ScrapRef scrap; - - char_u *str = NULL; - - if (!cbd->owned) - return; - - clip_get_selection(cbd); - - /* - * Once we set the clipboard, lose ownership. If another application sets - * the clipboard, we don't want to think that we still own it. - */ - cbd->owned = FALSE; - - type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd); - -#ifdef MACOS_CONVERT - size_t utf16_len = 0; - UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len); - if (to) - { - scrapSize = utf16_len; - vim_free(str); - str = (char_u *)to; - } -#endif - - if (type >= 0) - { - ClearCurrentScrap(); - - textOfClip = NewHandle(scrapSize + 1); - HLock(textOfClip); - - **textOfClip = type; - mch_memmove(*textOfClip + 1, str, scrapSize); - GetCurrentScrap(&scrap); - PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone, - scrapSize, *textOfClip + 1); - PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone, - scrapSize + 1, *textOfClip); - HUnlock(textOfClip); - DisposeHandle(textOfClip); - } - - vim_free(str); -} - - void -gui_mch_set_text_area_pos(int x, int y, int w, int h) -{ - Rect VimBound; - -// HideWindow(gui.VimWindow); - GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound); - - if (gui.which_scrollbars[SBAR_LEFT]) - VimBound.left = -gui.scrollbar_width + 1; - else - VimBound.left = 0; - - SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound); - - ShowWindow(gui.VimWindow); -} - -/* - * Menu stuff. - */ - - void -gui_mch_enable_menu(int flag) -{ - /* - * Menu is always active. - */ -} - - void -gui_mch_set_menu_pos(int x, int y, int w, int h) -{ - /* - * The menu is always at the top of the screen. - */ -} - -/* - * Add a sub menu to the menu bar. - */ - void -gui_mch_add_menu(vimmenu_T *menu, int idx) -{ - /* - * TODO: Try to use only menu_id instead of both menu_id and menu_handle. - * TODO: use menu->mnemonic and menu->actext - * TODO: Try to reuse menu id - * Carbon Help suggest to use only id between 1 and 235 - */ - static long next_avail_id = 128; - long menu_after_me = 0; // Default to the end - CFStringRef name; - short index; - vimmenu_T *parent = menu->parent; - vimmenu_T *brother = menu->next; - - // Cannot add a menu if ... - if ((parent != NULL && parent->submenu_id == 0)) - return; - - // menu ID greater than 1024 are reserved for ??? - if (next_avail_id == 1024) - return; - - // My brother could be the PopUp, find my real brother - while ((brother != NULL) && (!menu_is_menubar(brother->name))) - brother = brother->next; - - // Find where to insert the menu (for MenuBar) - if ((parent == NULL) && (brother != NULL)) - menu_after_me = brother->submenu_id; - - // If the menu is not part of the menubar (and its submenus), add it 'nowhere' - if (!menu_is_menubar(menu->name)) - menu_after_me = hierMenu; - - // Convert the name -#ifdef MACOS_CONVERT - name = menu_title_removing_mnemonic(menu); -#else - name = C2Pascal_save(menu->dname); -#endif - if (name == NULL) - return; - - // Create the menu unless it's the help menu - { - // Carbon suggest use of - // OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *); - // OSStatus SetMenuTitle(MenuRef, ConstStr255Param title); - menu->submenu_id = next_avail_id; - if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr) - SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name); - next_avail_id++; - } - - if (parent == NULL) - { - // Adding a menu to the menubar, or in the no mans land (for PopUp) - - // TODO: Verify if we could only Insert Menu if really part of the - // menubar The Inserted menu are scanned or the Command-key combos - - // Insert the menu - InsertMenu(menu->submenu_handle, menu_after_me); // insert before -#if 1 - // Vim should normally update it. TODO: verify - DrawMenuBar(); -#endif - } - else - { - // Adding as a submenu - - index = gui_mac_get_menu_item_index(menu); - - // Call InsertMenuItem followed by SetMenuItemText - // to avoid special character recognition by InsertMenuItem - InsertMenuItem(parent->submenu_handle, "\p ", idx); // afterItem - SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name); - SetItemCmd(parent->submenu_handle, idx+1, 0x1B); - SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id); - InsertMenu(menu->submenu_handle, hierMenu); - } - - CFRelease(name); - -#if 0 - // Done by Vim later on - DrawMenuBar(); -#endif -} - -/* - * Add a menu item to a menu - */ - void -gui_mch_add_menu_item(vimmenu_T *menu, int idx) -{ - CFStringRef name; - vimmenu_T *parent = menu->parent; - int menu_inserted; - - // Cannot add item, if the menu have not been created - if (parent->submenu_id == 0) - return; - - // Could call SetMenuRefCon [CARBON] to associate with the Menu, - // for older OS call GetMenuItemData (menu, item, isCommandID?, data) - - // Convert the name -#ifdef MACOS_CONVERT - name = menu_title_removing_mnemonic(menu); -#else - name = C2Pascal_save(menu->dname); -#endif - - // Where are just a menu item, so no handle, no id - menu->submenu_id = 0; - menu->submenu_handle = NULL; - - menu_inserted = 0; - if (menu->actext) - { - // If the accelerator text for the menu item looks like it describes - // a command key (e.g., "" or ""), display it as the - // item's command equivalent. - int key = 0; - int modifiers = 0; - char_u *p_actext; - - p_actext = menu->actext; - key = find_special_key(&p_actext, &modifiers, FSK_SIMPLIFY, NULL); - if (*p_actext != 0) - key = 0; // error: trailing text - // find_special_key() returns a keycode with as many of the - // specified modifiers as appropriate already applied (e.g., for - // "" it returns Ctrl-X as the keycode and MOD_MASK_CMD - // as the only modifier). Since we want to display all of the - // modifiers, we need to convert the keycode back to a printable - // character plus modifiers. - // TODO: Write an alternative find_special_key() that doesn't - // apply modifiers. - if (key > 0 && key < 32) - { - // Convert a control key to an uppercase letter. Note that - // by this point it is no longer possible to distinguish - // between, e.g., Ctrl-S and Ctrl-Shift-S. - modifiers |= MOD_MASK_CTRL; - key += '@'; - } - // If the keycode is an uppercase letter, set the Shift modifier. - // If it is a lowercase letter, don't set the modifier, but convert - // the letter to uppercase for display in the menu. - else if (key >= 'A' && key <= 'Z') - modifiers |= MOD_MASK_SHIFT; - else if (key >= 'a' && key <= 'z') - key += 'A' - 'a'; - // Note: keycodes below 0x22 are reserved by Apple. - if (key >= 0x22 && vim_isprintc_strict(key)) - { - int valid = 1; - char_u mac_mods = kMenuNoModifiers; - // Convert Vim modifier codes to Menu Manager equivalents. - if (modifiers & MOD_MASK_SHIFT) - mac_mods |= kMenuShiftModifier; - if (modifiers & MOD_MASK_CTRL) - mac_mods |= kMenuControlModifier; - if (!(modifiers & MOD_MASK_CMD)) - mac_mods |= kMenuNoCommandModifier; - if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK) - valid = 0; // TODO: will Alt someday map to Option? - if (valid) - { - char_u item_txt[10]; - // Insert the menu item after idx, with its command key. - item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/'; - item_txt[3] = key; - InsertMenuItem(parent->submenu_handle, item_txt, idx); - // Set the modifier keys. - SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods); - menu_inserted = 1; - } - } - } - // Call InsertMenuItem followed by SetMenuItemText - // to avoid special character recognition by InsertMenuItem - if (!menu_inserted) - InsertMenuItem(parent->submenu_handle, "\p ", idx); // afterItem - // Set the menu item name. - SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name); - -#if 0 - // Called by Vim - DrawMenuBar(); -#endif - - CFRelease(name); -} - - void -gui_mch_toggle_tearoffs(int enable) -{ - // no tearoff menus -} - -/* - * Destroy the machine specific menu widget. - */ - void -gui_mch_destroy_menu(vimmenu_T *menu) -{ - short index = gui_mac_get_menu_item_index(menu); - - if (index > 0) - { - if (menu->parent) - { - { - // For now just don't delete help menu items. (Huh? Dany) - DeleteMenuItem(menu->parent->submenu_handle, index); - - // Delete the Menu if it was a hierarchical Menu - if (menu->submenu_id != 0) - { - DeleteMenu(menu->submenu_id); - DisposeMenu(menu->submenu_handle); - } - } - } -#ifdef DEBUG_MAC_MENU - else - { - printf("gmdm 2\n"); - } -#endif - } - else - { - { - DeleteMenu(menu->submenu_id); - DisposeMenu(menu->submenu_handle); - } - } - // Shouldn't this be already done by Vim. TODO: Check - DrawMenuBar(); -} - -/* - * Make a menu either grey or not grey. - */ - void -gui_mch_menu_grey(vimmenu_T *menu, int grey) -{ - // TODO: Check if menu really exists - short index = gui_mac_get_menu_item_index(menu); -/* - index = menu->index; -*/ - if (grey) - { - if (menu->children) - DisableMenuItem(menu->submenu_handle, index); - if (menu->parent) - if (menu->parent->submenu_handle) - DisableMenuItem(menu->parent->submenu_handle, index); - } - else - { - if (menu->children) - EnableMenuItem(menu->submenu_handle, index); - if (menu->parent) - if (menu->parent->submenu_handle) - EnableMenuItem(menu->parent->submenu_handle, index); - } -} - -/* - * Make menu item hidden or not hidden - */ - void -gui_mch_menu_hidden(vimmenu_T *menu, int hidden) -{ - // There's no hidden mode on MacOS - gui_mch_menu_grey(menu, hidden); -} - - -/* - * This is called after setting all the menus to grey/hidden or not. - */ - void -gui_mch_draw_menubar(void) -{ - DrawMenuBar(); -} - - -/* - * Scrollbar stuff. - */ - - void -gui_mch_enable_scrollbar( - scrollbar_T *sb, - int flag) -{ - if (flag) - ShowControl(sb->id); - else - HideControl(sb->id); - -#ifdef DEBUG_MAC_SB - printf("enb_sb (%x) %x\n",sb->id, flag); -#endif -} - - void -gui_mch_set_scrollbar_thumb( - scrollbar_T *sb, - long val, - long size, - long max) -{ - SetControl32BitMaximum (sb->id, max); - SetControl32BitMinimum (sb->id, 0); - SetControl32BitValue (sb->id, val); - SetControlViewSize (sb->id, size); -#ifdef DEBUG_MAC_SB - printf("thumb_sb (%x) %lx, %lx,%lx\n",sb->id, val, size, max); -#endif -} - - void -gui_mch_set_scrollbar_pos( - scrollbar_T *sb, - int x, - int y, - int w, - int h) -{ - gui_mch_set_bg_color(gui.back_pixel); -#if 0 - if (gui.which_scrollbars[SBAR_LEFT]) - { - MoveControl(sb->id, x-16, y); - SizeControl(sb->id, w + 1, h); - } - else - { - MoveControl(sb->id, x, y); - SizeControl(sb->id, w + 1, h); - } -#endif - if (sb == &gui.bottom_sbar) - h += 1; - else - w += 1; - - if (gui.which_scrollbars[SBAR_LEFT]) - x -= 15; - - MoveControl(sb->id, x, y); - SizeControl(sb->id, w, h); -#ifdef DEBUG_MAC_SB - printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h); -#endif -} - - int -gui_mch_get_scrollbar_xpadding(void) -{ - // TODO: Calculate the padding for adjust scrollbar position when the - // Window is maximized. - return 0; -} - - int -gui_mch_get_scrollbar_ypadding(void) -{ - // TODO: Calculate the padding for adjust scrollbar position when the - // Window is maximized. - return 0; -} - - void -gui_mch_create_scrollbar( - scrollbar_T *sb, - int orient) // SBAR_VERT or SBAR_HORIZ -{ - Rect bounds; - - bounds.top = -16; - bounds.bottom = -10; - bounds.right = -10; - bounds.left = -16; - - sb->id = NewControl(gui.VimWindow, - &bounds, - "\pScrollBar", - TRUE, - 0, // current - 0, // top - 0, // bottom - kControlScrollBarLiveProc, - (long) sb->ident); -#ifdef DEBUG_MAC_SB - printf("create_sb (%x) %x\n",sb->id, orient); -#endif -} - - void -gui_mch_destroy_scrollbar(scrollbar_T *sb) -{ - gui_mch_set_bg_color(gui.back_pixel); - DisposeControl(sb->id); -#ifdef DEBUG_MAC_SB - printf("dest_sb (%x) \n",sb->id); -#endif -} - - int -gui_mch_is_blinking(void) -{ - return FALSE; -} - - int -gui_mch_is_blink_off(void) -{ - return FALSE; -} - -/* - * Cursor blink functions. - * - * This is a simple state machine: - * BLINK_NONE not blinking at all - * BLINK_OFF blinking, cursor is not shown - * BLINK_ON blinking, cursor is shown - */ - void -gui_mch_set_blinking(long wait, long on, long off) -{ -#if 0 - // TODO: TODO: TODO: TODO: - blink_waittime = wait; - blink_ontime = on; - blink_offtime = off; -#endif -} - -/* - * Stop the cursor blinking. Show the cursor if it wasn't shown. - */ - void -gui_mch_stop_blink(int may_call_gui_update_cursor) -{ - if (may_call_gui_update_cursor) - gui_update_cursor(TRUE, FALSE); -#if 0 - // TODO: TODO: TODO: TODO: - gui_w32_rm_blink_timer(); - if (blink_state == BLINK_OFF) - gui_update_cursor(TRUE, FALSE); - blink_state = BLINK_NONE; -#endif -} - -/* - * Start the cursor blinking. If it was already blinking, this restarts the - * waiting time and shows the cursor. - */ - void -gui_mch_start_blink(void) -{ - gui_update_cursor(TRUE, FALSE); - // TODO: TODO: TODO: TODO: -// gui_w32_rm_blink_timer(); - - // Only switch blinking on if none of the times is zero -#if 0 - if (blink_waittime && blink_ontime && blink_offtime) - { - blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime, - (TIMERPROC)_OnBlinkTimer); - blink_state = BLINK_ON; - gui_update_cursor(TRUE, FALSE); - } -#endif -} - -/* - * Return the RGB value of a pixel as long. - */ - guicolor_T -gui_mch_get_rgb(guicolor_T pixel) -{ - return (guicolor_T)((Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel)); -} - - - -#ifdef FEAT_BROWSE -/* - * Pop open a file browser and return the file selected, in allocated memory, - * or NULL if Cancel is hit. - * saving - TRUE if the file will be saved to, FALSE if it will be opened. - * title - Title message for the file browser dialog. - * dflt - Default name of file. - * ext - Default extension to be added to files without extensions. - * initdir - directory in which to open the browser (NULL = current dir) - * filter - Filter for matched files to choose from. - * Has a format like this: - * "C Files (*.c)\0*.c\0" - * "All Files\0*.*\0\0" - * If these two strings were concatenated, then a choice of two file - * filters will be selectable to the user. Then only matching files will - * be shown in the browser. If NULL, the default allows all files. - * - * *NOTE* - the filter string must be terminated with TWO nulls. - */ - char_u * -gui_mch_browse( - int saving, - char_u *title, - char_u *dflt, - char_u *ext, - char_u *initdir, - char_u *filter) -{ - // TODO: Add Ammon's safety check (Dany) - NavReplyRecord reply; - char_u *fname = NULL; - char_u **fnames = NULL; - long numFiles; - NavDialogOptions navOptions; - OSErr error; - - // Get Navigation Service Defaults value - NavGetDefaultDialogOptions(&navOptions); - - - // TODO: If we get a :browse args, set the Multiple bit. - navOptions.dialogOptionFlags = kNavAllowInvisibleFiles - | kNavDontAutoTranslate - | kNavDontAddTranslateItems - // | kNavAllowMultipleFiles - | kNavAllowStationery; - - (void) C2PascalString(title, &navOptions.message); - (void) C2PascalString(dflt, &navOptions.savedFileName); - // Could set clientName? - // windowTitle? (there's no title bar?) - - if (saving) - { - // Change first parm AEDesc (typeFSS) *defaultLocation to match dflt - NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL); - if (!reply.validRecord) - return NULL; - } - else - { - // Change first parm AEDesc (typeFSS) *defaultLocation to match dflt - NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL); - if (!reply.validRecord) - return NULL; - } - - fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error); - - NavDisposeReply(&reply); - - if (fnames) - { - fname = fnames[0]; - vim_free(fnames); - } - - // TODO: Shorten the file name if possible - return fname; -} -#endif // FEAT_BROWSE - -#ifdef FEAT_GUI_DIALOG -/* - * Stuff for dialogues - */ - -/* - * Create a dialogue dynamically from the parameter strings. - * type = type of dialogue (question, alert, etc.) - * title = dialogue title. may be NULL for default title. - * message = text to display. Dialogue sizes to accommodate it. - * buttons = '\n' separated list of button captions, default first. - * dfltbutton = number of default button. - * - * This routine returns 1 if the first button is pressed, - * 2 for the second, etc. - * - * 0 indicates Esc was pressed. - * -1 for unexpected error - * - * If stubbing out this fn, return 1. - */ - -typedef struct -{ - short idx; - short width; // Size of the text in pixel - Rect box; -} vgmDlgItm; // Vim Gui_Mac.c Dialog Item - -#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top) - - static void -macMoveDialogItem( - DialogRef theDialog, - short itemNumber, - short X, - short Y, - Rect *inBox) -{ -#if 0 // USE_CARBONIZED - // Untested - MoveDialogItem(theDialog, itemNumber, X, Y); - if (inBox != nil) - GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox); -#else - short itemType; - Handle itemHandle; - Rect localBox; - Rect *itemBox = &localBox; - - if (inBox != nil) - itemBox = inBox; - - GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox); - OffsetRect(itemBox, -itemBox->left, -itemBox->top); - OffsetRect(itemBox, X, Y); - // To move a control (like a button) we need to call both - // MoveControl and SetDialogItem. FAQ 6-18 - if (1) //(itemType & kControlDialogItem) - MoveControl((ControlRef) itemHandle, X, Y); - SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox); -#endif -} - - static void -macSizeDialogItem( - DialogRef theDialog, - short itemNumber, - short width, - short height) -{ - short itemType; - Handle itemHandle; - Rect itemBox; - - GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox); - - // When width or height is zero do not change it - if (width == 0) - width = itemBox.right - itemBox.left; - if (height == 0) - height = itemBox.bottom - itemBox.top; - -#if 0 // USE_CARBONIZED - SizeDialogItem(theDialog, itemNumber, width, height); // Untested -#else - // Resize the bounding box - itemBox.right = itemBox.left + width; - itemBox.bottom = itemBox.top + height; - - // To resize a control (like a button) we need to call both - // SizeControl and SetDialogItem. (deducted from FAQ 6-18) - if (itemType & kControlDialogItem) - SizeControl((ControlRef) itemHandle, width, height); - - // Configure back the item - SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox); -#endif -} - - static void -macSetDialogItemText( - DialogRef theDialog, - short itemNumber, - Str255 itemName) -{ - short itemType; - Handle itemHandle; - Rect itemBox; - - GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox); - - if (itemType & kControlDialogItem) - SetControlTitle((ControlRef) itemHandle, itemName); - else - SetDialogItemText(itemHandle, itemName); -} - - -/* - * ModalDialog() handler for message dialogs that have hotkey accelerators. - * Expects a mapping of hotkey char to control index in gDialogHotKeys; - * setting gDialogHotKeys to NULL disables any hotkey handling. - */ - static pascal Boolean -DialogHotkeyFilterProc ( - DialogRef theDialog, - EventRecord *event, - DialogItemIndex *itemHit) -{ - char_u keyHit; - - if (event->what == keyDown || event->what == autoKey) - { - keyHit = (event->message & charCodeMask); - - if (gDialogHotKeys && gDialogHotKeys[keyHit]) - { -#ifdef DEBUG_MAC_DIALOG_HOTKEYS - printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]); -#endif - *itemHit = gDialogHotKeys[keyHit]; - - // When handing off to StdFilterProc, pretend that the user - // clicked the control manually. Note that this is also supposed - // to cause the button to hilite briefly (to give some user - // feedback), but this seems not to actually work (or it's too - // fast to be seen). - event->what = kEventControlSimulateHit; - - return true; // we took care of it - } - - // Defer to the OS's standard behavior for this event. - // This ensures that Enter will still activate the default button. - return StdFilterProc(theDialog, event, itemHit); - } - return false; // Let ModalDialog deal with it -} - - -/* - * TODO: There have been some crashes with dialogs, check your inbox - * (Jussi) - */ - int -gui_mch_dialog( - int type, - char_u *title, - char_u *message, - char_u *buttons, - int dfltbutton, - char_u *textfield, - int ex_cmd) -{ - Handle buttonDITL; - Handle iconDITL; - Handle inputDITL; - Handle messageDITL; - Handle itemHandle; - Handle iconHandle; - DialogPtr theDialog; - char_u len; - char_u PascalTitle[256]; // place holder for the title - char_u name[256]; - GrafPtr oldPort; - short itemHit; - char_u *buttonChar; - short hotKeys[256]; // map of hotkey -> control ID - char_u aHotKey; - Rect box; - short button; - short lastButton; - short itemType; - short useIcon; - short width; - short totalButtonWidth = 0; // the width of all buttons together - // including spacing - short widestButton = 0; - short dfltButtonEdge = 20; // gut feeling - short dfltElementSpacing = 13; // from IM:V.2-29 - short dfltIconSideSpace = 23; // from IM:V.2-29 - short maximumWidth = 400; // gut feeling - short maxButtonWidth = 175; // gut feeling - - short vertical; - short dialogHeight; - short messageLines = 3; - FontInfo textFontInfo; - - vgmDlgItm iconItm; - vgmDlgItm messageItm; - vgmDlgItm inputItm; - vgmDlgItm buttonItm; - - WindowRef theWindow; - - ModalFilterUPP dialogUPP; - - // Check 'v' flag in 'guioptions': vertical button placement. - vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL); - - // Create a new Dialog Box from template. - theDialog = GetNewDialog(129, nil, (WindowRef) -1); - - // Get the WindowRef - theWindow = GetDialogWindow(theDialog); - - // Hide the window. - // 1. to avoid seeing slow drawing - // 2. to prevent a problem seen while moving dialog item - // within a visible window. (non-Carbon MacOS 9) - // Could be avoided by changing the resource. - HideWindow(theWindow); - - // Change the graphical port to the dialog, - // so we can measure the text with the proper font - GetPort(&oldPort); - SetPortDialogPort(theDialog); - - // Get the info about the default text, - // used to calculate the height of the message - // and of the text field - GetFontInfo(&textFontInfo); - - // Set the dialog title - if (title != NULL) - { - (void) C2PascalString(title, &PascalTitle); - SetWTitle(theWindow, PascalTitle); - } - - // Creates the buttons and add them to the Dialog Box. - buttonDITL = GetResource('DITL', 130); - buttonChar = buttons; - button = 0; - - // initialize the hotkey mapping - CLEAR_FIELD(hotKeys); - - for (;*buttonChar != 0;) - { - // Get the name of the button - button++; - len = 0; - for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++) - { - if (*buttonChar != DLG_HOTKEY_CHAR) - name[++len] = *buttonChar; - else - { - aHotKey = (char_u)*(buttonChar+1); - if (aHotKey >= 'A' && aHotKey <= 'Z') - aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A'); - hotKeys[aHotKey] = button; -#ifdef DEBUG_MAC_DIALOG_HOTKEYS - printf("### hotKey for button %d is '%c'\n", button, aHotKey); -#endif - } - } - - if (*buttonChar != 0) - buttonChar++; - name[0] = len; - - // Add the button - AppendDITL(theDialog, buttonDITL, overlayDITL); // appendDITLRight); - - // Change the button's name - macSetDialogItemText(theDialog, button, name); - - // Resize the button to fit its name - width = StringWidth(name) + 2 * dfltButtonEdge; - // Limit the size of any button to an acceptable value. - // TODO: Should be based on the message width - if (width > maxButtonWidth) - width = maxButtonWidth; - macSizeDialogItem(theDialog, button, width, 0); - - totalButtonWidth += width; - - if (width > widestButton) - widestButton = width; - } - ReleaseResource(buttonDITL); - lastButton = button; - - // Add the icon to the Dialog Box. - iconItm.idx = lastButton + 1; - iconDITL = GetResource('DITL', 131); - switch (type) - { - case VIM_GENERIC: - case VIM_INFO: - case VIM_QUESTION: useIcon = kNoteIcon; break; - case VIM_WARNING: useIcon = kCautionIcon; break; - case VIM_ERROR: useIcon = kStopIcon; break; - default: useIcon = kStopIcon; - } - AppendDITL(theDialog, iconDITL, overlayDITL); - ReleaseResource(iconDITL); - GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box); - // TODO: Should the item be freed? - iconHandle = GetIcon(useIcon); - SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box); - - // Add the message to the Dialog box. - messageItm.idx = lastButton + 2; - messageDITL = GetResource('DITL', 132); - AppendDITL(theDialog, messageDITL, overlayDITL); - ReleaseResource(messageDITL); - GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box); - (void) C2PascalString(message, &name); - SetDialogItemText(itemHandle, name); - messageItm.width = StringWidth(name); - - // Add the input box if needed - if (textfield != NULL) - { - // Cheat for now reuse the message and convert to text edit - inputItm.idx = lastButton + 3; - inputDITL = GetResource('DITL', 132); - AppendDITL(theDialog, inputDITL, overlayDITL); - ReleaseResource(inputDITL); - GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box); -// SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box); - (void) C2PascalString(textfield, &name); - SetDialogItemText(itemHandle, name); - inputItm.width = StringWidth(name); - - // Hotkeys don't make sense if there's a text field - gDialogHotKeys = NULL; - } - else - // Install hotkey table - gDialogHotKeys = (short *)&hotKeys; - - // Set the and button. - SetDialogDefaultItem(theDialog, dfltbutton); - SetDialogCancelItem(theDialog, 0); - - // Reposition element - - // Check if we need to force vertical - if (totalButtonWidth > maximumWidth) - vertical = TRUE; - - // Place icon - macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box); - iconItm.box.right = box.right; - iconItm.box.bottom = box.bottom; - - // Place Message - messageItm.box.left = iconItm.box.right + dfltIconSideSpace; - macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent)); - macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box); - - // Place Input - if (textfield != NULL) - { - inputItm.box.left = messageItm.box.left; - inputItm.box.top = messageItm.box.bottom + dfltElementSpacing; - macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent); - macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box); - // Convert the static text into a text edit. - // For some reason this change need to be done last (Dany) - GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box); - SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box); - SelectDialogItemText(theDialog, inputItm.idx, 0, 32767); - } - - // Place Button - if (textfield != NULL) - { - buttonItm.box.left = inputItm.box.left; - buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing; - } - else - { - buttonItm.box.left = messageItm.box.left; - buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing; - } - - for (button=1; button <= lastButton; button++) - { - - macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box); - // With vertical, it's better to have all buttons the same length - if (vertical) - { - macSizeDialogItem(theDialog, button, widestButton, 0); - GetDialogItem(theDialog, button, &itemType, &itemHandle, &box); - } - // Calculate position of next button - if (vertical) - buttonItm.box.top = box.bottom + dfltElementSpacing; - else - buttonItm.box.left = box.right + dfltElementSpacing; - } - - // Resize the dialog box - dialogHeight = box.bottom + dfltElementSpacing; - SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE); - - // Magic resize - AutoSizeDialog(theDialog); - // Need a horizontal resize anyway so not that useful - - // Display it - ShowWindow(theWindow); -// BringToFront(theWindow); - SelectWindow(theWindow); - -// DrawDialog(theDialog); -#if 0 - GetPort(&oldPort); - SetPortDialogPort(theDialog); -#endif - -#ifdef USE_CARBONKEYHANDLER - // Avoid that we use key events for the main window. - dialog_busy = TRUE; -#endif - - // Prepare the shortcut-handling filterProc for handing to the dialog - dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc); - - // Hang until one of the button is hit - do - ModalDialog(dialogUPP, &itemHit); - while ((itemHit < 1) || (itemHit > lastButton)); - -#ifdef USE_CARBONKEYHANDLER - dialog_busy = FALSE; -#endif - - // Copy back the text entered by the user into the param - if (textfield != NULL) - { - GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box); - GetDialogItemText(itemHandle, (char_u *) &name); -#if IOSIZE < 256 - // Truncate the name to IOSIZE if needed - if (name[0] > IOSIZE) - name[0] = IOSIZE - 1; -#endif - vim_strncpy(textfield, &name[1], name[0]); - } - - // Restore the original graphical port - SetPort(oldPort); - - // Free the modal filterProc - DisposeRoutineDescriptor(dialogUPP); - - // Get ride of the dialog (free memory) - DisposeDialog(theDialog); - - return itemHit; -/* - * Useful thing which could be used - * SetDialogTimeout(): Auto click a button after timeout - * SetDialogTracksCursor() : Get the I-beam cursor over input box - * MoveDialogItem(): Probably better than SetDialogItem - * SizeDialogItem(): (but is it Carbon Only?) - * AutoSizeDialog(): Magic resize of dialog based on text length - */ -} -#endif // FEAT_DIALOG_GUI - -/* - * Display the saved error message(s). - */ -#ifdef USE_MCH_ERRMSG - void -display_errors(void) -{ - char *p; - char_u pError[256]; - - if (error_ga.ga_data == NULL) - return; - - // avoid putting up a message box with blanks only - for (p = (char *)error_ga.ga_data; *p; ++p) - if (!isspace(*p)) - { - if (STRLEN(p) > 255) - pError[0] = 255; - else - pError[0] = STRLEN(p); - - STRNCPY(&pError[1], p, pError[0]); - ParamText(pError, nil, nil, nil); - Alert(128, nil); - break; - // TODO: handled message longer than 256 chars - // use auto-sizeable alert - // or dialog with scrollbars (TextEdit zone) - } - ga_clear(&error_ga); -} -#endif - -/* - * Get current mouse coordinates in text window. - */ - void -gui_mch_getmouse(int *x, int *y) -{ - Point where; - - GetMouse(&where); - - *x = where.h; - *y = where.v; -} - - void -gui_mch_setmouse(int x, int y) -{ - // TODO -#if 0 - // From FAQ 3-11 - - CursorDevicePtr myMouse; - Point where; - - if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap) - != NGetTrapAddress(_Unimplemented, ToolTrap)) - { - // New way - - /* - * Get first device with one button. - * This will probably be the standard mouse - * start at head of cursor dev list - * - */ - - myMouse = nil; - - do - { - // Get the next cursor device - CursorDeviceNextDevice(&myMouse); - } - while ((myMouse != nil) && (myMouse->cntButtons != 1)); - - CursorDeviceMoveTo(myMouse, x, y); - } - else - { - // Old way - where.h = x; - where.v = y; - - *(Point *)RawMouse = where; - *(Point *)MTemp = where; - *(Ptr) CrsrNew = 0xFFFF; - } -#endif -} - - void -gui_mch_show_popupmenu(vimmenu_T *menu) -{ -/* - * Clone PopUp to use menu - * Create a object descriptor for the current selection - * Call the procedure - */ - - MenuHandle CntxMenu; - Point where; - OSStatus status; - UInt32 CntxType; - SInt16 CntxMenuID; - UInt16 CntxMenuItem; - Str255 HelpName = ""; - GrafPtr savePort; - - // Save Current Port: On MacOS X we seem to lose the port - GetPort(&savePort); //OSX - - GetMouse(&where); - LocalToGlobal(&where); //OSX - CntxMenu = menu->submenu_handle; - - // TODO: Get the text selection from Vim - - // Call to Handle Popup - status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp, - HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem); - - if (status == noErr) - { - if (CntxType == kCMMenuItemSelected) - { - // Handle the menu CntxMenuID, CntxMenuItem - // The submenu can be handle directly by gui_mac_handle_menu - // But what about the current menu, is the menu changed by - // ContextualMenuSelect - gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem); - } - else if (CntxMenuID == kCMShowHelpSelected) - { - // Should come up with the help - } - } - - // Restore original Port - SetPort(savePort); //OSX -} - -#if defined(FEAT_CW_EDITOR) || defined(PROTO) -// TODO: Is it need for MACOS_X? (Dany) - void -mch_post_buffer_write(buf_T *buf) -{ - GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec); - Send_KAHL_MOD_AE(buf); -} -#endif - -#ifdef FEAT_TITLE -/* - * Set the window title and icon. - * (The icon is not taken care of). - */ - void -gui_mch_settitle(char_u *title, char_u *icon) -{ - // TODO: Get vim to make sure maxlen (from p_titlelen) is smaller - // that 256. Even better get it to fit nicely in the titlebar. -#ifdef MACOS_CONVERT - CFStringRef windowTitle; - size_t windowTitleLen; -#else - char_u *pascalTitle; -#endif - - if (title == NULL) // nothing to do - return; - -#ifdef MACOS_CONVERT - windowTitleLen = STRLEN(title); - windowTitle = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen); - - if (windowTitle) - { - SetWindowTitleWithCFString(gui.VimWindow, windowTitle); - CFRelease(windowTitle); - } -#else - pascalTitle = C2Pascal_save(title); - if (pascalTitle != NULL) - { - SetWTitle(gui.VimWindow, pascalTitle); - vim_free(pascalTitle); - } -#endif -} -#endif - -/* - * Transferred from os_mac.c for MacOS X using os_unix.c prep work - */ - - int -C2PascalString(char_u *CString, Str255 *PascalString) -{ - char_u *PascalPtr = (char_u *) PascalString; - int len; - int i; - - PascalPtr[0] = 0; - if (CString == NULL) - return 0; - - len = STRLEN(CString); - if (len > 255) - len = 255; - - for (i = 0; i < len; i++) - PascalPtr[i+1] = CString[i]; - - PascalPtr[0] = len; - - return 0; -} - - int -GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec) -{ - // From FAQ 8-12 - Str255 filePascal; - CInfoPBRec myCPB; - OSErr err; - - (void) C2PascalString(file, &filePascal); - - myCPB.dirInfo.ioNamePtr = filePascal; - myCPB.dirInfo.ioVRefNum = 0; - myCPB.dirInfo.ioFDirIndex = 0; - myCPB.dirInfo.ioDrDirID = 0; - - err= PBGetCatInfo(&myCPB, false); - - // vRefNum, dirID, name - FSMakeFSSpec(0, 0, filePascal, fileFSSpec); - - // TODO: Use an error code mechanism - return 0; -} - -/* - * Convert a FSSpec to a full path - */ - -char_u *FullPathFromFSSpec_save(FSSpec file) -{ - /* - * TODO: Add protection for 256 char max. - */ - - CInfoPBRec theCPB; - char_u fname[256]; - char_u *filenamePtr = fname; - OSErr error; - int folder = 1; -#ifdef USE_UNIXFILENAME - SInt16 dfltVol_vRefNum; - SInt32 dfltVol_dirID; - FSRef refFile; - OSStatus status; - UInt32 pathSize = 256; - char_u pathname[256]; - char_u *path = pathname; -#else - Str255 directoryName; - char_u temporary[255]; - char_u *temporaryPtr = temporary; -#endif - -#ifdef USE_UNIXFILENAME - // Get the default volume - // TODO: Remove as this only work if Vim is on the Boot Volume - error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID); - - if (error) - return NULL; -#endif - - // Start filling fname with file.name - vim_strncpy(filenamePtr, &file.name[1], file.name[0]); - - // Get the info about the file specified in FSSpec - theCPB.dirInfo.ioFDirIndex = 0; - theCPB.dirInfo.ioNamePtr = file.name; - theCPB.dirInfo.ioVRefNum = file.vRefNum; - //theCPB.hFileInfo.ioDirID = 0; - theCPB.dirInfo.ioDrDirID = file.parID; - - // As ioFDirIndex = 0, get the info of ioNamePtr, - // which is relative to ioVrefNum, ioDirID - error = PBGetCatInfo(&theCPB, false); - - // If we are called for a new file we expect fnfErr - if ((error) && (error != fnfErr)) - return NULL; - - // Check if it's a file or folder - // default to file if file don't exist - if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error)) - folder = 0; // It's not a folder - else - folder = 1; - -#ifdef USE_UNIXFILENAME - /* - * The functions used here are available in Carbon, but do nothing on - * MacOS 8 and 9. - */ - if (error == fnfErr) - { - // If the file to be saved does not already exist, it isn't possible - // to convert its FSSpec into an FSRef. But we can construct an - // FSSpec for the file's parent folder (since we have its volume and - // directory IDs), and since that folder does exist, we can convert - // that FSSpec into an FSRef, convert the FSRef in turn into a path, - // and, finally, append the filename. - FSSpec dirSpec; - FSRef dirRef; - Str255 emptyFilename = "\p"; - error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum, - theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec); - if (error) - return NULL; - - error = FSpMakeFSRef(&dirSpec, &dirRef); - if (error) - return NULL; - - status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize); - if (status) - return NULL; - - STRCAT(path, "/"); - STRCAT(path, filenamePtr); - } - else - { - // If the file to be saved already exists, we can get its full path - // by converting its FSSpec into an FSRef. - error=FSpMakeFSRef(&file, &refFile); - if (error) - return NULL; - - status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize); - if (status) - return NULL; - } - - // Add a slash at the end if needed - if (folder) - STRCAT(path, "/"); - - return (vim_strsave(path)); -#else - // TODO: Get rid of all USE_UNIXFILENAME below - // Set ioNamePtr, it's the same area which is always reused. - theCPB.dirInfo.ioNamePtr = directoryName; - - // Trick for first entry, set ioDrParID to the first value - // we want for ioDrDirID - theCPB.dirInfo.ioDrParID = file.parID; - theCPB.dirInfo.ioDrDirID = file.parID; - - if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/)) - do - { - theCPB.dirInfo.ioFDirIndex = -1; - // theCPB.dirInfo.ioNamePtr = directoryName; Already done above. - theCPB.dirInfo.ioVRefNum = file.vRefNum; - // theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 - theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID; - - // As ioFDirIndex = -1, get the info of ioDrDirID, - // *ioNamePtr[0 TO 31] will be updated - error = PBGetCatInfo(&theCPB,false); - - if (error) - return NULL; - - // Put the new directoryName in front of the current fname - STRCPY(temporaryPtr, filenamePtr); - vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]); - STRCAT(filenamePtr, ":"); - STRCAT(filenamePtr, temporaryPtr); - } -#if 1 // def USE_UNIXFILENAME - while ((theCPB.dirInfo.ioDrParID != fsRtDirID) - /* && (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/); -#else - while (theCPB.dirInfo.ioDrDirID != fsRtDirID); -#endif - - // Get the information about the volume on which the file reside - theCPB.dirInfo.ioFDirIndex = -1; - // theCPB.dirInfo.ioNamePtr = directoryName; Already done above. - theCPB.dirInfo.ioVRefNum = file.vRefNum; - // theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 - theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID; - - // As ioFDirIndex = -1, get the info of ioDrDirID, - // *ioNamePtr[0 TO 31] will be updated - error = PBGetCatInfo(&theCPB,false); - - if (error) - return NULL; - - // For MacOS Classic always add the volume name - // For MacOS X add the volume name preceded by "Volumes" - // when we are not referring to the boot volume -#ifdef USE_UNIXFILENAME - if (file.vRefNum != dfltVol_vRefNum) -#endif - { - // Add the volume name - STRCPY(temporaryPtr, filenamePtr); - vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]); - STRCAT(filenamePtr, ":"); - STRCAT(filenamePtr, temporaryPtr); - -#ifdef USE_UNIXFILENAME - STRCPY(temporaryPtr, filenamePtr); - filenamePtr[0] = 0; // NULL terminate the string - STRCAT(filenamePtr, "Volumes:"); - STRCAT(filenamePtr, temporaryPtr); -#endif - } - - // Append final path separator if it's a folder - if (folder) - STRCAT(fname, ":"); - - // As we use Unix File Name for MacOS X convert it -#ifdef USE_UNIXFILENAME - // Need to insert leading / - // TODO: get the above code to use directly the / - STRCPY(&temporaryPtr[1], filenamePtr); - temporaryPtr[0] = '/'; - STRCPY(filenamePtr, temporaryPtr); - { - char *p; - for (p = fname; *p; p++) - if (*p == ':') - *p = '/'; - } -#endif - - return (vim_strsave(fname)); -#endif -} - -#if defined(USE_CARBONKEYHANDLER) || defined(PROTO) -/* - * Input Method Control functions. - */ - -/* - * Notify cursor position to IM. - */ - void -im_set_position(int row, int col) -{ -# if 0 - // TODO: Implement me! - im_start_row = row; - im_start_col = col; -# endif -} - -static ScriptLanguageRecord gTSLWindow; -static ScriptLanguageRecord gTSLInsert; -static ScriptLanguageRecord gTSLDefault = { 0, 0 }; - -static Component gTSCWindow; -static Component gTSCInsert; -static Component gTSCDefault; - -static int im_initialized = 0; - - static void -im_on_window_switch(int active) -{ - ScriptLanguageRecord *slptr = NULL; - OSStatus err; - - if (! gui.in_use) - return; - - if (im_initialized == 0) - { - im_initialized = 1; - - // save default TSM component (should be U.S.) to default - GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault, - kKeyboardInputMethodClass); - } - - if (active == TRUE) - { - im_is_active = TRUE; - ActivateTSMDocument(gTSMDocument); - slptr = &gTSLWindow; - - if (slptr) - { - err = SetDefaultInputMethodOfClass(gTSCWindow, slptr, - kKeyboardInputMethodClass); - if (err == noErr) - err = SetTextServiceLanguage(slptr); - - if (err == noErr) - KeyScript(slptr->fScript | smKeyForceKeyScriptMask); - } - } - else - { - err = GetTextServiceLanguage(&gTSLWindow); - if (err == noErr) - slptr = &gTSLWindow; - - if (slptr) - GetDefaultInputMethodOfClass(&gTSCWindow, slptr, - kKeyboardInputMethodClass); - - im_is_active = FALSE; - DeactivateTSMDocument(gTSMDocument); - } -} - -/* - * Set IM status on ("active" is TRUE) or off ("active" is FALSE). - */ - void -im_set_active(int active) -{ - ScriptLanguageRecord *slptr = NULL; - OSStatus err; - - if (!gui.in_use) - return; - - if (im_initialized == 0) - { - im_initialized = 1; - - // save default TSM component (should be U.S.) to default - GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault, - kKeyboardInputMethodClass); - } - - if (active == TRUE) - { - im_is_active = TRUE; - ActivateTSMDocument(gTSMDocument); - slptr = &gTSLInsert; - - if (slptr) - { - err = SetDefaultInputMethodOfClass(gTSCInsert, slptr, - kKeyboardInputMethodClass); - if (err == noErr) - err = SetTextServiceLanguage(slptr); - - if (err == noErr) - KeyScript(slptr->fScript | smKeyForceKeyScriptMask); - } - } - else - { - err = GetTextServiceLanguage(&gTSLInsert); - if (err == noErr) - slptr = &gTSLInsert; - - if (slptr) - GetDefaultInputMethodOfClass(&gTSCInsert, slptr, - kKeyboardInputMethodClass); - - // restore to default when switch to normal mode, so than we could - // enter commands easier - SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault, - kKeyboardInputMethodClass); - SetTextServiceLanguage(&gTSLDefault); - - im_is_active = FALSE; - DeactivateTSMDocument(gTSMDocument); - } -} - -/* - * Get IM status. When IM is on, return not 0. Else return 0. - */ - int -im_get_status(void) -{ - if (! gui.in_use) - return 0; - - return im_is_active; -} - -#endif - - - -#if defined(FEAT_GUI_TABLINE) || defined(PROTO) -// drawer implementation -static MenuRef contextMenu = NULL; -enum -{ - kTabContextMenuId = 42 -}; - -// the caller has to CFRelease() the returned string - static CFStringRef -getTabLabel(tabpage_T *page) -{ - get_tabline_label(page, FALSE); -#ifdef MACOS_CONVERT - return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff)); -#else - // TODO: check internal encoding? - return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff, - kCFStringEncodingMacRoman); -#endif -} - - -#define DRAWER_SIZE 150 -#define DRAWER_INSET 16 - -static ControlRef dataBrowser = NULL; - -// when the tabline is hidden, vim doesn't call update_tabline(). When -// the tabline is shown again, show_tabline() is called before update_tabline(), -// and because of this, the tab labels and vim's internal tabs are out of sync -// for a very short time. to prevent inconsistent state, we store the labels -// of the tabs, not pointers to the tabs (which are invalid for a short time). -static CFStringRef *tabLabels = NULL; -static int tabLabelsSize = 0; - -enum -{ - kTabsColumn = 'Tabs' -}; - - static int -getTabCount(void) -{ - tabpage_T *tp; - int numTabs = 0; - - FOR_ALL_TABPAGES(tp) - ++numTabs; - return numTabs; -} - -// data browser item display callback - static OSStatus -dbItemDataCallback(ControlRef browser, - DataBrowserItemID itemID, - DataBrowserPropertyID property /* column id */, - DataBrowserItemDataRef itemData, - Boolean changeValue) -{ - OSStatus status = noErr; - - // assert(property == kTabsColumn); // why is this violated?? - - // changeValue is true if we have a modifiable list and data was changed. - // In our case, it's always false. - // (that is: if (changeValue) updateInternalData(); else return - // internalData(); - if (!changeValue) - { - CFStringRef str; - - assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize); - str = tabLabels[itemID - 1]; - status = SetDataBrowserItemDataText(itemData, str); - } - else - status = errDataBrowserPropertyNotSupported; - - return status; -} - -// data browser action callback - static void -dbItemNotificationCallback(ControlRef browser, - DataBrowserItemID item, - DataBrowserItemNotification message) -{ - switch (message) - { - case kDataBrowserItemSelected: - send_tabline_event(item); - break; - } -} - -// callbacks needed for contextual menu: - static void -dbGetContextualMenuCallback(ControlRef browser, - MenuRef *menu, - UInt32 *helpType, - CFStringRef *helpItemString, - AEDesc *selection) -{ - // on mac os 9: kCMHelpItemNoHelp, but it's not the same - *helpType = kCMHelpItemRemoveHelp; // OS X only ;-) - *helpItemString = NULL; - - *menu = contextMenu; -} - - static void -dbSelectContextualMenuCallback(ControlRef browser, - MenuRef menu, - UInt32 selectionType, - SInt16 menuID, - MenuItemIndex menuItem) -{ - if (selectionType == kCMMenuItemSelected) - { - MenuCommand command; - GetMenuItemCommandID(menu, menuItem, &command); - - // get tab that was selected when the context menu appeared - // (there is always one tab selected). TODO: check if the context menu - // isn't opened on an item but on empty space (has to be possible some - // way, the finder does it too ;-) ) - Handle items = NewHandle(0); - if (items != NULL) - { - int numItems; - - GetDataBrowserItems(browser, kDataBrowserNoItem, false, - kDataBrowserItemIsSelected, items); - numItems = GetHandleSize(items) / sizeof(DataBrowserItemID); - if (numItems > 0) - { - int idx; - DataBrowserItemID *itemsPtr; - - HLock(items); - itemsPtr = (DataBrowserItemID *)*items; - idx = itemsPtr[0]; - HUnlock(items); - send_tabline_menu_event(idx, command); - } - DisposeHandle(items); - } - } -} - -// focus callback of the data browser to always leave focus in vim - static OSStatus -dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data) -{ - assert(GetEventClass(event) == kEventClassControl - && GetEventKind(event) == kEventControlSetFocusPart); - - return paramErr; -} - - -// drawer callback to resize data browser to drawer size - static OSStatus -drawerCallback(EventHandlerCallRef handler, EventRef event, void *data) -{ - switch (GetEventKind(event)) - { - case kEventWindowBoundsChanged: // move or resize - { - UInt32 attribs; - GetEventParameter(event, kEventParamAttributes, typeUInt32, - NULL, sizeof(attribs), NULL, &attribs); - if (attribs & kWindowBoundsChangeSizeChanged) // resize - { - Rect r; - GetWindowBounds(drawer, kWindowContentRgn, &r); - SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top); - SetControlBounds(dataBrowser, &r); - SetDataBrowserTableViewNamedColumnWidth(dataBrowser, - kTabsColumn, r.right); - } - } - break; - } - - return eventNotHandledErr; -} - -// Load DataBrowserChangeAttributes() dynamically on tiger (and better). -// This way the code works on 10.2 and 10.3 as well (it doesn't have the -// blue highlights in the list view on these systems, though. Oh well.) - - -#import - -enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) }; - - static OSStatus -myDataBrowserChangeAttributes(ControlRef inDataBrowser, - OptionBits inAttributesToSet, - OptionBits inAttributesToClear) -{ - long osVersion; - char *symbolName; - NSSymbol symbol = NULL; - OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser, - OptionBits inAttributesToSet, OptionBits inAttributesToClear); - - Gestalt(gestaltSystemVersion, &osVersion); - if (osVersion < 0x1040) // only supported for 10.4 (and up) - return noErr; - - // C name mangling... - symbolName = "_DataBrowserChangeAttributes"; - if (!NSIsSymbolNameDefined(symbolName) - || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL) - return noErr; - - dataBrowserChangeAttributes = NSAddressOfSymbol(symbol); - if (dataBrowserChangeAttributes == NULL) - return noErr; // well... - return dataBrowserChangeAttributes(inDataBrowser, - inAttributesToSet, inAttributesToClear); -} - - static void -initialise_tabline(void) -{ - Rect drawerRect = { 0, 0, 0, DRAWER_SIZE }; - DataBrowserCallbacks dbCallbacks; - EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart}; - EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged}; - DataBrowserListViewColumnDesc colDesc; - - // drawers have to have compositing enabled - CreateNewWindow(kDrawerWindowClass, - kWindowStandardHandlerAttribute - | kWindowCompositingAttribute - | kWindowResizableAttribute - | kWindowLiveResizeAttribute, - &drawerRect, &drawer); - - SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true); - SetDrawerParent(drawer, gui.VimWindow); - SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET); - - - // create list view embedded in drawer - CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView, - &dataBrowser); - - dbCallbacks.version = kDataBrowserLatestCallbacks; - InitDataBrowserCallbacks(&dbCallbacks); - dbCallbacks.u.v1.itemDataCallback = - NewDataBrowserItemDataUPP(dbItemDataCallback); - dbCallbacks.u.v1.itemNotificationCallback = - NewDataBrowserItemNotificationUPP(dbItemNotificationCallback); - dbCallbacks.u.v1.getContextualMenuCallback = - NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback); - dbCallbacks.u.v1.selectContextualMenuCallback = - NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback); - - SetDataBrowserCallbacks(dataBrowser, &dbCallbacks); - - SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header - SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical - SetDataBrowserSelectionFlags(dataBrowser, - kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet); - SetDataBrowserTableViewHiliteStyle(dataBrowser, - kDataBrowserTableViewFillHilite); - Boolean b = false; - SetControlData(dataBrowser, kControlEntireControl, - kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b); - - // enable blue background in data browser (this is only in 10.4 and vim - // has to support older osx versions as well, so we have to load this - // function dynamically) - myDataBrowserChangeAttributes(dataBrowser, - kMyDataBrowserAttributeListViewAlternatingRowColors, 0); - - // install callback that keeps focus in vim and away from the data browser - InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent, - NULL, NULL); - - // install callback that keeps data browser at the size of the drawer - InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent, - NULL, NULL); - - // add "tabs" column to data browser - colDesc.propertyDesc.propertyID = kTabsColumn; - colDesc.propertyDesc.propertyType = kDataBrowserTextType; - - // add if items can be selected (?): kDataBrowserListViewSelectionColumn - colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags; - - colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc; - colDesc.headerBtnDesc.minimumWidth = 100; - colDesc.headerBtnDesc.maximumWidth = 150; - colDesc.headerBtnDesc.titleOffset = 0; - colDesc.headerBtnDesc.titleString = CFSTR("Tabs"); - colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing; - colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font - colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly; - - AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0); - - // create tabline popup menu required by vim docs (see :he tabline-menu) - CreateNewMenu(kTabContextMenuId, 0, &contextMenu); - AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close Tab"), 0, - TABLINE_MENU_CLOSE, NULL); - AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0, - TABLINE_MENU_NEW, NULL); - AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0, - TABLINE_MENU_OPEN, NULL); -} - - -/* - * Show or hide the tabline. - */ - void -gui_mch_show_tabline(int showit) -{ - if (showit == 0) - CloseDrawer(drawer, true); - else - OpenDrawer(drawer, kWindowEdgeRight, true); -} - -/* - * Return TRUE when tabline is displayed. - */ - int -gui_mch_showing_tabline(void) -{ - WindowDrawerState state = GetDrawerState(drawer); - - return state == kWindowDrawerOpen || state == kWindowDrawerOpening; -} - -/* - * Update the labels of the tabline. - */ - void -gui_mch_update_tabline(void) -{ - tabpage_T *tp; - int numTabs = getTabCount(); - int nr = 1; - int curtabidx = 1; - - // adjust data browser - if (tabLabels != NULL) - { - int i; - - for (i = 0; i < tabLabelsSize; ++i) - CFRelease(tabLabels[i]); - free(tabLabels); - } - tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef)); - tabLabelsSize = numTabs; - - for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr) - { - if (tp == curtab) - curtabidx = nr; - tabLabels[nr-1] = getTabLabel(tp); - } - - RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL, - kDataBrowserItemNoProperty); - // data browser uses ids 1, 2, 3, ... numTabs per default, so we - // can pass NULL for the id array - AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL, - kDataBrowserItemNoProperty); - - DataBrowserItemID item = curtabidx; - SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign); -} - -/* - * Set the current tab to "nr". First tab is 1. - */ - void -gui_mch_set_curtab(int nr) -{ - DataBrowserItemID item = nr; - SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign); - - // TODO: call something like this?: (or restore scroll position, or...) - RevealDataBrowserItem(dataBrowser, item, kTabsColumn, - kDataBrowserRevealOnly); -} - -#endif // FEAT_GUI_TABLINE diff --git a/src/if_mzsch.c b/src/if_mzsch.c index bfcdbea97e..7b52936709 100644 --- a/src/if_mzsch.c +++ b/src/if_mzsch.c @@ -812,10 +812,6 @@ static guint timer_id = 0; #elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) static void timer_proc(XtPointer, XtIntervalId *); static XtIntervalId timer_id = (XtIntervalId)0; -#elif defined(FEAT_GUI_MAC) -pascal void timer_proc(EventLoopTimerRef, void *); -static EventLoopTimerRef timer_id = NULL; -static EventLoopTimerUPP timerUPP; #endif #if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL) // Win32 console and Unix @@ -852,9 +848,6 @@ timer_proc(gpointer data UNUSED) # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) static void timer_proc(XtPointer timed_out UNUSED, XtIntervalId *interval_id UNUSED) -# elif defined(FEAT_GUI_MAC) - pascal void -timer_proc(EventLoopTimerRef theTimer UNUSED, void *userData UNUSED) # endif { scheme_check_threads(); @@ -877,10 +870,6 @@ setup_timer(void) timer_id = g_timeout_add((guint)p_mzq, (GSourceFunc)timer_proc, NULL); # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) timer_id = XtAppAddTimeOut(app_context, p_mzq, timer_proc, NULL); -# elif defined(FEAT_GUI_MAC) - timerUPP = NewEventLoopTimerUPP(timer_proc); - InstallEventLoopTimer(GetMainEventLoop(), p_mzq * kEventDurationMillisecond, - p_mzq * kEventDurationMillisecond, timerUPP, NULL, &timer_id); # endif } @@ -893,9 +882,6 @@ remove_timer(void) g_source_remove(timer_id); # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) XtRemoveTimeOut(timer_id); -# elif defined(FEAT_GUI_MAC) - RemoveEventLoopTimer(timer_id); - DisposeEventLoopTimerUPP(timerUPP); # endif timer_id = 0; } diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 4fe3d7d20b..390aa8dce4 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -133,7 +133,7 @@ static void scroll(VTermState *state, VTermRect rect, int downward, int rightwar if(rect.start_col == 0 && rect.end_col == state->cols && rightward == 0) { int height = rect.end_row - rect.start_row - abs(downward); int row; - VTermLineInfo zeroLineInfo = { 0 }; + VTermLineInfo zeroLineInfo = {0x0}; if(downward > 0) { memmove(state->lineinfo + rect.start_row, @@ -1813,7 +1813,7 @@ static int on_resize(int rows, int cols, void *user) } for( ; row < rows; row++) { - VTermLineInfo lineInfo = {0}; + VTermLineInfo lineInfo = {0x0}; newlineinfo[row] = lineInfo; } diff --git a/src/main.c b/src/main.c index 81bd4a1369..3beb8e414c 100644 --- a/src/main.c +++ b/src/main.c @@ -314,33 +314,6 @@ main params.want_full_screen = FALSE; #endif -#if defined(FEAT_GUI_MAC) && defined(MACOS_X_DARWIN) - // When the GUI is started from Finder, need to display messages in a - // message box. isatty(2) returns TRUE anyway, thus we need to check the - // name to know we're not started from a terminal. - if (gui.starting && (!isatty(2) || strcmp("/dev/console", ttyname(2)) == 0)) - { - params.want_full_screen = FALSE; - - // Avoid always using "/" as the current directory. Note that when - // started from Finder the arglist will be filled later in - // HandleODocAE() and "fname" will be NULL. - if (getcwd((char *)NameBuff, MAXPATHL) != NULL - && STRCMP(NameBuff, "/") == 0) - { - if (params.fname != NULL) - (void)vim_chdirfile(params.fname, "drop"); - else - { - expand_env((char_u *)"$HOME", NameBuff, MAXPATHL); - vim_chdir(NameBuff); - } - if (start_dir != NULL) - mch_dirname(start_dir, MAXPATHL); - } - } -#endif - /* * mch_init() sets up the terminal (window) for use. This must be * done after resetting full_screen, otherwise it may move the cursor. @@ -1922,18 +1895,6 @@ parse_command_name(mparm_T *parmp) initstr = gettail((char_u *)parmp->argv[0]); -#ifdef FEAT_GUI_MAC - // An issue has been seen when launching Vim in such a way that - // $PWD/$ARGV[0] or $ARGV[0] is not the absolute path to the - // executable or a symbolic link of it. Until this issue is resolved - // we prohibit the GUI from being used. - if (STRCMP(initstr, parmp->argv[0]) == 0) - disallow_gui = TRUE; - - // TODO: On MacOS X default to gui if argv[0] ends in: - // /Vim.app/Contents/MacOS/Vim -#endif - #ifdef FEAT_EVAL set_vim_var_string(VV_PROGNAME, initstr, -1); set_progpath((char_u *)parmp->argv[0]); diff --git a/src/misc2.c b/src/misc2.c index 2601d9364d..f19ad723f4 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -3348,7 +3348,7 @@ same_directory(char_u *f1, char_u *f2) } #if defined(FEAT_SESSION) || defined(FEAT_AUTOCHDIR) \ - || defined(MSWIN) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK) \ + || defined(MSWIN) || defined(FEAT_GUI_GTK) \ || defined(FEAT_NETBEANS_INTG) \ || defined(PROTO) /* diff --git a/src/mouse.c b/src/mouse.c index e77284fd38..0e25d0d483 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -116,9 +116,9 @@ find_end_of_word(pos_T *pos) #if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) \ || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \ - || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_PHOTON) \ - || defined(FEAT_TERM_POPUP_MENU) \ - || defined(FEAT_GUI_MACVIM) + || defined(FEAT_GUI_MACVIM) \ + || defined(FEAT_GUI_PHOTON) \ + || defined(FEAT_TERM_POPUP_MENU) # define USE_POPUP_SETPOS # define NEED_VCOL2COL @@ -533,7 +533,7 @@ do_mouse( if (gui.in_use) { # if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) \ - || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) + || defined(FEAT_GUI_PHOTON) if (!is_click) // Ignore right button release events, only shows the popup // menu on the button down event. diff --git a/src/option.h b/src/option.h index a9e2f4ed90..76dd4ee0a3 100644 --- a/src/option.h +++ b/src/option.h @@ -713,9 +713,6 @@ EXTERN int p_lpl; // 'loadplugins' #if defined(DYNAMIC_LUA) EXTERN char_u *p_luadll; // 'luadll' #endif -#ifdef FEAT_GUI_MAC -EXTERN int p_macatsui; // 'macatsui' -#endif #ifdef FEAT_GUI_MACVIM EXTERN int p_macligatures; // 'macligatures' EXTERN int p_macthinstrokes; // 'macthinstrokes' diff --git a/src/optiondefs.h b/src/optiondefs.h index 9f1825e009..f41dddfd47 100644 --- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -1255,7 +1255,7 @@ static struct vimoption options[] = (char_u *)&p_go, PV_NONE, # if defined(FEAT_GUI_MACVIM) {(char_u *)"egmrL", (char_u *)0L} -# elif defined(UNIX) && !defined(FEAT_GUI_MAC) +# elif defined(UNIX) {(char_u *)"aegimrLtT", (char_u *)0L} # else {(char_u *)"egmrLtT", (char_u *)0L} @@ -1668,13 +1668,8 @@ static struct vimoption options[] = #endif SCTX_INIT}, {"macatsui", NULL, P_BOOL|P_VI_DEF|P_RCLR, -#ifdef FEAT_GUI_MAC - (char_u *)&p_macatsui, PV_NONE, - {(char_u *)TRUE, (char_u *)0L} -#else (char_u *)NULL, PV_NONE, {(char_u *)"", (char_u *)0L} -#endif SCTX_INIT}, {"macligatures", NULL, P_BOOL|P_VI_DEF|P_RCLR, #ifdef FEAT_GUI_MACVIM diff --git a/src/os_mac.h b/src/os_mac.h index d052bb5d27..6524609152 100644 --- a/src/os_mac.h +++ b/src/os_mac.h @@ -20,25 +20,6 @@ # include #endif -/* - * Macintosh machine-dependent things. - * - * Include the Mac header files, unless also compiling with X11 (the header - * files have many conflicts). - */ -#ifdef FEAT_GUI_MAC -# include // Apple calls it QuickDraw.h... -# include -# include -# include -# include -# include -# include -# include -# include -# include -#endif - /* * Unix interface */ diff --git a/src/os_mac_conv.c b/src/os_mac_conv.c index 9de1dd837e..679132f2a0 100644 --- a/src/os_mac_conv.c +++ b/src/os_mac_conv.c @@ -17,7 +17,7 @@ #include "vim.h" -#if !defined(FEAT_GUI_MAC) && !defined(PROTO) +#if !defined(PROTO) # include #endif diff --git a/src/os_macosx.m b/src/os_macosx.m index 881bf8e967..2b877808e2 100644 --- a/src/os_macosx.m +++ b/src/os_macosx.m @@ -33,7 +33,7 @@ * gui_mac.c are used then. TODO: remove those instead? * But for MacVim we do need these ones. */ -#if defined(FEAT_CLIPBOARD) && (!defined(FEAT_GUI_ENABLED) || defined(FEAT_GUI_MACVIM)) +#if defined(FEAT_CLIPBOARD) && (!defined(FEAT_GUI_ENABLED)) /* Used to identify clipboard data copied from Vim. */ diff --git a/src/os_unix.c b/src/os_unix.c index ef89517274..4ceab10d99 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -2194,7 +2194,7 @@ mch_settitle(char_u *title, char_u *icon) if (get_x11_windis() == OK) type = 1; #else -# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) \ +# if defined(FEAT_GUI_PHOTON) \ || defined(FEAT_GUI_MACVIM) \ || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU) if (gui.in_use) @@ -2231,7 +2231,7 @@ mch_settitle(char_u *title, char_u *icon) #endif #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU) \ || defined(FEAT_GUI_MACVIM) \ - || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) + || defined(FEAT_GUI_PHOTON) else gui_mch_settitle(title, icon); #endif diff --git a/src/popupwin.c b/src/popupwin.c index 5325bf6f18..ff9e810044 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -1134,6 +1134,7 @@ popup_adjust_position(win_T *wp) int wantline = wp->w_wantline; // adjusted for textprop int wantcol = wp->w_wantcol; // adjusted for textprop int use_wantcol = wantcol != 0; + int adjust_height_for_top_aligned = FALSE; wp->w_winrow = 0; wp->w_wincol = 0; @@ -1483,16 +1484,7 @@ popup_adjust_position(win_T *wp) // Not enough space and more space on the other side: make top // aligned. wp->w_winrow = (wantline < 0 ? 0 : wantline) + 1; - if (wp->w_winrow + wp->w_height + extra_height >= Rows) - { - wp->w_height = Rows - wp->w_winrow - extra_height; - if (wp->w_want_scrollbar -#ifdef FEAT_TERMINAL - && wp->w_buffer->b_term == NULL -#endif - ) - wp->w_has_scrollbar = TRUE; - } + adjust_height_for_top_aligned = TRUE; } } else if (wp->w_popup_pos == POPPOS_TOPRIGHT @@ -1513,9 +1505,25 @@ popup_adjust_position(win_T *wp) } } else + { wp->w_winrow = wantline - 1; + adjust_height_for_top_aligned = TRUE; + } } - // make sure w_window is valid + + if (adjust_height_for_top_aligned && wp->w_want_scrollbar + && wp->w_winrow + wp->w_height + extra_height > Rows) + { + // Bottom of the popup goes below the last line, reduce the height and + // add a scrollbar. + wp->w_height = Rows - wp->w_winrow - extra_height; +#ifdef FEAT_TERMINAL + if (wp->w_buffer->b_term == NULL) +#endif + wp->w_has_scrollbar = TRUE; + } + + // make sure w_winrow is valid if (wp->w_winrow >= Rows) wp->w_winrow = Rows - 1; else if (wp->w_winrow < 0) @@ -3201,7 +3209,14 @@ popup_do_filter(int c) res = invoke_popup_filter(wp, c); if (must_redraw > was_must_redraw) + { + int save_got_int = got_int; + + // Reset got_int to avoid a function used in the statusline aborts. + got_int = FALSE; redraw_after_callback(FALSE); + got_int |= save_got_int; + } recursive = FALSE; KeyTyped = save_KeyTyped; return res; diff --git a/src/proto.h b/src/proto.h index a22d5c0a68..011c39abd7 100644 --- a/src/proto.h +++ b/src/proto.h @@ -323,9 +323,6 @@ extern char *vim_SelFile(Widget toplevel, char *prompt, char *init_path, int (*s # ifdef FEAT_GUI_HAIKU # include "gui_haiku.pro" # endif -# ifdef FEAT_GUI_MAC -# include "gui_mac.pro" -# endif # ifdef FEAT_GUI_MACVIM # include "gui_macvim.pro" # endif diff --git a/src/proto/gui_mac.pro b/src/proto/gui_mac.pro deleted file mode 100644 index 1fa34532b2..0000000000 --- a/src/proto/gui_mac.pro +++ /dev/null @@ -1,153 +0,0 @@ -/* gui_mac.c */ - -/* - * Mac specific prototypes - */ - -pascal Boolean WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn); -pascal void gui_mac_scroll_action(ControlHandle theControl, short partCode); -pascal void gui_mac_drag_thumb (ControlHandle theControl, short partCode); -void gui_mac_handle_event(EventRecord *event); -void gui_mac_doMouseDown(EventRecord *theEvent); -void gui_mac_do_key(EventRecord *theEvent); -void gui_mac_handle_menu(long menuChoice); -void gui_mac_focus_change(EventRecord *event); -void gui_mac_update(EventRecord *event); -short gui_mch_get_mac_menu_item_index(vimmenu_T *menu, vimmenu_T *parent); -int gui_mch_is_blinking(void); -int gui_mch_is_blink_off(void); -void gui_mch_set_blinking(long wait, long on, long off); -void gui_mch_stop_blink(int may_call_gui_update_cursor); -void gui_mch_start_blink(void); -void gui_mch_getmouse(int *x, int *y); -void gui_mch_setmouse(int x, int y); -void gui_mch_prepare(int *argc, char **argv); -int gui_mch_init_check(void); -int gui_mch_init(void); -void gui_mch_new_colors(void); -int gui_mch_open(void); -void gui_mch_exit(int); -void gui_mch_set_winsize(int width, int height, int min_width, int min_height, int base_width, int base_height); -int gui_mch_get_winpos(int *x, int *y); -void gui_mch_set_winpos(int x, int y); -void gui_mch_set_shellsize(int width, int height, int min_width, int min_height, int base_width, int base_height, int direction); -void gui_mch_get_screen_dimensions(int *screen_w, int *screen_h); -void gui_mch_set_text_area_pos(int x, int y, int w, int h); -void gui_mch_enable_scrollbar(scrollbar_T *sb, int flag); -void gui_mch_set_scrollbar_thumb(scrollbar_T *sb, long val, long size, long max); -void gui_mch_set_scrollbar_pos(scrollbar_T *sb, int x, int y, int w, int h); -int gui_mch_get_scrollbar_xpadding(void); -int gui_mch_get_scrollbar_ypadding(void); -void gui_mch_create_scrollbar(scrollbar_T *sb, int orient); -void gui_mch_destroy_scrollbar(scrollbar_T *sb); -int gui_mch_adjust_charheight(void); -int gui_mch_init_font(char_u *font_name, int fontset); -GuiFont gui_mch_get_font(char_u *name, int giveErrorIfMissing); -char_u *gui_mch_get_fontname(GuiFont font, char_u *name); -GuiFont gui_mac_find_font(char_u *font_name); -void gui_mch_set_font(GuiFont font); -int gui_mch_same_font(GuiFont f1, GuiFont f2); -void gui_mch_free_font(GuiFont font); -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); -void gui_mch_set_bg_color(guicolor_T color); -void gui_mch_set_sp_color(guicolor_T color); -void gui_mch_draw_string(int row, int col, char_u *s, int len, int flags); -int gui_mch_haskey(char_u *name); -void gui_mch_beep(void); -void gui_mch_flash(int msec); -void gui_mch_invert_rectangle(int r, int c, int nr, int nc); -void gui_mch_iconify(void); -void gui_mch_settitle(char_u *title, char_u *icon); -void gui_mch_draw_hollow_cursor(guicolor_T color); -void gui_mch_draw_part_cursor(int w, int h, guicolor_T color); -void gui_mch_update(void); -int gui_mch_wait_for_chars(int wtime); -void gui_mch_flush(void); -void gui_mch_clear_block(int row1, int col1, int row2, int col2); -void gui_mch_clear_all(void); -void gui_mch_delete_lines(int row, int num_lines); -void gui_mch_insert_lines(int row, int num_lines); -void gui_mch_enable_menu(int flag); -void gui_mch_set_menu_pos(int x, int y, int w, int h); -/*void gui_mch_add_menu(vimmenu_T *menu, vimmenu_T *parent, int idx);*/ -void gui_mch_add_menu(vimmenu_T *menu, int pos); -/*void gui_mch_add_menu_item(vimmenu_T *menu, vimmenu_T *parent, int idx);*/ -void gui_mch_add_menu_item(vimmenu_T *menu, int idx); -void gui_mch_show_popupmenu(vimmenu_T *menu); -void gui_mch_destroy_menu(vimmenu_T *menu); -void gui_mch_menu_grey(vimmenu_T *menu, int grey); -void gui_mch_menu_hidden(vimmenu_T *menu, int hidden); -void gui_mch_draw_menubar(void); -int gui_mch_get_lightness(guicolor_T pixel); -guicolor_T gui_mch_get_rgb(guicolor_T pixel); -int gui_mch_get_mouse_x(void); -int gui_mch_get_mouse_y(void); -void gui_mch_setmouse(int x, int y); -void gui_mch_show_popupmenu(vimmenu_T *menu); -int gui_mch_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton, char_u *textfield, int ex_cmd); -char_u *gui_mch_browse(int saving, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter); -void gui_mch_set_foreground(void); -void gui_mch_show_tabline(int showit); -int gui_mch_showing_tabline(void); -void gui_mch_update_tabline(void); -void gui_mch_set_curtab(int nr); - -char_u *C2Pascal_save(char_u *Cstring); -char_u *C2Pascal_save_and_remove_backslash(char_u *Cstring); -int_u EventModifiers2VimMouseModifiers(EventModifiers macModifiers); -char_u **new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error); - - -void gui_request_selection(void); -void gui_mch_lose_selection(void); -int gui_mch_own_selection(void); -void gui_mch_clear_selection(void); - -void gui_win_new_height(win_T *wp); -void gui_win_comp_pos(void); -void gui_win_free(win_T *wp); -void gui_win_alloc(win_T *wp); -void mch_post_buffer_write (buf_T *buf); - -void mch_errmsg(char *str); -void mch_display_error(void); -void clip_mch_lose_selection(Clipboard_T *cbd); -void clip_mch_request_selection(Clipboard_T *cbd); -void clip_mch_set_selection(Clipboard_T *cbd); -int clip_mch_own_selection(Clipboard_T *cbd); - -pascal OSErr FindProcessBySignature( const OSType targetType, - const OSType targetCreator, ProcessSerialNumberPtr psnPtr ); -OSErr InstallAEHandlers (void); -pascal OSErr HandleODocAE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon); -pascal OSErr Handle_aevt_oapp_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon); -pascal OSErr Handle_aevt_quit_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon); -pascal OSErr Handle_aevt_pdoc_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon); -pascal OSErr Handle_unknown_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon); -/* Shoulde we return MenuItemIndex? IMO yes, I did that for 5.7 ak*/ -short gui_mac_get_menu_item_index (vimmenu_T *pMenu); - -pascal OSErr Handle_KAHL_SRCH_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon); -pascal OSErr Handle_KAHL_MOD_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon); -pascal OSErr Handle_KAHL_GTTX_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon); -void Send_KAHL_MOD_AE (buf_T *buf); - -void gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow); -void gui_mac_doInDragClick(Point where, WindowPtr whichWindow); -void gui_mac_doInGrowClick(Point where, WindowPtr whichWindow); -void gui_mac_doUpdateEvent(EventRecord *event); -void gui_mac_doActivateEvent(EventRecord *event); -void gui_mac_doSuspendEvent(EventRecord *event); -void gui_mac_doKeyEvent(EventRecord *theEvent); -void gui_mac_doMouseDownEvent(EventRecord *theEvent); -void gui_mac_doMouseMovedEvent(EventRecord *event); -void gui_mac_doMouseUpEvent(EventRecord *theEvent); -void gui_mch_mousehide(int hide); - -int C2PascalString (char_u *CString, Str255 *PascalString); -int GetFSSpecFromPath ( char_u *file, FSSpec *fileFSSpec); -char_u *FullPathFromFSSpec_save (FSSpec file); - -/* vim: set ft=c : */ diff --git a/src/structs.h b/src/structs.h index 1eca510905..ca2002640d 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2533,9 +2533,6 @@ struct file_buffer dev_t b_dev; // device number ino_t b_ino; // inode number #endif -#ifdef FEAT_CW_EDITOR - FSSpec b_FSSpec; // MacOS File Identification -#endif #ifdef VMS char b_fab_rfm; // Record format char b_fab_rat; // Record attribute @@ -3802,15 +3799,6 @@ struct VimMenu BPictureButton *button; # endif #endif -#ifdef FEAT_GUI_MAC -// MenuHandle id; -// short index; // the item index within the father menu - short menu_id; // the menu id to which this item belongs - short submenu_id; // the menu id of the children (could be - // get through some tricks) - MenuHandle menu_handle; - MenuHandle submenu_handle; -#endif #ifdef FEAT_GUI_PHOTON PtWidget_t *id; PtWidget_t *submenu_id; diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index 37fbdc33ba..da8653eb09 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -10,24 +10,6 @@ NO_INITS = -U NONE $(NO_PLUGINS) # The first script creates small.vim. SCRIPTS_FIRST = test1.out -# Tests that run on all systems. -SCRIPTS_ALL = - -# Tests that run on most systems, but not on Amiga. -SCRIPTS_MORE1 = - -# Tests that run on most systems, but not on Amiga and DOS/Windows. -SCRIPTS_MORE2 = test49.out - -# Tests that run on most systems, but not on VMS -SCRIPTS_MORE4 = - -# Tests specifically for MS-Windows. -SCRIPTS_WIN32 = - -# Tests for the GUI. -SCRIPTS_GUI = - # Tests for Vim9 script. TEST_VIM9 = \ test_vim9_cmd \ diff --git a/src/testdir/Make_amiga.mak b/src/testdir/Make_amiga.mak index e6e55e3b4f..efd5808429 100644 --- a/src/testdir/Make_amiga.mak +++ b/src/testdir/Make_amiga.mak @@ -9,14 +9,9 @@ default: nongui include Make_all.mak -SCRIPTS = $(SCRIPTS_ALL) $(SCRIPTS_MORE4) +.SUFFIXES: .in .out .res .vim -# Must run test1 first to create small.vim. -$(SCRIPTS) $(SCRIPTS_GUI) $(NEW_TESTS_RES): $(SCRIPTS_FIRST) - -.SUFFIXES: .in .out - -nongui: /tmp $(SCRIPTS_FIRST) $(SCRIPTS) +nongui: /tmp $(SCRIPTS_FIRST) csh -c echo ALL DONE clean: diff --git a/src/testdir/Make_dos.mak b/src/testdir/Make_dos.mak index f97b3e9bb4..5931da25df 100644 --- a/src/testdir/Make_dos.mak +++ b/src/testdir/Make_dos.mak @@ -9,25 +9,20 @@ default: nongui !include Make_all.mak -# Omitted: -# test49 fails in various ways - -SCRIPTS = $(SCRIPTS_ALL) $(SCRIPTS_MORE1) $(SCRIPTS_MORE4) - -TEST_OUTFILES = $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_WIN32) $(SCRIPTS_GUI) +TEST_OUTFILES = $(SCRIPTS_FIRST) DOSTMP = dostmp DOSTMP_OUTFILES = $(TEST_OUTFILES:test=dostmp\test) DOSTMP_INFILES = $(DOSTMP_OUTFILES:.out=.in) .SUFFIXES: .in .out .res .vim -nongui: nolog $(SCRIPTS_FIRST) $(SCRIPTS) newtests report +nongui: nolog $(SCRIPTS_FIRST) newtests report small: nolog report -gui: nolog $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_GUI) newtests report +gui: nolog $(SCRIPTS_FIRST) newtests report -win32: nolog $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_WIN32) newtests report +win32: nolog $(SCRIPTS_FIRST) newtests report # Copy the input files to dostmp, changing the fileformat to dos. $(DOSTMP_INFILES): $(*B).in diff --git a/src/testdir/Make_ming.mak b/src/testdir/Make_ming.mak index e1f3467492..b34ae1d2c3 100644 --- a/src/testdir/Make_ming.mak +++ b/src/testdir/Make_ming.mak @@ -28,19 +28,17 @@ default: vimall include Make_all.mak -SCRIPTS = $(SCRIPTS_ALL) $(SCRIPTS_MORE1) $(SCRIPTS_MORE4) $(SCRIPTS_WIN32) - SCRIPTS_BENCH = test_bench_regexp.res # Must run test1 first to create small.vim. -$(SCRIPTS) $(SCRIPTS_GUI) $(SCRIPTS_WIN32) $(NEW_TESTS_RES): $(SCRIPTS_FIRST) +$(NEW_TESTS_RES): $(SCRIPTS_FIRST) .SUFFIXES: .in .out .res .vim -vimall: fixff $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_GUI) $(SCRIPTS_WIN32) newtests +vimall: fixff $(SCRIPTS_FIRST) newtests @echo ALL DONE -nongui: fixff nolog $(SCRIPTS_FIRST) $(SCRIPTS) newtests +nongui: fixff nolog $(SCRIPTS_FIRST) newtests @echo ALL DONE benchmark: $(SCRIPTS_BENCH) @@ -48,10 +46,10 @@ benchmark: $(SCRIPTS_BENCH) small: nolog @echo ALL DONE -gui: fixff nolog $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_GUI) newtests +gui: fixff nolog $(SCRIPTS_FIRST) newtests @echo ALL DONE -win32: fixff nolog $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_WIN32) newtests +win32: fixff nolog $(SCRIPTS_FIRST) newtests @echo ALL DONE # TODO: find a way to avoid changing the distributed files. @@ -88,19 +86,6 @@ test1.out: test1.in -@if exist test.out $(DEL) test.out -@if exist viminfo $(DEL) viminfo -.in.out: - -@if exist $*.ok $(CP) $*.ok test.ok - $(VIMPROG) -u dos.vim $(NO_INITS) -s dotest.in $*.in - @diff test.out $*.ok - -@if exist $*.out $(DEL) $*.out - @$(MV) test.out $*.out - -@if exist Xdir1 $(DELDIR) Xdir1 - -@if exist Xfind $(DELDIR) Xfind - -@if exist XfakeHOME $(DELDIR) XfakeHOME - -@if exist X* $(DEL) X* - -@if exist test.ok $(DEL) test.ok - -@if exist viminfo $(DEL) viminfo - nolog: -@if exist test.log $(DEL) test.log -@if exist messages $(DEL) messages diff --git a/src/testdir/Make_vms.mms b/src/testdir/Make_vms.mms index 59da981b37..f36ae6edd8 100644 --- a/src/testdir/Make_vms.mms +++ b/src/testdir/Make_vms.mms @@ -27,26 +27,6 @@ # Uncomment if you want tests in GUI mode. Terminal mode is default. # WANT_GUI = YES -# Comment out if you want to run Unix specific tests as well, but please -# be aware, that on OpenVMS will fail, because of cat, rm, etc commands -# and directory handling. -# WANT_UNIX = YES - -# Comment out if you have gzip on your system -# HAVE_GZIP = YES - -# Comment out if you have GNU compatible diff on your system -# HAVE_GDIFF = YES - -# Comment out if you have ICONV support -# HAVE_ICONV = YES - -# Comment out if you have LUA support -# HAVE_LUA = YES - -# Comment out if you have PYTHON support -# HAVE_PYTHON = YES - ####################################################################### # End of configuration section. # @@ -57,16 +37,12 @@ VIMPROG = <->vim.exe .SUFFIXES : .out .in -SCRIPT = test1.out test49.out test77a.out +SCRIPT = test1.out test77a.out .IFDEF WANT_GUI GUI_OPTION = -g .ENDIF -.IFDEF WANT_UNIX -SCRIPT_UNIX = test49.out -.ENDIF - .in.out : -@ !clean up before doing the test -@ if "''F$SEARCH("test.out.*")'" .NES. "" then delete/noconfirm/nolog test.out.* @@ -87,7 +63,7 @@ SCRIPT_UNIX = test49.out -@ if "''F$SEARCH("Xdotest.*")'" .NES. "" then delete/noconfirm/nolog Xdotest.*.* -@ if "''F$SEARCH("Xtest.*")'" .NES. "" then delete/noconfirm/nolog Xtest.*.* -all : clean nolog $(START_WITH) $(SCRIPT) $(SCRIPT_UNIX) nolog +all : clean nolog $(START_WITH) $(SCRIPT) nolog -@ write sys$output " " -@ write sys$output "-----------------------------------------------" -@ write sys$output " All done" @@ -111,12 +87,6 @@ nolog : -@ write sys$output "-----------------------------------------------" -@ write sys$output "MAKE_VMS.MMS options:" -@ write sys$output " WANT_GUI = ""$(WANT_GUI)"" " - -@ write sys$output " WANT_UNIX = ""$(WANT_UNIX)"" " - -@ write sys$output " HAVE_GZIP = ""$(HAVE_GZIP)"" " - -@ write sys$output " HAVE_GDIFF = ""$(HAVE_GDIFF)"" " - -@ write sys$output " HAVE_ICONV = ""$(HAVE_ICONV)"" " - -@ write sys$output " HAVE_LUA = ""$(HAVE_LUA)"" " - -@ write sys$output " HAVE_PYTHON= ""$(HAVE_PYTHON)"" " -@ write sys$output "Default vimrc file is VMS.VIM:" -@ write sys$output "-----------------------------------------------" -@ type VMS.VIM diff --git a/src/testdir/Makefile b/src/testdir/Makefile index 7f9ef04342..0d51fde3e1 100644 --- a/src/testdir/Makefile +++ b/src/testdir/Makefile @@ -23,28 +23,19 @@ REDIR_TEST_TO_NULL = --cmd 'au SwapExists * let v:swapchoice = "e"' > /dev/null default: nongui # The list of tests is common to all systems. -# This defines NEW_TESTS, NEW_TESTS_RES, SCRIPTS_ALL, SCRIPTS_MORE* and -# SCRIPTS_GUI. +# This defines SCRIPTS_FIRST, NEW_TESTS and NEW_TESTS_RES include Make_all.mak - -SCRIPTS = $(SCRIPTS_ALL) \ - $(SCRIPTS_MORE1) \ - $(SCRIPTS_MORE2) \ - $(SCRIPTS_MORE4) - # Explicit dependencies. -test49.out: test49.vim - test_options.res test_alot.res: opt_test.vim SCRIPTS_BENCH = test_bench_regexp.res .SUFFIXES: .in .out .res .vim -nongui: nolog $(SCRIPTS_FIRST) $(SCRIPTS) newtests report +nongui: nolog $(SCRIPTS_FIRST) newtests report -gui: nolog $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_GUI) newtests report +gui: nolog $(SCRIPTS_FIRST) newtests report benchmark: $(SCRIPTS_BENCH) @@ -63,10 +54,10 @@ report: else echo ALL DONE; \ fi" -$(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_GUI) $(NEW_TESTS_RES): $(VIMPROG) +$(SCRIPTS_FIRST) $(NEW_TESTS_RES): $(VIMPROG) # Must run test1 first to create small.vim. -$(SCRIPTS) $(SCRIPTS_GUI) $(NEW_TESTS_RES): $(SCRIPTS_FIRST) +$(NEW_TESTS_RES): $(SCRIPTS_FIRST) # Execute an individual new style test, e.g.: @@ -116,37 +107,6 @@ test1.out: test1.in echo; exit 1; fi" -rm -rf X* viminfo -.in.out: - -rm -rf $*.failed test.ok $(RM_ON_RUN) - cp $*.ok test.ok - # Sleep a moment to avoid that the xterm title is messed up. - # 200 msec is sufficient, but only modern sleep supports a fraction of - # a second, fall back to a second if it fails. - @-/bin/sh -c "sleep .2 > /dev/null 2>&1 || sleep 1" - $(RUN_VIM) $*.in $(REDIR_TEST_TO_NULL) - - # For flaky tests retry one time. No tests at the moment. - #@/bin/sh -c "if test -f test.out -a $* = test61; then \ - # if diff test.out $*.ok; \ - # then echo flaky test ok first time; \ - # else rm -rf $*.failed $(RM_ON_RUN); \ - # $(RUN_VIM) $*.in; \ - # fi \ - # fi" - - # Check if the test.out file matches test.ok. - @/bin/sh -c "if test -f test.out; then \ - if diff test.out $*.ok; \ - then mv -f test.out $*.out; \ - else echo $* FAILED >>test.log; mv -f test.out $*.failed; \ - fi \ - else echo $* NO OUTPUT >>test.log; \ - fi" - @/bin/sh -c "if test -f valgrind; then\ - mv -f valgrind valgrind.$*; \ - fi" - -rm -rf X* test.ok viminfo - nolog: -rm -f test.log messages diff --git a/src/testdir/README.txt b/src/testdir/README.txt index d639146761..8bfe47582a 100644 --- a/src/testdir/README.txt +++ b/src/testdir/README.txt @@ -4,14 +4,6 @@ For testing an indent script see runtime/indent/testdir/README.txt. If it makes sense, add a new test method to an already existing file. You may want to separate it from other tests with comment lines. -The numbered tests are older, we have switched to named tests. Don't add any -more numbered tests. - -And then you can choose between a new style test, which is a Vim script, or an -old style test, which uses Normal mode commands. Use a new style test if you -can. Use an old style test when it needs to run without the +eval feature. - - TO ADD A NEW STYLE TEST: 1) Create a test_.vim file. @@ -57,16 +49,3 @@ TO ADD A SCREEN DUMP TEST: Mostly the same as writing a new style test. Additionally, see help on "terminal-dumptest". Put the reference dump in "dumps/Test_func_name.dump". - -TO ADD AN OLD STYLE TEST: - -1) Create test_.in and test_.ok files. -2) Add test_.out to SCRIPTS_ALL in Make_all.mak in alphabetical order. -3) Use make test_.out to run a single test in src/testdir/. - Use make test_ to run a single test in src/. -4) Also add an entry in src/Makefile. - -Keep in mind that the files are used as if everything was typed: -- To add comments use: :" (that's an Ex command comment) -- A line break is like pressing Enter. If that happens on the last line - you'll hear a beep! diff --git a/src/testdir/dumps/Test_popupwin_ctrl_c.dump b/src/testdir/dumps/Test_popupwin_ctrl_c.dump new file mode 100644 index 0000000000..d6636aef40 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_ctrl_c.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@36||+1&&| +0&&@36 +|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35 +|~| @35||+1#0000000&|~+0#4040ff13&| @35 +|~| @35||+1#0000000&|~+0#4040ff13&| @35 +|~| @35||+1#0000000&|~+0#4040ff13&| @35 +|~| @35||+1#0000000&|~+0#4040ff13&| @35 +|~| @35||+1#0000000&|~+0#4040ff13&| @35 +|~| @35||+1#0000000&|~+0#4040ff13&| @35 +|[+3#0000000&|N|o| |N|a|m|e|]| @9|0|,|0|-|1| @9|A|l@1| |[+1&&|N|o| |N|a|m|e|]| @9|0|,|0|-|1| @9|A|l@1 +| +0&&@74 diff --git a/src/testdir/dumps/Test_popupwin_nospace.dump b/src/testdir/dumps/Test_popupwin_nospace.dump index 9eaacf066f..de8521c0df 100644 --- a/src/testdir/dumps/Test_popupwin_nospace.dump +++ b/src/testdir/dumps/Test_popupwin_nospace.dump @@ -3,10 +3,10 @@ |-|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|b@2|║|-+0#0000000#ffffff0@15|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@11| @14 |-|╚+0#0000001#ffd7ff255|═@2|╝|-+0#0000000#ffffff0@1|╚+0#0000001#ffd7ff255|═@2|╝|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|c@2|║|-+0#0000000#ffffff0@15|║+0#0000001#ffd7ff255|t|e@1|║|-+0#0000000#ffffff0@11| @14 |-|@|-@5|#|-@5|%|-@5|║+0#0000001#ffd7ff255|d@2|║|-+0#0000000#ffffff0@15|║+0#0000001#ffd7ff255|f|o|u|║|-+0#0000000#ffffff0@1>*|-@8| @14 -|-@14|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|e@2|║|-+0#0000000#ffffff0@15|║+0#0000001#ffd7ff255|f|i|v|║|-+0#0000000#ffffff0@1|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@4| @14 -|-@14|║+0#0000001#ffd7ff255|o|n|e|║|-+0#0000000#ffffff0@1|╚+0#0000001#ffd7ff255|═@2|╝|-+0#0000000#ffffff0@15|╚+0#0000001#ffd7ff255|═@2|╝|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|a@2|║|-+0#0000000#ffffff0@4| @14 -|-@14|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@1|*|-@5|@|-@5|#|-@5|%|-@5|║+0#0000001#ffd7ff255|b@2|║|-+0#0000000#ffffff0@4| @14 -|-@14|║+0#0000001#ffd7ff255|t|e@1|║|-+0#0000000#ffffff0@8|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@1|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|c@2|║|-+0#0000000#ffffff0@4| @14 -|-@14|╚+0#0000001#ffd7ff255|═@2|╝|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|o|n|e|║|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|o|n|e|║|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|d@2|║|-+0#0000000#ffffff0@4| @14 -|-@28|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|e@2|║|-+0#0000000#ffffff0@4| @14 -@29|╚+0#0000001#ffd7ff255|═@2|╝| +0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|t|e@1|║| +0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|f@2|║| +0#0000000#ffffff0@1|5|,|5|1| @9|T|o|p| +|-@14|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|e@2|║|-+0#0000000#ffffff0@15|║+0#0000001#ffd7ff255|f|i|v|║|-+0#0000000#ffffff0@1|╔+0#0000001#ffd7ff255|═@3|╗|-+0#0000000#ffffff0@3| @14 +|-@14|║+0#0000001#ffd7ff255|o|n|e|║|-+0#0000000#ffffff0@1|╚+0#0000001#ffd7ff255|═@2|╝|-+0#0000000#ffffff0@15|╚+0#0000001#ffd7ff255|═@2|╝|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|a@2| +0#0000000#0000001|║+0#0000001#ffd7ff255|-+0#0000000#ffffff0@3| @14 +|-@14|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@1|*|-@5|@|-@5|#|-@5|%|-@5|║+0#0000001#ffd7ff255|b@2| +0#0000000#0000001|║+0#0000001#ffd7ff255|-+0#0000000#ffffff0@3| @14 +|-@14|║+0#0000001#ffd7ff255|t|e@1|║|-+0#0000000#ffffff0@8|╔+0#0000001#ffd7ff255|═@2|╗|-+0#0000000#ffffff0@1|╔+0#0000001#ffd7ff255|═@3|╗|-+0#0000000#ffffff0@7|║+0#0000001#ffd7ff255|c@2| +0#0000000#0000001|║+0#0000001#ffd7ff255|-+0#0000000#ffffff0@3| @14 +|-@14|╚+0#0000001#ffd7ff255|═@2|╝|-+0#0000000#ffffff0@8|║+0#0000001#ffd7ff255|o|n|e|║|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|o|n|e| +0#0000000#0000001|║+0#0000001#ffd7ff255|-+0#0000000#ffffff0@7|║+0#0000001#ffd7ff255|d@2| +0#0000000#0000001|║+0#0000001#ffd7ff255|-+0#0000000#ffffff0@3| @14 +|-@28|║+0#0000001#ffd7ff255|t|w|o|║|-+0#0000000#ffffff0@1|║+0#0000001#ffd7ff255|t|w|o| +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255|-+0#0000000#ffffff0@7|║+0#0000001#ffd7ff255|e@2| +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255|-+0#0000000#ffffff0@3| @14 +@29|╚+0#0000001#ffd7ff255|═@2|╝| +0#0000000#ffffff0@1|╚+0#0000001#ffd7ff255|═@3|╝| +0#0000000#ffffff0@7|╚+0#0000001#ffd7ff255|═@3|╝| +0#0000000#ffffff0|5|,|5|1| @9|T|o|p| diff --git a/src/testdir/dumps/Test_popupwin_toohigh_3.dump b/src/testdir/dumps/Test_popupwin_toohigh_3.dump new file mode 100644 index 0000000000..8c15a40328 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_toohigh_3.dump @@ -0,0 +1,10 @@ +|1+0&#ffffff0@8>1| @64 +|2@8|╔+0#0000001#ffd7ff255|═@8|╗| +0#0000000#ffffff0@54 +|3@8|║+0#0000001#ffd7ff255|o|n|e| @4| +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@54 +|4@8|║+0#0000001#ffd7ff255|t|w|o| @4| +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@54 +|5@8|║+0#0000001#ffd7ff255|t|h|r|e@1| @2| +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@54 +|6@8|║+0#0000001#ffd7ff255|f|o|u|r| @3| +0#0000000#0000001|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@54 +|7@8|║+0#0000001#ffd7ff255|f|i|v|e| @3| +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@54 +|8@8|║+0#0000001#ffd7ff255|s|i|x| @4| +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@54 +|9@8|║+0#0000001#ffd7ff255|s|e|v|e|n| @2| +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@54 +|:|c|a|l@1| |S|h|o|╚+0#0000001#ffd7ff255|═@8|╝| +0#0000000#ffffff0@36|1|,|1|0| @9|T|o|p| diff --git a/src/testdir/test49.in b/src/testdir/test49.in deleted file mode 100644 index 79f13f6a56..0000000000 --- a/src/testdir/test49.in +++ /dev/null @@ -1,32 +0,0 @@ -This is a test of the script language. - -If after adding a new test, the test output doesn't appear properly in -test49.failed, try to add one or more "G"s at the line ending in "test.out" - -STARTTEST -:so small.vim -:se nocp nomore viminfo+=nviminfo -:lang mess C -:so test49.vim -:" Go back to this file and append the results from register r. -:buf test49.in -G"rp:/^Results/,$w! test.out -:" -:" make valgrind happy -:redir => funclist -:silent func -:redir END -:for line in split(funclist, "\n") -: let name = matchstr(line, 'function \zs[A-Z]\w*\ze(') -: if name != '' -: exe "delfunc " . name -: endif -:endfor -:for v in keys(g:) -: silent! exe "unlet " . v -:endfor -:unlet v -:qa! -ENDTEST - -Results of test49.vim: diff --git a/src/testdir/test49.ok b/src/testdir/test49.ok deleted file mode 100644 index 8ca8a564c3..0000000000 --- a/src/testdir/test49.ok +++ /dev/null @@ -1,26 +0,0 @@ -Results of test49.vim: -*** Test 59: OK (2038431743) -*** Test 60: OK (311511339) -*** Test 62: OK (286331153) -*** Test 63: OK (236978127) -*** Test 64: OK (1499645335) -*** Test 66: OK (5464) -*** Test 67: OK (212514423) -*** Test 68: OK (212514423) -*** Test 76: OK (1610087935) -*** Test 77: OK (1388671) -*** Test 78: OK (134217728) -*** Test 79: OK (70288929) -*** Test 80: OK (17895765) -*** Test 81: OK (387) -*** Test 82: OK (8454401) -*** Test 83: OK (2835) -*** Test 84: OK (934782101) -*** Test 85: OK (198689) ---- Test 86: No Crash for vimgrep on BufUnload -*** Test 86: OK (0) ---- Test 88: All tests were run with throwing exceptions on error. - The $VIMNOERRTHROW control is not configured. ---- Test 88: All tests were run with throwing exceptions on interrupt. - The $VIMNOINTTHROW control is not configured. -*** Test 88: OK (50443995) diff --git a/src/testdir/test49.vim b/src/testdir/test49.vim deleted file mode 100644 index 9ef91dffa4..0000000000 --- a/src/testdir/test49.vim +++ /dev/null @@ -1,3911 +0,0 @@ -" Vim script language tests -" Author: Servatius Brandt -" Last Change: 2020 Jun 07 - -"------------------------------------------------------------------------------- -" Test environment {{{1 -"------------------------------------------------------------------------------- - - -" Adding new tests easily. {{{2 -" -" Writing new tests is eased considerably with the following functions and -" abbreviations (see "Commands for recording the execution path", "Automatic -" argument generation"). -" -" To get the abbreviations, execute the command -" -" :let test49_set_env = 1 | source test49.vim -" -" To get them always (from src/testdir), put a line -" -" au! BufRead test49.vim let test49_set_env = 1 | source test49.vim -" -" into the local .vimrc file in the src/testdir directory. -" -if exists("test49_set_env") && test49_set_env - - " Automatic argument generation for the test environment commands. - - function! Xsum() - let addend = substitute(getline("."), '^.*"\s*X:\s*\|^.*', '', "") - " Evaluate arithmetic expression. - if addend != "" - exec "let g:Xsum = g:Xsum + " . addend - endif - endfunction - - function! Xcheck() - let g:Xsum=0 - ?XpathINIT?,.call Xsum() - exec "norm A " - return g:Xsum - endfunction - - iab Xcheck Xcheck=Xcheck()x - - function! Xcomment(num) - let str = "" - let tabwidth = &sts ? &sts : &ts - let tabs = (48+tabwidth - a:num - virtcol(".")) / tabwidth - while tabs > 0 - let str = str . "\t" - let tabs = tabs - 1 - endwhile - let str = str . '" X:' - return str - endfunction - - function! Xloop() - let back = line(".") . "|norm" . virtcol(".") . "|" - norm 0 - let last = search('X\(loop\|path\)INIT\|Xloop\>', "bW") - exec back - let theline = getline(last) - if theline =~ 'X\(loop\|path\)INIT' - let num = 1 - else - let num = 2 * substitute(theline, '.*Xloop\s*\(\d\+\).*', '\1', "") - endif - ?X\(loop\|path\)INIT? - \s/\(XloopINIT!\=\s*\d\+\s\+\)\@<=\(\d\+\)/\=2*submatch(2)/ - exec back - exec "norm a " - return num . Xcomment(strlen(num)) - endfunction - - iab Xloop Xloop=Xloop()x - - function! Xpath(loopinit) - let back = line(".") . "|norm" . virtcol(".") . "|" - norm 0 - let last = search('XpathINIT\|Xpath\>\|XloopINIT', "bW") - exec back - let theline = getline(last) - if theline =~ 'XpathINIT' - let num = 1 - elseif theline =~ 'Xpath\>' - let num = 2 * substitute(theline, '.*Xpath\s*\(\d\+\).*', '\1', "") - else - let pattern = '.*XloopINIT!\=\s*\(\d\+\)\s*\(\d\+\).*' - let num = substitute(theline, pattern, '\1', "") - let factor = substitute(theline, pattern, '\2', "") - " The "x" from the "Xpath" iab and the character triggering its - " expansion are in the input buffer. Save and clear typeahead so - " that it is not read away by the call to "input()" below. Restore - " afterwards. - call inputsave() - let loops = input("Number of iterations in previous loop? ") - call inputrestore() - while (loops > 0) - let num = num * factor - let loops = loops - 1 - endwhile - endif - exec "norm a " - if a:loopinit - return num . " 1" - endif - return num . Xcomment(strlen(num)) - endfunction - - iab Xpath Xpath=Xpath(0)x - iab XloopINIT XloopINIT=Xpath(1)x - - " Also useful (see ExtraVim below): - aug ExtraVim - au! - au BufEnter syn region ExtraVim - \ start=+^if\s\+ExtraVim(.*)+ end=+^endif+ - \ transparent keepend - au BufEnter syn match ExtraComment /^"/ - \ contained containedin=ExtraVim - au BufEnter hi link ExtraComment vimComment - aug END - - aug Xpath - au BufEnter syn keyword Xpath - \ XpathINIT Xpath XloopINIT Xloop XloopNEXT Xcheck Xout - au BufEnter hi link Xpath Special - aug END - - do BufEnter - - " Do not execute the tests when sourcing this file for getting the functions - " and abbreviations above, which are intended for easily adding new test - " cases; they are not needed for test execution. Unlet the variable - " controlling this so that an explicit ":source" command for this file will - " execute the tests. - unlet test49_set_env - finish - -endif - - -" Commands for recording the execution path. {{{2 -" -" The Xpath/Xloop commands can be used for computing the eXecution path by -" adding (different) powers of 2 from those script lines, for which the -" execution should be checked. Xloop provides different addends for each -" execution of a loop. Permitted values are 2^0 to 2^30, so that 31 execution -" points (multiply counted inside loops) can be tested. -" -" Note that the arguments of the following commands can be generated -" automatically, see below. -" -" Usage: {{{3 -" -" - Use XpathINIT at the beginning of the test. -" -" - Use Xpath to check if a line is executed. -" Argument: power of 2 (decimal). -" -" - To check multiple execution of loops use Xloop for automatically -" computing Xpath values: -" -" - Use XloopINIT before the loop. -" Two arguments: -" - the first Xpath value (power of 2) to be used (Xnext), -" - factor for computing a new Xnext value when reexecuting a loop -" (by a ":continue" or ":endwhile"); this should be 2^n where -" n is the number of Xloop commands inside the loop. -" If XloopINIT! is used, the first execution of XloopNEXT is -" a no-operation. -" -" - Use Xloop inside the loop: -" One argument: -" The argument and the Xnext value are multiplied to build the -" next Xpath value. No new Xnext value is prepared. The argument -" should be 2^(n-1) for the nth Xloop command inside the loop. -" If the loop has only one Xloop command, the argument can be -" omitted (default: 1). -" -" - Use XloopNEXT before ":continue" and ":endwhile". This computes a new -" Xnext value for the next execution of the loop by multiplying the old -" one with the factor specified in the XloopINIT command. No Argument. -" Alternatively, when XloopINIT! is used, a single XloopNEXT at the -" beginning of the loop can be used. -" -" Nested loops are not supported. -" -" - Use Xcheck at end of each test. It prints the test number, the expected -" execution path value, the test result ("OK" or "FAIL"), and, if the tests -" fails, the actual execution path. -" One argument: -" Expected Xpath/Xloop sum for the correct execution path. -" In order that this value can be computed automatically, do the -" following: For each line in the test with an Xpath and Xloop -" command, add a comment starting with "X:" and specifying an -" expression that evaluates to the value contributed by this line to -" the correct execution path. (For copying an Xpath argument of at -" least two digits into the comment, press .) At the end of the -" test, just type "Xcheck" and press . -" -" - In order to add additional information to the test output file, use the -" Xout command. Argument(s) like ":echo". -" -" Automatic argument generation: {{{3 -" -" The arguments of the Xpath, XloopINIT, Xloop, and Xcheck commands can be -" generated automatically, so that new tests can easily be written without -" mental arithmetic. The Xcheck argument is computed from the "X:" comments -" of the preceding Xpath and Xloop commands. See the commands and -" abbreviations at the beginning of this file. -" -" Implementation: {{{3 -" XpathINIT, Xpath, XloopINIT, Xloop, XloopNEXT, Xcheck, Xout. -" -" The variants for existing g:ExtraVimResult are needed when executing a script -" in an extra Vim process, see ExtraVim below. - -" EXTRA_VIM_START - do not change or remove this line. - -com! XpathINIT let g:Xpath = 0 - -if exists("g:ExtraVimResult") - com! -count -bar Xpath exec "!echo >>" . g:ExtraVimResult -else - com! -count -bar Xpath let g:Xpath = g:Xpath + -endif - -com! -count -nargs=1 -bang - \ XloopINIT let g:Xnext = | - \ let g:Xfactor = | - \ let g:Xskip = strlen("") - -if exists("g:ExtraVimResult") - com! -count=1 -bar Xloop exec "!echo " . (g:Xnext * ) . " >>" . - \ g:ExtraVimResult -else - com! -count=1 -bar Xloop let g:Xpath = g:Xpath + g:Xnext * -endif - -com! XloopNEXT let g:Xnext = g:Xnext * - \ (g:Xskip ? 1 : g:Xfactor) | - \ let g:Xskip = 0 - -let @r = "" -let Xtest = 1 -com! -count Xcheck let Xresult = "*** Test " . - \ (Xtest<10?" ":Xtest<100?" ":"") . - \ Xtest . ": " . ( - \ (Xpath==) ? "OK (".Xpath.")" : - \ "FAIL (".Xpath." instead of )" - \ ) | - \ let @R = Xresult . "\n" | - \ echo Xresult | - \ let Xtest = Xtest + 1 - -if exists("g:ExtraVimResult") - com! -nargs=+ Xoutq exec "!echo @R:'" . - \ substitute(substitute(, - \ "'", '&\\&&', "g"), "\n", "@NL@", "g") - \ . "' >>" . g:ExtraVimResult -else - com! -nargs=+ Xoutq let @R = "--- Test " . - \ (g:Xtest<10?" ":g:Xtest<100?" ":"") . - \ g:Xtest . ": " . substitute(, - \ "\n", "&\t ", "g") . "\n" -endif -com! -nargs=+ Xout exec 'Xoutq' - -" Switch off storing of lines for undoing changes. Speeds things up a little. -set undolevels=-1 - -" EXTRA_VIM_STOP - do not change or remove this line. - - -" ExtraVim() - Run a script file in an extra Vim process. {{{2 -" -" This is useful for testing immediate abortion of the script processing due to -" an error in a command dynamically enclosed by a :try/:tryend region or when an -" exception is thrown but not caught or when an interrupt occurs. It can also -" be used for testing :finish. -" -" An interrupt location can be specified by an "INTERRUPT" comment. A number -" telling how often this location is reached (in a loop or in several function -" calls) should be specified as argument. When missing, once per script -" invocation or function call is assumed. INTERRUPT locations are tested by -" setting a breakpoint in that line and using the ">quit" debug command when -" the breakpoint is reached. A function for which an INTERRUPT location is -" specified must be defined before calling it (or executing it as a script by -" using ExecAsScript below). -" -" This function is only called in normal modus ("g:ExtraVimResult" undefined). -" -" Tests to be executed as an extra script should be written as follows: -" -" column 1 column 1 -" | | -" v v -" -" XpathINIT XpathINIT -" if ExtraVim() if ExtraVim() -" ... " ... -" ... " ... -" endif endif -" Xcheck Xcheck -" -" Double quotes in column 1 are removed before the script is executed. -" They should be used if the test has unbalanced conditionals (:if/:endif, -" :while:/endwhile, :try/:endtry) or for a line with a syntax error. The -" extra script may use Xpath, XloopINIT, Xloop, XloopNEXT, and Xout as usual. -" -" A file name may be specified as argument. All messages of the extra Vim -" process are then redirected to the file. An existing file is overwritten. -" -let ExtraVimCount = 0 -let ExtraVimBase = expand("") -let ExtraVimTestEnv = "" -" -function ExtraVim(...) - " Count how often this function is called. - let g:ExtraVimCount = g:ExtraVimCount + 1 - - " Disable folds to prevent that the ranges in the ":write" commands below - " are extended up to the end of a closed fold. This also speeds things up - " considerably. - set nofoldenable - - " Open a buffer for this test script and copy the test environment to - " a temporary file. Take account of parts relevant for the extra script - " execution only. - let current_buffnr = bufnr("%") - execute "view +1" g:ExtraVimBase - if g:ExtraVimCount == 1 - let g:ExtraVimTestEnv = tempname() - execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w" - \ g:ExtraVimTestEnv "|']+" - execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w >>" - \ g:ExtraVimTestEnv "|']+" - execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w >>" - \ g:ExtraVimTestEnv "|']+" - execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w >>" - \ g:ExtraVimTestEnv "|']+" - endif - - " Start the extra Vim script with a ":source" command for the test - " environment. The source line number where the extra script will be - " appended, needs to be passed as variable "ExtraVimBegin" to the script. - let extra_script = tempname() - exec "!echo 'source " . g:ExtraVimTestEnv . "' >" . extra_script - let extra_begin = 1 - - " Starting behind the test environment, skip over the first g:ExtraVimCount - " occurrences of "if ExtraVim()" and copy the following lines up to the - " matching "endif" to the extra Vim script. - execute "/E" . "ND_OF_TEST_ENVIRONMENT/" - exec 'norm ' . g:ExtraVimCount . '/^\s*if\s\+ExtraVim(.*)/+' . "\n" - execute ".,/^endif/-write >>" . extra_script - - " Open a buffer for the extra Vim script, delete all ^", and write the - " script if was actually modified. - execute "edit +" . (extra_begin + 1) extra_script - ,$s/^"//e - update - - " Count the INTERRUPTs and build the breakpoint and quit commands. - let breakpoints = "" - let debug_quits = "" - let in_func = 0 - exec extra_begin - while search( - \ '"\s*INTERRUPT\h\@!\|^\s*fu\%[nction]\>!\=\s*\%(\u\|s:\)\w*\s*(\|' - \ . '^\s*\\\|^\s*endf\%[unction]\>\|' - \ . '\%(^\s*fu\%[nction]!\=\s*\)\@ 0 - let theline = getline(".") - if theline =~ '^\s*fu' - " Function definition. - let in_func = 1 - let func_start = line(".") - let func_name = substitute(theline, - \ '^\s*fu\%[nction]!\=\s*\(\%(\u\|s:\)\w*\).*', '\1', "") - elseif theline =~ '^\s*endf' - " End of function definition. - let in_func = 0 - else - let finding = substitute(theline, '.*\(\%' . col(".") . 'c.*\)', - \ '\1', "") - if finding =~ '^"\s*INTERRUPT\h\@!' - " Interrupt comment. Compose as many quit commands as - " specified. - let cnt = substitute(finding, - \ '^"\s*INTERRUPT\s*\(\d*\).*$', '\1', "") - let quits = "" - while cnt > 0 - " Use "\r" rather than "\n" to separate the quit commands. - " "\r" is not interpreted as command separator by the ":!" - " command below but works to separate commands in the - " external vim. - let quits = quits . "q\r" - let cnt = cnt - 1 - endwhile - if in_func - " Add the function breakpoint and note the number of quits - " to be used, if specified, or one for every call else. - let breakpoints = breakpoints . " -c 'breakadd func " . - \ (line(".") - func_start) . " " . - \ func_name . "'" - if quits != "" - let debug_quits = debug_quits . quits - elseif !exists("quits{func_name}") - let quits{func_name} = "q\r" - else - let quits{func_name} = quits{func_name} . "q\r" - endif - else - " Add the file breakpoint and the quits to be used for it. - let breakpoints = breakpoints . " -c 'breakadd file " . - \ line(".") . " " . extra_script . "'" - if quits == "" - let quits = "q\r" - endif - let debug_quits = debug_quits . quits - endif - else - " Add the quits to be used for calling the function or executing - " it as script file. - if finding =~ '^ExecAsScript' - " Sourcing function as script. - let finding = substitute(finding, - \ '^ExecAsScript\s\+\(\%(\u\|s:\)\w*\).*', '\1', "") - else - " Function call. - let finding = substitute(finding, - \ '^\(\%(\u\|s:\)\w*\).*', '\1', "") - endif - if exists("quits{finding}") - let debug_quits = debug_quits . quits{finding} - endif - endif - endif - endwhile - - " Close the buffer for the script and create an (empty) resultfile. - bwipeout - let resultfile = tempname() - exec "!>" . resultfile - - " Run the script in an extra vim. Switch to extra modus by passing the - " resultfile in ExtraVimResult. Redirect messages to the file specified as - " argument if any. Use ":debuggreedy" so that the commands provided on the - " pipe are consumed at the debug prompt. Use "-N" to enable command-line - " continuation ("C" in 'cpo'). Add "nviminfo" to 'viminfo' to avoid - " messing up the user's viminfo file. - let redirect = a:0 ? - \ " -c 'au VimLeave * redir END' -c 'redir\\! >" . a:1 . "'" : "" - exec "!echo '" . debug_quits . "q' | " .. v:progpath .. " -u NONE -N -Xes" . redirect . - \ " -c 'debuggreedy|set viminfo+=nviminfo'" . - \ " -c 'let ExtraVimBegin = " . extra_begin . "'" . - \ " -c 'let ExtraVimResult = \"" . resultfile . "\"'" . breakpoints . - \ " -S " . extra_script - - " Build the resulting sum for resultfile and add it to g:Xpath. Add Xout - " information provided by the extra Vim process to the test output. - let sum = 0 - exec "edit" resultfile - let line = 1 - while line <= line("$") - let theline = getline(line) - if theline =~ '^@R:' - exec 'Xout "' . substitute(substitute( - \ escape(escape(theline, '"'), '\"'), - \ '^@R:', '', ""), '@NL@', "\n", "g") . '"' - else - let sum = sum + getline(line) - endif - let line = line + 1 - endwhile - bwipeout - let g:Xpath = g:Xpath + sum - - " Delete the extra script and the resultfile. - call delete(extra_script) - call delete(resultfile) - - " Switch back to the buffer that was active when this function was entered. - exec "buffer" current_buffnr - - " Return 0. This protects extra scripts from being run in the main Vim - " process. - return 0 -endfunction - - -" ExtraVimThrowpoint() - Relative throwpoint in ExtraVim script {{{2 -" -" Evaluates v:throwpoint and returns the throwpoint relative to the beginning of -" an ExtraVim script as passed by ExtraVim() in ExtraVimBegin. -" -" EXTRA_VIM_START - do not change or remove this line. -function ExtraVimThrowpoint() - if !exists("g:ExtraVimBegin") - Xout "ExtraVimThrowpoint() used outside ExtraVim() script." - return v:throwpoint - endif - - if v:throwpoint =~ '^function\>' - return v:throwpoint - endif - - return "line " . - \ (substitute(v:throwpoint, '.*, line ', '', "") - g:ExtraVimBegin) . - \ " of ExtraVim() script" -endfunction -" EXTRA_VIM_STOP - do not change or remove this line. - - -" MakeScript() - Make a script file from a function. {{{2 -" -" Create a script that consists of the body of the function a:funcname. -" Replace any ":return" by a ":finish", any argument variable by a global -" variable, and every ":call" by a ":source" for the next following argument -" in the variable argument list. This function is useful if similar tests are -" to be made for a ":return" from a function call or a ":finish" in a script -" file. -" -" In order to execute a function specifying an INTERRUPT location (see ExtraVim) -" as a script file, use ExecAsScript below. -" -" EXTRA_VIM_START - do not change or remove this line. -function MakeScript(funcname, ...) - let script = tempname() - execute "redir! >" . script - execute "function" a:funcname - redir END - execute "edit" script - " Delete the "function" and the "endfunction" lines. Do not include the - " word "function" in the pattern since it might be translated if LANG is - " set. When MakeScript() is being debugged, this deletes also the debugging - " output of its line 3 and 4. - exec '1,/.*' . a:funcname . '(.*)/d' - /^\d*\s*endfunction\>/,$d - %s/^\d*//e - %s/return/finish/e - %s/\ 0 - let cnt = cnt + 1 - s/\" . bplist - breaklist - redir END - execute "edit" bplist - " Get the line number from the function breakpoint. Works also when - " LANG is set. - execute 'v/^\s*\d\+\s\+func\s\+' . a:funcname . '\s.*/d' - %s/^\s*\d\+\s\+func\s\+\%(\u\|s:\)\w*\s\D*\(\d*\).*/\1/e - let cnt = 0 - while cnt < line("$") - let cnt = cnt + 1 - if getline(cnt) != "" - execute "breakadd file" getline(cnt) script - endif - endwhile - bwipeout! - call delete(bplist) - endif - - " Source and delete the script. - exec "source" script - call delete(script) -endfunction - -com! -nargs=1 -bar ExecAsScript call ExecAsScript() -" EXTRA_VIM_STOP - do not change or remove this line. - - -" END_OF_TEST_ENVIRONMENT - do not change or remove this line. - -function! MESSAGES(...) - try - exec "edit" g:msgfile - catch /^Vim(edit):/ - return 0 - endtry - - let english = v:lang == "C" || v:lang =~ '^[Ee]n' - let match = 1 - norm gg - - let num = a:0 / 2 - let cnt = 1 - while cnt <= num - let enr = a:{2*cnt - 1} - let emsg= a:{2*cnt} - let cnt = cnt + 1 - - if enr == "" - Xout "TODO: Add message number for:" emsg - elseif enr == "INT" - let enr = "" - endif - if enr == "" && !english - continue - endif - let pattern = (enr != "") ? enr . ':.*' : '' - if english - let pattern = pattern . emsg - endif - if !search(pattern, "W") - let match = 0 - Xout "No match for:" pattern - endif - norm $ - endwhile - - bwipeout! - return match -endfunction - -" Leave MESSAGES() for the next tests. - -" Tests 1 to 50, 52 to 57, 87 were moved to test_vimscript.vim -" Tests 25, 26, 32, 33, 41-48, 51, 69-75 were moved to test_trycatch.vim -let Xtest = 59 - -"------------------------------------------------------------------------------- -" -" Test 59: v:exception and v:throwpoint when discarding exceptions {{{1 -" -" When a :catch clause is left by a ":break" etc or an error or -" interrupt exception, v:exception and v:throwpoint are reset. They -" are not affected by an exception that is discarded before being -" caught. -"------------------------------------------------------------------------------- - -XpathINIT - -if ExtraVim() - - XloopINIT! 1 2 - - let sfile = expand("") - - function! LineNumber() - return substitute(substitute(v:throwpoint, g:sfile, '', ""), - \ '\D*\(\d*\).*', '\1', "") - endfunction - - command! -nargs=1 SetLineNumber - \ try | throw "line" | catch /.*/ | let = LineNumber() | endtry - - " Check v:exception/v:throwpoint against second/fourth parameter if - " specified, check for being empty else. - function! CHECK(n, ...) - XloopNEXT - let exception = a:0 != 0 ? a:1 : "" " second parameter (optional) - let emsg = a:0 != 0 ? a:2 : "" " third parameter (optional) - let line = a:0 != 0 ? a:3 : 0 " fourth parameter (optional) - let error = 0 - if emsg != "" - " exception is the error number, emsg the English error message text - if exception !~ '^E\d\+$' - Xout "TODO: Add message number for:" emsg - elseif v:lang == "C" || v:lang =~ '^[Ee]n' - if exception == "E492" && emsg == "Not an editor command" - let exception = '^Vim:' . exception . ': ' . emsg - else - let exception = '^Vim(\a\+):' . exception . ': ' . emsg - endif - else - if exception == "E492" - let exception = '^Vim:' . exception - else - let exception = '^Vim(\a\+):' . exception - endif - endif - endif - if exception == "" && v:exception != "" - Xout a:n.": v:exception is set:" v:exception - let error = 1 - elseif exception != "" && v:exception !~ exception - Xout a:n.": v:exception (".v:exception.") does not match" exception - let error = 1 - endif - if line == 0 && v:throwpoint != "" - Xout a:n.": v:throwpoint is set:" v:throwpoint - let error = 1 - elseif line != 0 && v:throwpoint !~ '\<' . line . '\>' - Xout a:n.": v:throwpoint (".v:throwpoint.") does not match" line - let error = 1 - endif - if !error - Xloop 1 " X: 2097151 - endif - endfunction - - while 1 - try - throw "x1" - catch /.*/ - break - endtry - endwhile - call CHECK(1) - - while 1 - try - throw "x2" - catch /.*/ - break - finally - call CHECK(2) - endtry - break - endwhile - call CHECK(3) - - while 1 - try - let errcaught = 0 - try - try - throw "x3" - catch /.*/ - SetLineNumber line_before_error - asdf - endtry - catch /.*/ - let errcaught = 1 - call CHECK(4, 'E492', "Not an editor command", - \ line_before_error + 1) - endtry - finally - if !errcaught && $VIMNOERRTHROW - call CHECK(4) - endif - break " discard error for $VIMNOERRTHROW - endtry - endwhile - call CHECK(5) - - Xpath 2097152 " X: 2097152 - - while 1 - try - let intcaught = 0 - try - try - throw "x4" - catch /.*/ - SetLineNumber two_lines_before_interrupt - "INTERRUPT - let dummy = 0 - endtry - catch /.*/ - let intcaught = 1 - call CHECK(6, "Vim:Interrupt", '', - \ two_lines_before_interrupt + 2) - endtry - finally - if !intcaught && $VIMNOINTTHROW - call CHECK(6) - endif - break " discard interrupt for $VIMNOINTTHROW - endtry - endwhile - call CHECK(7) - - Xpath 4194304 " X: 4194304 - - while 1 - try - let errcaught = 0 - try - try -" if 1 - SetLineNumber line_before_throw - throw "x5" - " missing endif - catch /.*/ - Xpath 8388608 " X: 0 - endtry - catch /.*/ - let errcaught = 1 - call CHECK(8, 'E171', "Missing :endif", line_before_throw + 3) - endtry - finally - if !errcaught && $VIMNOERRTHROW - call CHECK(8) - endif - break " discard error for $VIMNOERRTHROW - endtry - endwhile - call CHECK(9) - - Xpath 16777216 " X: 16777216 - - try - while 1 - try - throw "x6" - finally - break - endtry - break - endwhile - catch /.*/ - Xpath 33554432 " X: 0 - endtry - call CHECK(10) - - try - while 1 - try - throw "x7" - finally - break - endtry - break - endwhile - catch /.*/ - Xpath 67108864 " X: 0 - finally - call CHECK(11) - endtry - call CHECK(12) - - while 1 - try - let errcaught = 0 - try - try - throw "x8" - finally - SetLineNumber line_before_error - asdf - endtry - catch /.*/ - let errcaught = 1 - call CHECK(13, 'E492', "Not an editor command", - \ line_before_error + 1) - endtry - finally - if !errcaught && $VIMNOERRTHROW - call CHECK(13) - endif - break " discard error for $VIMNOERRTHROW - endtry - endwhile - call CHECK(14) - - Xpath 134217728 " X: 134217728 - - while 1 - try - let intcaught = 0 - try - try - throw "x9" - finally - SetLineNumber two_lines_before_interrupt - "INTERRUPT - endtry - catch /.*/ - let intcaught = 1 - call CHECK(15, "Vim:Interrupt", '', - \ two_lines_before_interrupt + 2) - endtry - finally - if !intcaught && $VIMNOINTTHROW - call CHECK(15) - endif - break " discard interrupt for $VIMNOINTTHROW - endtry - endwhile - call CHECK(16) - - Xpath 268435456 " X: 268435456 - - while 1 - try - let errcaught = 0 - try - try -" if 1 - SetLineNumber line_before_throw - throw "x10" - " missing endif - finally - call CHECK(17) - endtry - catch /.*/ - let errcaught = 1 - call CHECK(18, 'E171', "Missing :endif", line_before_throw + 3) - endtry - finally - if !errcaught && $VIMNOERRTHROW - call CHECK(18) - endif - break " discard error for $VIMNOERRTHROW - endtry - endwhile - call CHECK(19) - - Xpath 536870912 " X: 536870912 - - while 1 - try - let errcaught = 0 - try - try -" if 1 - SetLineNumber line_before_throw - throw "x11" - " missing endif - endtry - catch /.*/ - let errcaught = 1 - call CHECK(20, 'E171', "Missing :endif", line_before_throw + 3) - endtry - finally - if !errcaught && $VIMNOERRTHROW - call CHECK(20) - endif - break " discard error for $VIMNOERRTHROW - endtry - endwhile - call CHECK(21) - - Xpath 1073741824 " X: 1073741824 - -endif - -Xcheck 2038431743 - - -"------------------------------------------------------------------------------- -" -" Test 60: (Re)throwing v:exception; :echoerr. {{{1 -" -" A user exception can be rethrown after catching by throwing -" v:exception. An error or interrupt exception cannot be rethrown -" because Vim exceptions cannot be faked. A Vim exception using the -" value of v:exception can, however, be triggered by the :echoerr -" command. -"------------------------------------------------------------------------------- - -XpathINIT - -try - try - Xpath 1 " X: 1 - throw "oops" - catch /oops/ - Xpath 2 " X: 2 - throw v:exception " rethrow user exception - catch /.*/ - Xpath 4 " X: 0 - endtry -catch /^oops$/ " catches rethrown user exception - Xpath 8 " X: 8 -catch /.*/ - Xpath 16 " X: 0 -endtry - -function! F() - try - let caught = 0 - try - Xpath 32 " X: 32 - write /n/o/n/w/r/i/t/a/b/l/e/_/f/i/l/e - Xpath 64 " X: 0 - Xout "did_emsg was reset before executing " . - \ "BufWritePost autocommands." - catch /^Vim(write):/ - let caught = 1 - throw v:exception " throw error: cannot fake Vim exception - catch /.*/ - Xpath 128 " X: 0 - finally - Xpath 256 " X: 256 - if !caught && !$VIMNOERRTHROW - Xpath 512 " X: 0 - endif - endtry - catch /^Vim(throw):/ " catches throw error - let caught = caught + 1 - catch /.*/ - Xpath 1024 " X: 0 - finally - Xpath 2048 " X: 2048 - if caught != 2 - if !caught && !$VIMNOERRTHROW - Xpath 4096 " X: 0 - elseif caught - Xpath 8192 " X: 0 - endif - return | " discard error for $VIMNOERRTHROW - endif - endtry -endfunction - -call F() -delfunction F - -function! G() - try - let caught = 0 - try - Xpath 16384 " X: 16384 - asdf - catch /^Vim/ " catch error exception - let caught = 1 - " Trigger Vim error exception with value specified after :echoerr - let value = substitute(v:exception, '^Vim\((.*)\)\=:', '', "") - echoerr value - catch /.*/ - Xpath 32768 " X: 0 - finally - Xpath 65536 " X: 65536 - if !caught - if !$VIMNOERRTHROW - Xpath 131072 " X: 0 - else - let value = "Error" - echoerr value - endif - endif - endtry - catch /^Vim(echoerr):/ - let caught = caught + 1 - if v:exception !~ value - Xpath 262144 " X: 0 - endif - catch /.*/ - Xpath 524288 " X: 0 - finally - Xpath 1048576 " X: 1048576 - if caught != 2 - if !caught && !$VIMNOERRTHROW - Xpath 2097152 " X: 0 - elseif caught - Xpath 4194304 " X: 0 - endif - return | " discard error for $VIMNOERRTHROW - endif - endtry -endfunction - -call G() -delfunction G - -unlet! value caught - -if ExtraVim() - try - let errcaught = 0 - try - Xpath 8388608 " X: 8388608 - let intcaught = 0 - "INTERRUPT - catch /^Vim:/ " catch interrupt exception - let intcaught = 1 - " Trigger Vim error exception with value specified after :echoerr - echoerr substitute(v:exception, '^Vim\((.*)\)\=:', '', "") - catch /.*/ - Xpath 16777216 " X: 0 - finally - Xpath 33554432 " X: 33554432 - if !intcaught - if !$VIMNOINTTHROW - Xpath 67108864 " X: 0 - else - echoerr "Interrupt" - endif - endif - endtry - catch /^Vim(echoerr):/ - let errcaught = 1 - if v:exception !~ "Interrupt" - Xpath 134217728 " X: 0 - endif - finally - Xpath 268435456 " X: 268435456 - if !errcaught && !$VIMNOERRTHROW - Xpath 536870912 " X: 0 - endif - endtry -endif - -Xcheck 311511339 - -" Test 61 was moved to test_vimscript.vim -let Xtest = 62 - -"------------------------------------------------------------------------------- -" Test 62: Catching error exceptions {{{1 -" -" An error inside a :try/:endtry region is converted to an exception -" and can be caught. The error exception has a "Vim(cmdname):" prefix -" where cmdname is the name of the failing command, or a "Vim:" prefix -" if no command name is known. The "Vim" prefixes cannot be faked. -"------------------------------------------------------------------------------- - -XpathINIT - -function! MSG(enr, emsg) - let english = v:lang == "C" || v:lang =~ '^[Ee]n' - if a:enr == "" - Xout "TODO: Add message number for:" a:emsg - let v:errmsg = ":" . v:errmsg - endif - let match = 1 - if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg) - let match = 0 - if v:errmsg == "" - Xout "Message missing." - else - let v:errmsg = escape(v:errmsg, '"') - Xout "Unexpected message:" v:errmsg - endif - endif - return match -endfunction - -while 1 - try - try - let caught = 0 - unlet novar - catch /^Vim(unlet):/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim(unlet):', '', "") - finally - Xpath 1 " X: 1 - if !caught && !$VIMNOERRTHROW - Xpath 2 " X: 0 - endif - if !MSG('E108', "No such variable") - Xpath 4 " X: 0 - endif - endtry - catch /.*/ - Xpath 8 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -while 1 - try - try - let caught = 0 - throw novar " error in :throw - catch /^Vim(throw):/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "") - finally - Xpath 16 " X: 16 - if !caught && !$VIMNOERRTHROW - Xpath 32 " X: 0 - endif - if caught ? !MSG('E121', "Undefined variable") - \ : !MSG('E15', "Invalid expression") - Xpath 64 " X: 0 - endif - endtry - catch /.*/ - Xpath 128 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -while 1 - try - try - let caught = 0 - throw "Vim:faked" " error: cannot fake Vim exception - catch /^Vim(throw):/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "") - finally - Xpath 256 " X: 256 - if !caught && !$VIMNOERRTHROW - Xpath 512 " X: 0 - endif - if !MSG('E608', "Cannot :throw exceptions with 'Vim' prefix") - Xpath 1024 " X: 0 - endif - endtry - catch /.*/ - Xpath 2048 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -function! F() - while 1 - " Missing :endwhile -endfunction - -while 1 - try - try - let caught = 0 - call F() - catch /^Vim(endfunction):/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim(endfunction):', '', "") - finally - Xpath 4096 " X: 4096 - if !caught && !$VIMNOERRTHROW - Xpath 8192 " X: 0 - endif - if !MSG('E170', "Missing :endwhile") - Xpath 16384 " X: 0 - endif - endtry - catch /.*/ - Xpath 32768 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -while 1 - try - try - let caught = 0 - ExecAsScript F - catch /^Vim:/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim:', '', "") - finally - Xpath 65536 " X: 65536 - if !caught && !$VIMNOERRTHROW - Xpath 131072 " X: 0 - endif - if !MSG('E170', "Missing :endwhile") - Xpath 262144 " X: 0 - endif - endtry - catch /.*/ - Xpath 524288 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -function! G() - call G() -endfunction - -while 1 - try - let mfd_save = &mfd - set mfd=3 - try - let caught = 0 - call G() - catch /^Vim(call):/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim(call):', '', "") - finally - Xpath 1048576 " X: 1048576 - if !caught && !$VIMNOERRTHROW - Xpath 2097152 " X: 0 - endif - if !MSG('E132', "Function call depth is higher than 'maxfuncdepth'") - Xpath 4194304 " X: 0 - endif - endtry - catch /.*/ - Xpath 8388608 " X: 0 - Xout v:exception "in" v:throwpoint - finally - let &mfd = mfd_save - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -function! H() - return H() -endfunction - -while 1 - try - let mfd_save = &mfd - set mfd=3 - try - let caught = 0 - call H() - catch /^Vim(return):/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim(return):', '', "") - finally - Xpath 16777216 " X: 16777216 - if !caught && !$VIMNOERRTHROW - Xpath 33554432 " X: 0 - endif - if !MSG('E132', "Function call depth is higher than 'maxfuncdepth'") - Xpath 67108864 " X: 0 - endif - endtry - catch /.*/ - Xpath 134217728 " X: 0 - Xout v:exception "in" v:throwpoint - finally - let &mfd = mfd_save - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -unlet! caught mfd_save -delfunction F -delfunction G -delfunction H -Xpath 268435456 " X: 268435456 - -Xcheck 286331153 - -" Leave MSG() for the next test. - - -"------------------------------------------------------------------------------- -" Test 63: Suppressing error exceptions by :silent!. {{{1 -" -" A :silent! command inside a :try/:endtry region suppresses the -" conversion of errors to an exception and the immediate abortion on -" error. When the commands executed by the :silent! themselves open -" a new :try/:endtry region, conversion of errors to exception and -" immediate abortion is switched on again - until the next :silent! -" etc. The :silent! has the effect of setting v:errmsg to the error -" message text (without displaying it) and continuing with the next -" script line. -" -" When a command triggering autocommands is executed by :silent! -" inside a :try/:endtry, the autocommand execution is not suppressed -" on error. -" -" This test reuses the function MSG() from the previous test. -"------------------------------------------------------------------------------- - -XpathINIT - -XloopINIT! 1 4 - -let taken = "" - -function! S(n) abort - XloopNEXT - let g:taken = g:taken . "E" . a:n - let v:errmsg = "" - exec "asdf" . a:n - - " Check that ":silent!" continues: - Xloop 1 - - " Check that ":silent!" sets "v:errmsg": - if MSG('E492', "Not an editor command") - Xloop 2 - endif -endfunction - -function! Foo() - while 1 - try - try - let caught = 0 - " This is not silent: - call S(3) " X: 0 * 16 - catch /^Vim:/ - let caught = 1 - let errmsg3 = substitute(v:exception, '^Vim:', '', "") - silent! call S(4) " X: 3 * 64 - finally - if !caught - let errmsg3 = v:errmsg - " Do call S(4) here if not executed in :catch. - silent! call S(4) - endif - Xpath 1048576 " X: 1048576 - if !caught && !$VIMNOERRTHROW - Xpath 2097152 " X: 0 - endif - let v:errmsg = errmsg3 - if !MSG('E492', "Not an editor command") - Xpath 4194304 " X: 0 - endif - silent! call S(5) " X: 3 * 256 - " Break out of try conditionals that cover ":silent!". This also - " discards the aborting error when $VIMNOERRTHROW is non-zero. - break - endtry - catch /.*/ - Xpath 8388608 " X: 0 - Xout v:exception "in" v:throwpoint - endtry - endwhile - " This is a double ":silent!" (see caller). - silent! call S(6) " X: 3 * 1024 -endfunction - -function! Bar() - try - silent! call S(2) " X: 3 * 4 - " X: 3 * 4096 - silent! execute "call Foo() | call S(7)" - silent! call S(8) " X: 3 * 16384 - endtry " normal end of try cond that covers ":silent!" - " This has a ":silent!" from the caller: - call S(9) " X: 3 * 65536 -endfunction - -silent! call S(1) " X: 3 * 1 -silent! call Bar() -silent! call S(10) " X: 3 * 262144 - -let expected = "E1E2E3E4E5E6E7E8E9E10" -if taken != expected - Xpath 16777216 " X: 0 - Xout "'taken' is" taken "instead of" expected -endif - -augroup TMP - autocmd BufWritePost * Xpath 33554432 " X: 33554432 -augroup END - -Xpath 67108864 " X: 67108864 -write /i/m/p/o/s/s/i/b/l/e -Xpath 134217728 " X: 134217728 - -autocmd! TMP -unlet! caught errmsg3 taken expected -delfunction S -delfunction Foo -delfunction Bar -delfunction MSG - -Xcheck 236978127 - - -"------------------------------------------------------------------------------- -" Test 64: Error exceptions after error, interrupt or :throw {{{1 -" -" When an error occurs after an interrupt or a :throw but before -" a matching :catch is reached, all following :catches of that try -" block are ignored, but the error exception can be caught by the next -" surrounding try conditional. Any previous error exception is -" discarded. An error is ignored when there is a previous error that -" has not been caught. -"------------------------------------------------------------------------------- - -XpathINIT - -if ExtraVim() - - while 1 - try - try - Xpath 1 " X: 1 - let caught = 0 - while 1 -" if 1 - " Missing :endif - endwhile " throw error exception - catch /^Vim(/ - let caught = 1 - finally - Xpath 2 " X: 2 - if caught || $VIMNOERRTHROW - Xpath 4 " X: 4 - endif - endtry - catch /.*/ - Xpath 8 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry - endwhile - - while 1 - try - try - Xpath 16 " X: 16 - let caught = 0 - try -" if 1 - " Missing :endif - catch /.*/ " throw error exception - Xpath 32 " X: 0 - catch /.*/ - Xpath 64 " X: 0 - endtry - catch /^Vim(/ - let caught = 1 - finally - Xpath 128 " X: 128 - if caught || $VIMNOERRTHROW - Xpath 256 " X: 256 - endif - endtry - catch /.*/ - Xpath 512 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry - endwhile - - while 1 - try - try - let caught = 0 - try - Xpath 1024 " X: 1024 - "INTERRUPT - catch /do_not_catch/ - Xpath 2048 " X: 0 -" if 1 - " Missing :endif - catch /.*/ " throw error exception - Xpath 4096 " X: 0 - catch /.*/ - Xpath 8192 " X: 0 - endtry - catch /^Vim(/ - let caught = 1 - finally - Xpath 16384 " X: 16384 - if caught || $VIMNOERRTHROW - Xpath 32768 " X: 32768 - endif - endtry - catch /.*/ - Xpath 65536 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry - endwhile - - while 1 - try - try - let caught = 0 - try - Xpath 131072 " X: 131072 - throw "x" - catch /do_not_catch/ - Xpath 262144 " X: 0 -" if 1 - " Missing :endif - catch /x/ " throw error exception - Xpath 524288 " X: 0 - catch /.*/ - Xpath 1048576 " X: 0 - endtry - catch /^Vim(/ - let caught = 1 - finally - Xpath 2097152 " X: 2097152 - if caught || $VIMNOERRTHROW - Xpath 4194304 " X: 4194304 - endif - endtry - catch /.*/ - Xpath 8388608 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry - endwhile - - while 1 - try - try - let caught = 0 - Xpath 16777216 " X: 16777216 -" endif " :endif without :if; throw error exception -" if 1 - " Missing :endif - catch /do_not_catch/ " ignore new error - Xpath 33554432 " X: 0 - catch /^Vim(endif):/ - let caught = 1 - catch /^Vim(/ - Xpath 67108864 " X: 0 - finally - Xpath 134217728 " X: 134217728 - if caught || $VIMNOERRTHROW - Xpath 268435456 " X: 268435456 - endif - endtry - catch /.*/ - Xpath 536870912 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry - endwhile - - Xpath 1073741824 " X: 1073741824 - -endif - -Xcheck 1499645335 - -" Test 65 was moved to test_vimscript.vim -let Xtest = 66 - -"------------------------------------------------------------------------------- -" Test 66: Stop range :call on error, interrupt, or :throw {{{1 -" -" When a function which is multiply called for a range since it -" doesn't handle the range itself has an error in a command -" dynamically enclosed by :try/:endtry or gets an interrupt or -" executes a :throw, no more calls for the remaining lines in the -" range are made. On an error in a command not dynamically enclosed -" by :try/:endtry, the function is executed again for the remaining -" lines in the range. -"------------------------------------------------------------------------------- - -XpathINIT - -if ExtraVim() - - let file = tempname() - exec "edit" file - - insert -line 1 -line 2 -line 3 -. - - XloopINIT! 1 2 - - let taken = "" - let expected = "G1EF1E(1)F1E(2)F1E(3)G2EF2E(1)G3IF3I(1)G4TF4T(1)G5AF5A(1)" - - function! F(reason, n) abort - let g:taken = g:taken . "F" . a:n . - \ substitute(a:reason, '\(\l\).*', '\u\1', "") . - \ "(" . line(".") . ")" - - if a:reason == "error" - asdf - elseif a:reason == "interrupt" - "INTERRUPT - let dummy = 0 - elseif a:reason == "throw" - throw "xyz" - elseif a:reason == "aborting error" - XloopNEXT - if g:taken != g:expected - Xloop 1 " X: 0 - Xout "'taken' is" g:taken "instead of" g:expected - endif - try - bwipeout! - call delete(file) - asdf - endtry - endif - endfunction - - function! G(reason, n) - let g:taken = g:taken . "G" . a:n . - \ substitute(a:reason, '\(\l\).*', '\u\1', "") - 1,3call F(a:reason, a:n) - endfunction - - Xpath 8 " X: 8 - call G("error", 1) - try - Xpath 16 " X: 16 - try - call G("error", 2) - Xpath 32 " X: 0 - finally - Xpath 64 " X: 64 - try - call G("interrupt", 3) - Xpath 128 " X: 0 - finally - Xpath 256 " X: 256 - try - call G("throw", 4) - Xpath 512 " X: 0 - endtry - endtry - endtry - catch /xyz/ - Xpath 1024 " X: 1024 - catch /.*/ - Xpath 2048 " X: 0 - Xout v:exception "in" ExtraVimThrowpoint() - endtry - Xpath 4096 " X: 4096 - call G("aborting error", 5) - Xpath 8192 " X: 0 - Xout "'taken' is" taken "instead of" expected - -endif - -Xcheck 5464 - - -"------------------------------------------------------------------------------- -" Test 67: :throw across :call command {{{1 -" -" On a call command, an exception might be thrown when evaluating the -" function name, during evaluation of the arguments, or when the -" function is being executed. The exception can be caught by the -" caller. -"------------------------------------------------------------------------------- - -XpathINIT - -function! THROW(x, n) - if a:n == 1 - Xpath 1 " X: 1 - elseif a:n == 2 - Xpath 2 " X: 2 - elseif a:n == 3 - Xpath 4 " X: 4 - endif - throw a:x -endfunction - -function! NAME(x, n) - if a:n == 1 - Xpath 8 " X: 0 - elseif a:n == 2 - Xpath 16 " X: 16 - elseif a:n == 3 - Xpath 32 " X: 32 - elseif a:n == 4 - Xpath 64 " X: 64 - endif - return a:x -endfunction - -function! ARG(x, n) - if a:n == 1 - Xpath 128 " X: 0 - elseif a:n == 2 - Xpath 256 " X: 0 - elseif a:n == 3 - Xpath 512 " X: 512 - elseif a:n == 4 - Xpath 1024 " X: 1024 - endif - return a:x -endfunction - -function! F(x, n) - if a:n == 2 - Xpath 2048 " X: 0 - elseif a:n == 4 - Xpath 4096 " X: 4096 - endif -endfunction - -while 1 - try - let error = 0 - let v:errmsg = "" - - while 1 - try - Xpath 8192 " X: 8192 - call {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1) - Xpath 16384 " X: 0 - catch /^name$/ - Xpath 32768 " X: 32768 - catch /.*/ - let error = 1 - Xout "1:" v:exception "in" v:throwpoint - finally - if !error && $VIMNOERRTHROW && v:errmsg != "" - let error = 1 - Xout "1:" v:errmsg - endif - if error - Xpath 65536 " X: 0 - endif - let error = 0 - let v:errmsg = "" - break " discard error for $VIMNOERRTHROW - endtry - endwhile - - while 1 - try - Xpath 131072 " X: 131072 - call {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2) - Xpath 262144 " X: 0 - catch /^arg$/ - Xpath 524288 " X: 524288 - catch /.*/ - let error = 1 - Xout "2:" v:exception "in" v:throwpoint - finally - if !error && $VIMNOERRTHROW && v:errmsg != "" - let error = 1 - Xout "2:" v:errmsg - endif - if error - Xpath 1048576 " X: 0 - endif - let error = 0 - let v:errmsg = "" - break " discard error for $VIMNOERRTHROW - endtry - endwhile - - while 1 - try - Xpath 2097152 " X: 2097152 - call {NAME("THROW", 3)}(ARG("call", 3), 3) - Xpath 4194304 " X: 0 - catch /^call$/ - Xpath 8388608 " X: 8388608 - catch /^0$/ " default return value - Xpath 16777216 " X: 0 - Xout "3:" v:throwpoint - catch /.*/ - let error = 1 - Xout "3:" v:exception "in" v:throwpoint - finally - if !error && $VIMNOERRTHROW && v:errmsg != "" - let error = 1 - Xout "3:" v:errmsg - endif - if error - Xpath 33554432 " X: 0 - endif - let error = 0 - let v:errmsg = "" - break " discard error for $VIMNOERRTHROW - endtry - endwhile - - while 1 - try - Xpath 67108864 " X: 67108864 - call {NAME("F", 4)}(ARG(4711, 4), 4) - Xpath 134217728 " X: 134217728 - catch /.*/ - let error = 1 - Xout "4:" v:exception "in" v:throwpoint - finally - if !error && $VIMNOERRTHROW && v:errmsg != "" - let error = 1 - Xout "4:" v:errmsg - endif - if error - Xpath 268435456 " X: 0 - endif - let error = 0 - let v:errmsg = "" - break " discard error for $VIMNOERRTHROW - endtry - endwhile - - catch /^0$/ " default return value - Xpath 536870912 " X: 0 - Xout v:throwpoint - catch /.*/ - let error = 1 - Xout v:exception "in" v:throwpoint - finally - if !error && $VIMNOERRTHROW && v:errmsg != "" - let error = 1 - Xout v:errmsg - endif - if error - Xpath 1073741824 " X: 0 - endif - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -unlet error -delfunction F - -Xcheck 212514423 - -" Leave THROW(), NAME(), and ARG() for the next test. - - -"------------------------------------------------------------------------------- -" Test 68: :throw across function calls in expressions {{{1 -" -" On a function call within an expression, an exception might be -" thrown when evaluating the function name, during evaluation of the -" arguments, or when the function is being executed. The exception -" can be caught by the caller. -" -" This test reuses the functions THROW(), NAME(), and ARG() from the -" previous test. -"------------------------------------------------------------------------------- - -XpathINIT - -function! F(x, n) - if a:n == 2 - Xpath 2048 " X: 0 - elseif a:n == 4 - Xpath 4096 " X: 4096 - endif - return a:x -endfunction - -unlet! var1 var2 var3 var4 - -while 1 - try - let error = 0 - let v:errmsg = "" - - while 1 - try - Xpath 8192 " X: 8192 - let var1 = {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1) - Xpath 16384 " X: 0 - catch /^name$/ - Xpath 32768 " X: 32768 - catch /.*/ - let error = 1 - Xout "1:" v:exception "in" v:throwpoint - finally - if !error && $VIMNOERRTHROW && v:errmsg != "" - let error = 1 - Xout "1:" v:errmsg - endif - if error - Xpath 65536 " X: 0 - endif - let error = 0 - let v:errmsg = "" - break " discard error for $VIMNOERRTHROW - endtry - endwhile - - while 1 - try - Xpath 131072 " X: 131072 - let var2 = {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2) - Xpath 262144 " X: 0 - catch /^arg$/ - Xpath 524288 " X: 524288 - catch /.*/ - let error = 1 - Xout "2:" v:exception "in" v:throwpoint - finally - if !error && $VIMNOERRTHROW && v:errmsg != "" - let error = 1 - Xout "2:" v:errmsg - endif - if error - Xpath 1048576 " X: 0 - endif - let error = 0 - let v:errmsg = "" - break " discard error for $VIMNOERRTHROW - endtry - endwhile - - while 1 - try - Xpath 2097152 " X: 2097152 - let var3 = {NAME("THROW", 3)}(ARG("call", 3), 3) - Xpath 4194304 " X: 0 - catch /^call$/ - Xpath 8388608 " X: 8388608 - catch /^0$/ " default return value - Xpath 16777216 " X: 0 - Xout "3:" v:throwpoint - catch /.*/ - let error = 1 - Xout "3:" v:exception "in" v:throwpoint - finally - if !error && $VIMNOERRTHROW && v:errmsg != "" - let error = 1 - Xout "3:" v:errmsg - endif - if error - Xpath 33554432 " X: 0 - endif - let error = 0 - let v:errmsg = "" - break " discard error for $VIMNOERRTHROW - endtry - endwhile - - while 1 - try - Xpath 67108864 " X: 67108864 - let var4 = {NAME("F", 4)}(ARG(4711, 4), 4) - Xpath 134217728 " X: 134217728 - catch /.*/ - let error = 1 - Xout "4:" v:exception "in" v:throwpoint - finally - if !error && $VIMNOERRTHROW && v:errmsg != "" - let error = 1 - Xout "4:" v:errmsg - endif - if error - Xpath 268435456 " X: 0 - endif - let error = 0 - let v:errmsg = "" - break " discard error for $VIMNOERRTHROW - endtry - endwhile - - catch /^0$/ " default return value - Xpath 536870912 " X: 0 - Xout v:throwpoint - catch /.*/ - let error = 1 - Xout v:exception "in" v:throwpoint - finally - if !error && $VIMNOERRTHROW && v:errmsg != "" - let error = 1 - Xout v:errmsg - endif - if error - Xpath 1073741824 " X: 0 - endif - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -if exists("var1") || exists("var2") || exists("var3") || - \ !exists("var4") || var4 != 4711 - " The Xpath command does not accept 2^31 (negative); add explicitly: - let Xpath = Xpath + 2147483648 " X: 0 - if exists("var1") - Xout "var1 =" var1 - endif - if exists("var2") - Xout "var2 =" var2 - endif - if exists("var3") - Xout "var3 =" var3 - endif - if !exists("var4") - Xout "var4 unset" - elseif var4 != 4711 - Xout "var4 =" var4 - endif -endif - -unlet! error var1 var2 var3 var4 -delfunction THROW -delfunction NAME -delfunction ARG -delfunction F - -Xcheck 212514423 - -" Tests 69 to 75 were moved to test_trycatch.vim -let Xtest = 76 - - -"------------------------------------------------------------------------------- -" Test 76: Errors, interrupts, :throw during expression evaluation {{{1 -" -" When a function call made during expression evaluation is aborted -" due to an error inside a :try/:endtry region or due to an interrupt -" or a :throw, the expression evaluation is aborted as well. No -" message is displayed for the cancelled expression evaluation. On an -" error not inside :try/:endtry, the expression evaluation continues. -"------------------------------------------------------------------------------- - -XpathINIT - -if ExtraVim() - - let taken = "" - - function! ERR(n) - let g:taken = g:taken . "E" . a:n - asdf - endfunction - - function! ERRabort(n) abort - let g:taken = g:taken . "A" . a:n - asdf - endfunction " returns -1; may cause follow-up msg for illegal var/func name - - function! WRAP(n, arg) - let g:taken = g:taken . "W" . a:n - let g:saved_errmsg = v:errmsg - return arg - endfunction - - function! INT(n) - let g:taken = g:taken . "I" . a:n - "INTERRUPT9 - let dummy = 0 - endfunction - - function! THR(n) - let g:taken = g:taken . "T" . a:n - throw "should not be caught" - endfunction - - function! CONT(n) - let g:taken = g:taken . "C" . a:n - endfunction - - function! MSG(n) - let g:taken = g:taken . "M" . a:n - let errmsg = (a:n >= 37 && a:n <= 44) ? g:saved_errmsg : v:errmsg - let msgptn = (a:n >= 10 && a:n <= 27) ? "^$" : "asdf" - if errmsg !~ msgptn - let g:taken = g:taken . "x" - Xout "Expr" a:n.": Unexpected message:" v:errmsg - endif - let v:errmsg = "" - let g:saved_errmsg = "" - endfunction - - let v:errmsg = "" - - try - let t = 1 - XloopINIT 1 2 - while t <= 9 - Xloop 1 " X: 511 - try - if t == 1 - let v{ERR(t) + CONT(t)} = 0 - elseif t == 2 - let v{ERR(t) + CONT(t)} - elseif t == 3 - let var = exists('v{ERR(t) + CONT(t)}') - elseif t == 4 - unlet v{ERR(t) + CONT(t)} - elseif t == 5 - function F{ERR(t) + CONT(t)}() - endfunction - elseif t == 6 - function F{ERR(t) + CONT(t)} - elseif t == 7 - let var = exists('*F{ERR(t) + CONT(t)}') - elseif t == 8 - delfunction F{ERR(t) + CONT(t)} - elseif t == 9 - let var = ERR(t) + CONT(t) - endif - catch /asdf/ - " v:errmsg is not set when the error message is converted to an - " exception. Set it to the original error message. - let v:errmsg = substitute(v:exception, '^Vim:', '', "") - catch /^Vim\((\a\+)\)\=:/ - " An error exception has been thrown after the original error. - let v:errmsg = "" - finally - call MSG(t) - let t = t + 1 - XloopNEXT - continue " discard an aborting error - endtry - endwhile - catch /.*/ - Xpath 512 " X: 0 - Xout v:exception "in" ExtraVimThrowpoint() - endtry - - try - let t = 10 - XloopINIT 1024 2 - while t <= 18 - Xloop 1 " X: 1024 * 511 - try - if t == 10 - let v{INT(t) + CONT(t)} = 0 - elseif t == 11 - let v{INT(t) + CONT(t)} - elseif t == 12 - let var = exists('v{INT(t) + CONT(t)}') - elseif t == 13 - unlet v{INT(t) + CONT(t)} - elseif t == 14 - function F{INT(t) + CONT(t)}() - endfunction - elseif t == 15 - function F{INT(t) + CONT(t)} - elseif t == 16 - let var = exists('*F{INT(t) + CONT(t)}') - elseif t == 17 - delfunction F{INT(t) + CONT(t)} - elseif t == 18 - let var = INT(t) + CONT(t) - endif - catch /^Vim\((\a\+)\)\=:\(Interrupt\)\@!/ - " An error exception has been triggered after the interrupt. - let v:errmsg = substitute(v:exception, - \ '^Vim\((\a\+)\)\=:', '', "") - finally - call MSG(t) - let t = t + 1 - XloopNEXT - continue " discard interrupt - endtry - endwhile - catch /.*/ - Xpath 524288 " X: 0 - Xout v:exception "in" ExtraVimThrowpoint() - endtry - - try - let t = 19 - XloopINIT 1048576 2 - while t <= 27 - Xloop 1 " X: 1048576 * 511 - try - if t == 19 - let v{THR(t) + CONT(t)} = 0 - elseif t == 20 - let v{THR(t) + CONT(t)} - elseif t == 21 - let var = exists('v{THR(t) + CONT(t)}') - elseif t == 22 - unlet v{THR(t) + CONT(t)} - elseif t == 23 - function F{THR(t) + CONT(t)}() - endfunction - elseif t == 24 - function F{THR(t) + CONT(t)} - elseif t == 25 - let var = exists('*F{THR(t) + CONT(t)}') - elseif t == 26 - delfunction F{THR(t) + CONT(t)} - elseif t == 27 - let var = THR(t) + CONT(t) - endif - catch /^Vim\((\a\+)\)\=:/ - " An error exception has been triggered after the :throw. - let v:errmsg = substitute(v:exception, - \ '^Vim\((\a\+)\)\=:', '', "") - finally - call MSG(t) - let t = t + 1 - XloopNEXT - continue " discard exception - endtry - endwhile - catch /.*/ - Xpath 536870912 " X: 0 - Xout v:exception "in" ExtraVimThrowpoint() - endtry - - let v{ERR(28) + CONT(28)} = 0 - call MSG(28) - let v{ERR(29) + CONT(29)} - call MSG(29) - let var = exists('v{ERR(30) + CONT(30)}') - call MSG(30) - unlet v{ERR(31) + CONT(31)} - call MSG(31) - function F{ERR(32) + CONT(32)}() - endfunction - call MSG(32) - function F{ERR(33) + CONT(33)} - call MSG(33) - let var = exists('*F{ERR(34) + CONT(34)}') - call MSG(34) - delfunction F{ERR(35) + CONT(35)} - call MSG(35) - let var = ERR(36) + CONT(36) - call MSG(36) - - let saved_errmsg = "" - - let v{WRAP(37, ERRabort(37)) + CONT(37)} = 0 - call MSG(37) - let v{WRAP(38, ERRabort(38)) + CONT(38)} - call MSG(38) - let var = exists('v{WRAP(39, ERRabort(39)) + CONT(39)}') - call MSG(39) - unlet v{WRAP(40, ERRabort(40)) + CONT(40)} - call MSG(40) - function F{WRAP(41, ERRabort(41)) + CONT(41)}() - endfunction - call MSG(41) - function F{WRAP(42, ERRabort(42)) + CONT(42)} - call MSG(42) - let var = exists('*F{WRAP(43, ERRabort(43)) + CONT(43)}') - call MSG(43) - delfunction F{WRAP(44, ERRabort(44)) + CONT(44)} - call MSG(44) - let var = ERRabort(45) + CONT(45) - call MSG(45) - - Xpath 1073741824 " X: 1073741824 - - let expected = "" - \ . "E1M1E2M2E3M3E4M4E5M5E6M6E7M7E8M8E9M9" - \ . "I10M10I11M11I12M12I13M13I14M14I15M15I16M16I17M17I18M18" - \ . "T19M19T20M20T21M21T22M22T23M23T24M24T25M25T26M26T27M27" - \ . "E28C28M28E29C29M29E30C30M30E31C31M31E32C32M32E33C33M33" - \ . "E34C34M34E35C35M35E36C36M36" - \ . "A37W37C37M37A38W38C38M38A39W39C39M39A40W40C40M40A41W41C41M41" - \ . "A42W42C42M42A43W43C43M43A44W44C44M44A45C45M45" - - if taken != expected - " The Xpath command does not accept 2^31 (negative); display explicitly: - exec "!echo 2147483648 >>" . g:ExtraVimResult - " X: 0 - Xout "'taken' is" taken "instead of" expected - if substitute(taken, - \ '\(.*\)E3C3M3x\(.*\)E30C30M30x\(.*\)A39C39M39x\(.*\)', - \ '\1E3M3\2E30C30M30\3A39C39M39\4', - \ "") == expected - Xout "Is ++emsg_skip for var with expr_start non-NULL" - \ "in f_exists ok?" - endif - endif - - unlet! v var saved_errmsg taken expected - call delete(WA_t5) - call delete(WA_t14) - call delete(WA_t23) - unlet! WA_t5 WA_t14 WA_t23 - delfunction WA_t5 - delfunction WA_t14 - delfunction WA_t23 - -endif - -Xcheck 1610087935 - - -"------------------------------------------------------------------------------- -" Test 77: Errors, interrupts, :throw in name{brace-expression} {{{1 -" -" When a function call made during evaluation of an expression in -" braces as part of a function name after ":function" is aborted due -" to an error inside a :try/:endtry region or due to an interrupt or -" a :throw, the expression evaluation is aborted as well, and the -" function definition is ignored, skipping all commands to the -" ":endfunction". On an error not inside :try/:endtry, the expression -" evaluation continues and the function gets defined, and can be -" called and deleted. -"------------------------------------------------------------------------------- - -XpathINIT - -XloopINIT 1 4 - -function! ERR() abort - Xloop 1 " X: 1 + 4 + 16 + 64 - asdf -endfunction " returns -1 - -function! OK() - Xloop 2 " X: 2 * (1 + 4 + 16) - let v:errmsg = "" - return 0 -endfunction - -let v:errmsg = "" - -Xpath 4096 " X: 4096 -function! F{1 + ERR() + OK()}(arg) - " F0 should be defined. - if exists("a:arg") && a:arg == "calling" - Xpath 8192 " X: 8192 - else - Xpath 16384 " X: 0 - endif -endfunction -if v:errmsg != "" - Xpath 32768 " X: 0 -endif -XloopNEXT - -Xpath 65536 " X: 65536 -call F{1 + ERR() + OK()}("calling") -if v:errmsg != "" - Xpath 131072 " X: 0 -endif -XloopNEXT - -Xpath 262144 " X: 262144 -delfunction F{1 + ERR() + OK()} -if v:errmsg != "" - Xpath 524288 " X: 0 -endif -XloopNEXT - -try - while 1 - let caught = 0 - try - Xpath 1048576 " X: 1048576 - function! G{1 + ERR() + OK()}(arg) - " G0 should not be defined, and the function body should be - " skipped. - if exists("a:arg") && a:arg == "calling" - Xpath 2097152 " X: 0 - else - Xpath 4194304 " X: 0 - endif - " Use an unmatched ":finally" to check whether the body is - " skipped when an error occurs in ERR(). This works whether or - " not the exception is converted to an exception. - finally - Xpath 8388608 " X: 0 - Xout "Body of G{1 + ERR() + OK()}() not skipped" - " Discard the aborting error or exception, and break the - " while loop. - break - " End the try conditional and start a new one to avoid - " ":catch after :finally" errors. - endtry - try - Xpath 16777216 " X: 0 - endfunction - - " When the function was not defined, this won't be reached - whether - " the body was skipped or not. When the function was defined, it - " can be called and deleted here. - Xpath 33554432 " X: 0 - Xout "G0() has been defined" - XloopNEXT - try - call G{1 + ERR() + OK()}("calling") - catch /.*/ - Xpath 67108864 " X: 0 - endtry - Xpath 134217728 " X: 0 - XloopNEXT - try - delfunction G{1 + ERR() + OK()} - catch /.*/ - Xpath 268435456 " X: 0 - endtry - catch /asdf/ - " Jumped to when the function is not defined and the body is - " skipped. - let caught = 1 - catch /.*/ - Xpath 536870912 " X: 0 - finally - if !caught && !$VIMNOERRTHROW - Xpath 1073741824 " X: 0 - endif - break " discard error for $VIMNOERRTHROW - endtry " jumped to when the body is not skipped - endwhile -catch /.*/ - " The Xpath command does not accept 2^31 (negative); add explicitly: - let Xpath = Xpath + 2147483648 " X: 0 - Xout "Body of G{1 + ERR() + OK()}() not skipped, exception caught" - Xout v:exception "in" v:throwpoint -endtry - -Xcheck 1388671 - - -"------------------------------------------------------------------------------- -" Test 78: Messages on parsing errors in expression evaluation {{{1 -" -" When an expression evaluation detects a parsing error, an error -" message is given and converted to an exception, and the expression -" evaluation is aborted. -"------------------------------------------------------------------------------- - -XpathINIT - -if ExtraVim() - - let taken = "" - - function! F(n) - let g:taken = g:taken . "F" . a:n - endfunction - - function! MSG(n, enr, emsg) - let g:taken = g:taken . "M" . a:n - let english = v:lang == "C" || v:lang =~ '^[Ee]n' - if a:enr == "" - Xout "TODO: Add message number for:" a:emsg - let v:errmsg = ":" . v:errmsg - endif - if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg) - if v:errmsg == "" - Xout "Expr" a:n.": Message missing." - let g:taken = g:taken . "x" - else - let v:errmsg = escape(v:errmsg, '"') - Xout "Expr" a:n.": Unexpected message:" v:errmsg - Xout "Expected: " . a:enr . ': ' . a:emsg - let g:taken = g:taken . "X" - endif - endif - endfunction - - function! CONT(n) - let g:taken = g:taken . "C" . a:n - endfunction - - let v:errmsg = "" - XloopINIT 1 2 - - try - let t = 1 - while t <= 14 - let g:taken = g:taken . "T" . t - let v:errmsg = "" - try - let caught = 0 - if t == 1 - let v{novar + CONT(t)} = 0 - elseif t == 2 - let v{novar + CONT(t)} - elseif t == 3 - let var = exists('v{novar + CONT(t)}') - elseif t == 4 - unlet v{novar + CONT(t)} - elseif t == 5 - function F{novar + CONT(t)}() - endfunction - elseif t == 6 - function F{novar + CONT(t)} - elseif t == 7 - let var = exists('*F{novar + CONT(t)}') - elseif t == 8 - delfunction F{novar + CONT(t)} - elseif t == 9 - echo novar + CONT(t) - elseif t == 10 - echo v{novar + CONT(t)} - elseif t == 11 - echo F{novar + CONT(t)} - elseif t == 12 - let var = novar + CONT(t) - elseif t == 13 - let var = v{novar + CONT(t)} - elseif t == 14 - let var = F{novar + CONT(t)}() - endif - catch /^Vim\((\a\+)\)\=:/ - " v:errmsg is not set when the error message is converted to an - " exception. Set it to the original error message. - let v:errmsg = substitute(v:exception, - \ '^Vim\((\a\+)\)\=:', '', "") - let caught = 1 - finally - if t <= 8 && t != 3 && t != 7 - call MSG(t, 'E475', 'Invalid argument\>') - else - if !caught " no error exceptions ($VIMNOERRTHROW set) - call MSG(t, 'E15', "Invalid expression") - else - call MSG(t, 'E121', "Undefined variable") - endif - endif - let t = t + 1 - XloopNEXT - continue " discard an aborting error - endtry - endwhile - catch /.*/ - Xloop 1 " X: 0 - Xout t.":" v:exception "in" ExtraVimThrowpoint() - endtry - - function! T(n, expr, enr, emsg) - try - let g:taken = g:taken . "T" . a:n - let v:errmsg = "" - try - let caught = 0 - execute "let var = " . a:expr - catch /^Vim\((\a\+)\)\=:/ - " v:errmsg is not set when the error message is converted to an - " exception. Set it to the original error message. - let v:errmsg = substitute(v:exception, - \ '^Vim\((\a\+)\)\=:', '', "") - let caught = 1 - finally - if !caught " no error exceptions ($VIMNOERRTHROW set) - call MSG(a:n, 'E15', "Invalid expression") - else - call MSG(a:n, a:enr, a:emsg) - endif - XloopNEXT - " Discard an aborting error: - return - endtry - catch /.*/ - Xloop 1 " X: 0 - Xout a:n.":" v:exception "in" ExtraVimThrowpoint() - endtry - endfunction - - call T(15, 'Nofunc() + CONT(15)', 'E117', "Unknown function") - call T(16, 'F(1 2 + CONT(16))', 'E116', "Invalid arguments") - call T(17, 'F(1, 2) + CONT(17)', 'E118', "Too many arguments") - call T(18, 'F() + CONT(18)', 'E119', "Not enough arguments") - call T(19, '{(1} + CONT(19)', 'E110', "Missing ')'") - call T(20, '("abc"[1) + CONT(20)', 'E111', "Missing ']'") - call T(21, '(1 +) + CONT(21)', 'E15', "Invalid expression") - call T(22, '1 2 + CONT(22)', 'E15', "Invalid expression") - call T(23, '(1 ? 2) + CONT(23)', 'E109', "Missing ':' after '?'") - call T(24, '("abc) + CONT(24)', 'E114', "Missing quote") - call T(25, "('abc) + CONT(25)", 'E115', "Missing quote") - call T(26, '& + CONT(26)', 'E112', "Option name missing") - call T(27, '&asdf + CONT(27)', 'E113', "Unknown option") - - Xpath 134217728 " X: 134217728 - - let expected = "" - \ . "T1M1T2M2T3M3T4M4T5M5T6M6T7M7T8M8T9M9T10M10T11M11T12M12T13M13T14M14" - \ . "T15M15T16M16T17M17T18M18T19M19T20M20T21M21T22M22T23M23T24M24T25M25" - \ . "T26M26T27M27" - - if taken != expected - Xpath 268435456 " X: 0 - Xout "'taken' is" taken "instead of" expected - if substitute(taken, '\(.*\)T3M3x\(.*\)', '\1T3M3\2', "") == expected - Xout "Is ++emsg_skip for var with expr_start non-NULL" - \ "in f_exists ok?" - endif - endif - - unlet! var caught taken expected - call delete(WA_t5) - unlet! WA_t5 - delfunction WA_t5 - -endif - -Xcheck 134217728 - - -"------------------------------------------------------------------------------- -" Test 79: Throwing one of several errors for the same command {{{1 -" -" When several errors appear in a row (for instance during expression -" evaluation), the first as the most specific one is used when -" throwing an error exception. If, however, a syntax error is -" detected afterwards, this one is used for the error exception. -" On a syntax error, the next command is not executed, on a normal -" error, however, it is (relevant only in a function without the -" "abort" flag). v:errmsg is not set. -" -" If throwing error exceptions is configured off, v:errmsg is always -" set to the latest error message, that is, to the more general -" message or the syntax error, respectively. -"------------------------------------------------------------------------------- - -XpathINIT - -XloopINIT 1 2 - -function! NEXT(cmd) - exec a:cmd . " | Xloop 1" -endfunction - -call NEXT('echo novar') " X: 1 * 1 (checks nextcmd) -XloopNEXT -call NEXT('let novar #') " X: 0 * 2 (skips nextcmd) -XloopNEXT -call NEXT('unlet novar #') " X: 0 * 4 (skips nextcmd) -XloopNEXT -call NEXT('let {novar}') " X: 0 * 8 (skips nextcmd) -XloopNEXT -call NEXT('unlet{ novar}') " X: 0 * 16 (skips nextcmd) - -function! EXEC(cmd) - exec a:cmd -endfunction - -function! MATCH(expected, msg, enr, emsg) - let msg = a:msg - if a:enr == "" - Xout "TODO: Add message number for:" a:emsg - let msg = ":" . msg - endif - let english = v:lang == "C" || v:lang =~ '^[Ee]n' - if msg !~ '^'.a:enr.':' || (english && msg !~ a:emsg) - let match = 0 - if a:expected " no match although expected - if a:msg == "" - Xout "Message missing." - else - let msg = escape(msg, '"') - Xout "Unexpected message:" msg - Xout "Expected:" a:enr . ": " . a:emsg - endif - endif - else - let match = 1 - if !a:expected " match although not expected - let msg = escape(msg, '"') - Xout "Unexpected message:" msg - Xout "Expected none." - endif - endif - return match -endfunction - -try - - while 1 " dummy loop - try - let v:errmsg = "" - let caught = 0 - let thrmsg = "" - call EXEC('echo novar') " normal error - catch /^Vim\((\a\+)\)\=:/ - let caught = 1 - let thrmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") - finally - Xpath 32 " X: 32 - if !caught - if !$VIMNOERRTHROW - Xpath 64 " X: 0 - endif - elseif !MATCH(1, thrmsg, 'E121', "Undefined variable") - \ || v:errmsg != "" - Xpath 128 " X: 0 - endif - if !caught && !MATCH(1, v:errmsg, 'E15', "Invalid expression") - Xpath 256 " X: 0 - endif - break " discard error if $VIMNOERRTHROW == 1 - endtry - endwhile - - Xpath 512 " X: 512 - let cmd = "let" - XloopINIT 1024 32 - while cmd != "" - try - let v:errmsg = "" - let caught = 0 - let thrmsg = "" - call EXEC(cmd . ' novar #') " normal plus syntax error - catch /^Vim\((\a\+)\)\=:/ - let caught = 1 - let thrmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") - finally - Xloop 1 " X: 1024 * (1 + 32) - if !caught - if !$VIMNOERRTHROW - Xloop 2 " X: 0 - endif - else - if cmd == "let" - let match = MATCH(0, thrmsg, 'E121', "Undefined variable") - elseif cmd == "unlet" - let match = MATCH(0, thrmsg, 'E108', "No such variable") - endif - if match " normal error - Xloop 4 " X: 0 - endif - if !MATCH(1, thrmsg, 'E488', "Trailing characters") - \|| v:errmsg != "" - " syntax error - Xloop 8 " X: 0 - endif - endif - if !caught && !MATCH(1, v:errmsg, 'E488', "Trailing characters") - " last error - Xloop 16 " X: 0 - endif - if cmd == "let" - let cmd = "unlet" - else - let cmd = "" - endif - XloopNEXT - continue " discard error if $VIMNOERRTHROW == 1 - endtry - endwhile - - Xpath 1048576 " X: 1048576 - let cmd = "let" - XloopINIT 2097152 32 - while cmd != "" - try - let v:errmsg = "" - let caught = 0 - let thrmsg = "" - call EXEC(cmd . ' {novar}') " normal plus syntax error - catch /^Vim\((\a\+)\)\=:/ - let caught = 1 - let thrmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") - finally - Xloop 1 " X: 2097152 * (1 + 32) - if !caught - if !$VIMNOERRTHROW - Xloop 2 " X: 0 - endif - else - if MATCH(0, thrmsg, 'E121', "Undefined variable") " normal error - Xloop 4 " X: 0 - endif - if !MATCH(1, thrmsg, 'E475', 'Invalid argument\>') - \ || v:errmsg != "" " syntax error - Xloop 8 " X: 0 - endif - endif - if !caught && !MATCH(1, v:errmsg, 'E475', 'Invalid argument\>') - " last error - Xloop 16 " X: 0 - endif - if cmd == "let" - let cmd = "unlet" - else - let cmd = "" - endif - XloopNEXT - continue " discard error if $VIMNOERRTHROW == 1 - endtry - endwhile - -catch /.*/ - " The Xpath command does not accept 2^31 (negative); add explicitly: - let Xpath = Xpath + 2147483648 " X: 0 - Xout v:exception "in" v:throwpoint -endtry - -unlet! next_command thrmsg match -delfunction NEXT -delfunction EXEC -delfunction MATCH - -Xcheck 70288929 - - -"------------------------------------------------------------------------------- -" Test 80: Syntax error in expression for illegal :elseif {{{1 -" -" If there is a syntax error in the expression after an illegal -" :elseif, an error message is given (or an error exception thrown) -" for the illegal :elseif rather than the expression error. -"------------------------------------------------------------------------------- - -XpathINIT - -function! MSG(enr, emsg) - let english = v:lang == "C" || v:lang =~ '^[Ee]n' - if a:enr == "" - Xout "TODO: Add message number for:" a:emsg - let v:errmsg = ":" . v:errmsg - endif - let match = 1 - if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg) - let match = 0 - if v:errmsg == "" - Xout "Message missing." - else - let v:errmsg = escape(v:errmsg, '"') - Xout "Unexpected message:" v:errmsg - endif - endif - return match -endfunction - -let v:errmsg = "" -if 0 -else -elseif 1 ||| 2 -endif -Xpath 1 " X: 1 -if !MSG('E584', ":elseif after :else") - Xpath 2 " X: 0 -endif - -let v:errmsg = "" -if 1 -else -elseif 1 ||| 2 -endif -Xpath 4 " X: 4 -if !MSG('E584', ":elseif after :else") - Xpath 8 " X: 0 -endif - -let v:errmsg = "" -elseif 1 ||| 2 -Xpath 16 " X: 16 -if !MSG('E582', ":elseif without :if") - Xpath 32 " X: 0 -endif - -let v:errmsg = "" -while 1 - elseif 1 ||| 2 -endwhile -Xpath 64 " X: 64 -if !MSG('E582', ":elseif without :if") - Xpath 128 " X: 0 -endif - -while 1 - try - try - let v:errmsg = "" - let caught = 0 - if 0 - else - elseif 1 ||| 2 - endif - catch /^Vim\((\a\+)\)\=:/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") - finally - Xpath 256 " X: 256 - if !caught && !$VIMNOERRTHROW - Xpath 512 " X: 0 - endif - if !MSG('E584', ":elseif after :else") - Xpath 1024 " X: 0 - endif - endtry - catch /.*/ - Xpath 2048 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -while 1 - try - try - let v:errmsg = "" - let caught = 0 - if 1 - else - elseif 1 ||| 2 - endif - catch /^Vim\((\a\+)\)\=:/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") - finally - Xpath 4096 " X: 4096 - if !caught && !$VIMNOERRTHROW - Xpath 8192 " X: 0 - endif - if !MSG('E584', ":elseif after :else") - Xpath 16384 " X: 0 - endif - endtry - catch /.*/ - Xpath 32768 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -while 1 - try - try - let v:errmsg = "" - let caught = 0 - elseif 1 ||| 2 - catch /^Vim\((\a\+)\)\=:/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") - finally - Xpath 65536 " X: 65536 - if !caught && !$VIMNOERRTHROW - Xpath 131072 " X: 0 - endif - if !MSG('E582', ":elseif without :if") - Xpath 262144 " X: 0 - endif - endtry - catch /.*/ - Xpath 524288 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -while 1 - try - try - let v:errmsg = "" - let caught = 0 - while 1 - elseif 1 ||| 2 - endwhile - catch /^Vim\((\a\+)\)\=:/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") - finally - Xpath 1048576 " X: 1048576 - if !caught && !$VIMNOERRTHROW - Xpath 2097152 " X: 0 - endif - if !MSG('E582', ":elseif without :if") - Xpath 4194304 " X: 0 - endif - endtry - catch /.*/ - Xpath 8388608 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -Xpath 16777216 " X: 16777216 - -unlet! caught -delfunction MSG - -Xcheck 17895765 - - -"------------------------------------------------------------------------------- -" Test 81: Discarding exceptions after an error or interrupt {{{1 -" -" When an exception is thrown from inside a :try conditional without -" :catch and :finally clauses and an error or interrupt occurs before -" the :endtry is reached, the exception is discarded. -"------------------------------------------------------------------------------- - -XpathINIT - -if ExtraVim() - try - Xpath 1 " X: 1 - try - Xpath 2 " X: 2 - throw "arrgh" - Xpath 4 " X: 0 -" if 1 - Xpath 8 " X: 0 - " error after :throw: missing :endif - endtry - Xpath 16 " X: 0 - catch /arrgh/ - Xpath 32 " X: 0 - endtry - Xpath 64 " X: 0 -endif - -if ExtraVim() - try - Xpath 128 " X: 128 - try - Xpath 256 " X: 256 - throw "arrgh" - Xpath 512 " X: 0 - endtry " INTERRUPT - Xpath 1024 " X: 0 - catch /arrgh/ - Xpath 2048 " X: 0 - endtry - Xpath 4096 " X: 0 -endif - -Xcheck 387 - - -"------------------------------------------------------------------------------- -" Test 82: Ignoring :catch clauses after an error or interrupt {{{1 -" -" When an exception is thrown and an error or interrupt occurs before -" the matching :catch clause is reached, the exception is discarded -" and the :catch clause is ignored (also for the error or interrupt -" exception being thrown then). -"------------------------------------------------------------------------------- - -XpathINIT - -if ExtraVim() - try - try - Xpath 1 " X: 1 - throw "arrgh" - Xpath 2 " X: 0 -" if 1 - Xpath 4 " X: 0 - " error after :throw: missing :endif - catch /.*/ - Xpath 8 " X: 0 - Xout v:exception "in" ExtraVimThrowpoint() - catch /.*/ - Xpath 16 " X: 0 - Xout v:exception "in" ExtraVimThrowpoint() - endtry - Xpath 32 " X: 0 - catch /arrgh/ - Xpath 64 " X: 0 - endtry - Xpath 128 " X: 0 -endif - -if ExtraVim() - function! E() - try - try - Xpath 256 " X: 256 - throw "arrgh" - Xpath 512 " X: 0 -" if 1 - Xpath 1024 " X: 0 - " error after :throw: missing :endif - catch /.*/ - Xpath 2048 " X: 0 - Xout v:exception "in" ExtraVimThrowpoint() - catch /.*/ - Xpath 4096 " X: 0 - Xout v:exception "in" ExtraVimThrowpoint() - endtry - Xpath 8192 " X: 0 - catch /arrgh/ - Xpath 16384 " X: 0 - endtry - endfunction - - call E() - Xpath 32768 " X: 0 -endif - -if ExtraVim() - try - try - Xpath 65536 " X: 65536 - throw "arrgh" - Xpath 131072 " X: 0 - catch /.*/ "INTERRUPT - Xpath 262144 " X: 0 - Xout v:exception "in" ExtraVimThrowpoint() - catch /.*/ - Xpath 524288 " X: 0 - Xout v:exception "in" ExtraVimThrowpoint() - endtry - Xpath 1048576 " X: 0 - catch /arrgh/ - Xpath 2097152 " X: 0 - endtry - Xpath 4194304 " X: 0 -endif - -if ExtraVim() - function I() - try - try - Xpath 8388608 " X: 8388608 - throw "arrgh" - Xpath 16777216 " X: 0 - catch /.*/ "INTERRUPT - Xpath 33554432 " X: 0 - Xout v:exception "in" ExtraVimThrowpoint() - catch /.*/ - Xpath 67108864 " X: 0 - Xout v:exception "in" ExtraVimThrowpoint() - endtry - Xpath 134217728 " X: 0 - catch /arrgh/ - Xpath 268435456 " X: 0 - endtry - endfunction - - call I() - Xpath 536870912 " X: 0 -endif - -Xcheck 8454401 - - -"------------------------------------------------------------------------------- -" Test 83: Executing :finally clauses after an error or interrupt {{{1 -" -" When an exception is thrown and an error or interrupt occurs before -" the :finally of the innermost :try is reached, the exception is -" discarded and the :finally clause is executed. -"------------------------------------------------------------------------------- - -XpathINIT - -if ExtraVim() - try - Xpath 1 " X: 1 - try - Xpath 2 " X: 2 - throw "arrgh" - Xpath 4 " X: 0 -" if 1 - Xpath 8 " X: 0 - " error after :throw: missing :endif - finally - Xpath 16 " X: 16 - endtry - Xpath 32 " X: 0 - catch /arrgh/ - Xpath 64 " X: 0 - endtry - Xpath 128 " X: 0 -endif - -if ExtraVim() - try - Xpath 256 " X: 256 - try - Xpath 512 " X: 512 - throw "arrgh" - Xpath 1024 " X: 0 - finally "INTERRUPT - Xpath 2048 " X: 2048 - endtry - Xpath 4096 " X: 0 - catch /arrgh/ - Xpath 8192 " X: 0 - endtry - Xpath 16384 " X: 0 -endif - -Xcheck 2835 - - -"------------------------------------------------------------------------------- -" Test 84: Exceptions in autocommand sequences. {{{1 -" -" When an exception occurs in a sequence of autocommands for -" a specific event, the rest of the sequence is not executed. The -" command that triggered the autocommand execution aborts, and the -" exception is propagated to the caller. -" -" For the FuncUndefined event under a function call expression or -" :call command, the function is not executed, even when it has -" been defined by the autocommands before the exception occurred. -"------------------------------------------------------------------------------- - -XpathINIT - -if ExtraVim() - - function! INT() - "INTERRUPT - let dummy = 0 - endfunction - - aug TMP - autocmd! - - autocmd User x1 Xpath 1 " X: 1 - autocmd User x1 throw "x1" - autocmd User x1 Xpath 2 " X: 0 - - autocmd User x2 Xpath 4 " X: 4 - autocmd User x2 asdf - autocmd User x2 Xpath 8 " X: 0 - - autocmd User x3 Xpath 16 " X: 16 - autocmd User x3 call INT() - autocmd User x3 Xpath 32 " X: 0 - - autocmd FuncUndefined U1 function! U1() - autocmd FuncUndefined U1 Xpath 64 " X: 0 - autocmd FuncUndefined U1 endfunction - autocmd FuncUndefined U1 Xpath 128 " X: 128 - autocmd FuncUndefined U1 throw "U1" - autocmd FuncUndefined U1 Xpath 256 " X: 0 - - autocmd FuncUndefined U2 function! U2() - autocmd FuncUndefined U2 Xpath 512 " X: 0 - autocmd FuncUndefined U2 endfunction - autocmd FuncUndefined U2 Xpath 1024 " X: 1024 - autocmd FuncUndefined U2 ASDF - autocmd FuncUndefined U2 Xpath 2048 " X: 0 - - autocmd FuncUndefined U3 function! U3() - autocmd FuncUndefined U3 Xpath 4096 " X: 0 - autocmd FuncUndefined U3 endfunction - autocmd FuncUndefined U3 Xpath 8192 " X: 8192 - autocmd FuncUndefined U3 call INT() - autocmd FuncUndefined U3 Xpath 16384 " X: 0 - aug END - - try - try - Xpath 32768 " X: 32768 - doautocmd User x1 - catch /x1/ - Xpath 65536 " X: 65536 - endtry - - while 1 - try - Xpath 131072 " X: 131072 - let caught = 0 - doautocmd User x2 - catch /asdf/ - let caught = 1 - finally - Xpath 262144 " X: 262144 - if !caught && !$VIMNOERRTHROW - Xpath 524288 " X: 0 - " Propagate uncaught error exception, - else - " ... but break loop for caught error exception, - " or discard error and break loop if $VIMNOERRTHROW - break - endif - endtry - endwhile - - while 1 - try - Xpath 1048576 " X: 1048576 - let caught = 0 - doautocmd User x3 - catch /Vim:Interrupt/ - let caught = 1 - finally - Xpath 2097152 " X: 2097152 - if !caught && !$VIMNOINTTHROW - Xpath 4194304 " X: 0 - " Propagate uncaught interrupt exception, - else - " ... but break loop for caught interrupt exception, - " or discard interrupt and break loop if $VIMNOINTTHROW - break - endif - endtry - endwhile - - if exists("*U1") | delfunction U1 | endif - if exists("*U2") | delfunction U2 | endif - if exists("*U3") | delfunction U3 | endif - - try - Xpath 8388608 " X: 8388608 - call U1() - catch /U1/ - Xpath 16777216 " X: 16777216 - endtry - - while 1 - try - Xpath 33554432 " X: 33554432 - let caught = 0 - call U2() - catch /ASDF/ - let caught = 1 - finally - Xpath 67108864 " X: 67108864 - if !caught && !$VIMNOERRTHROW - Xpath 134217728 " X: 0 - " Propagate uncaught error exception, - else - " ... but break loop for caught error exception, - " or discard error and break loop if $VIMNOERRTHROW - break - endif - endtry - endwhile - - while 1 - try - Xpath 268435456 " X: 268435456 - let caught = 0 - call U3() - catch /Vim:Interrupt/ - let caught = 1 - finally - Xpath 536870912 " X: 536870912 - if !caught && !$VIMNOINTTHROW - Xpath 1073741824 " X: 0 - " Propagate uncaught interrupt exception, - else - " ... but break loop for caught interrupt exception, - " or discard interrupt and break loop if $VIMNOINTTHROW - break - endif - endtry - endwhile - catch /.*/ - " The Xpath command does not accept 2^31 (negative); display explicitly: - exec "!echo 2147483648 >>" . g:ExtraVimResult - Xout "Caught" v:exception "in" v:throwpoint - endtry - - unlet caught - delfunction INT - delfunction U1 - delfunction U2 - delfunction U3 - au! TMP - aug! TMP -endif - -Xcheck 934782101 - - -"------------------------------------------------------------------------------- -" Test 85: Error exceptions in autocommands for I/O command events {{{1 -" -" When an I/O command is inside :try/:endtry, autocommands to be -" executed after it should be skipped on an error (exception) in the -" command itself or in autocommands to be executed before the command. -" In the latter case, the I/O command should not be executed either. -" Example 1: BufWritePre, :write, BufWritePost -" Example 2: FileReadPre, :read, FileReadPost. -"------------------------------------------------------------------------------- - -XpathINIT - -function! MSG(enr, emsg) - let english = v:lang == "C" || v:lang =~ '^[Ee]n' - if a:enr == "" - Xout "TODO: Add message number for:" a:emsg - let v:errmsg = ":" . v:errmsg - endif - let match = 1 - if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg) - let match = 0 - if v:errmsg == "" - Xout "Message missing." - else - let v:errmsg = escape(v:errmsg, '"') - Xout "Unexpected message:" v:errmsg - endif - endif - return match -endfunction - -" Remove the autocommands for the events specified as arguments in all used -" autogroups. -function Delete_autocommands(...) - let augfile = tempname() - while 1 - try - exec "redir >" . augfile - aug - redir END - exec "edit" augfile - g/^$/d - norm G$ - let wrap = "w" - while search('\%( \|^\)\@<=.\{-}\%( \)\@=', wrap) > 0 - let wrap = "W" - exec "norm y/ \n" - let argno = 1 - while argno <= a:0 - exec "au!" escape(@", " ") a:{argno} - let argno = argno + 1 - endwhile - endwhile - catch /.*/ - finally - bwipeout! - call delete(augfile) - break " discard errors for $VIMNOERRTHROW - endtry - endwhile -endfunction - -call Delete_autocommands("BufWritePre", "BufWritePost") - -while 1 - try - try - let post = 0 - aug TMP - au! BufWritePost * let post = 1 - aug END - let caught = 0 - write /n/o/n/e/x/i/s/t/e/n/t - catch /^Vim(write):/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim(write):', '', "") - finally - Xpath 1 " X: 1 - if !caught && !$VIMNOERRTHROW - Xpath 2 " X: 0 - endif - let v:errmsg = substitute(v:errmsg, '^"/n/o/n/e/x/i/s/t/e/n/t" ', - \ '', "") - if !MSG('E212', "Can't open file for writing") - Xpath 4 " X: 0 - endif - if post - Xpath 8 " X: 0 - Xout "BufWritePost commands executed after write error" - endif - au! TMP - aug! TMP - endtry - catch /.*/ - Xpath 16 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -while 1 - try - try - let post = 0 - aug TMP - au! BufWritePre * asdf - au! BufWritePost * let post = 1 - aug END - let tmpfile = tempname() - let caught = 0 - exec "write" tmpfile - catch /^Vim\((write)\)\=:/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim\((write)\)\=:', '', "") - finally - Xpath 32 " X: 32 - if !caught && !$VIMNOERRTHROW - Xpath 64 " X: 0 - endif - let v:errmsg = substitute(v:errmsg, '^"'.tmpfile.'" ', '', "") - if !MSG('E492', "Not an editor command") - Xpath 128 " X: 0 - endif - if filereadable(tmpfile) - Xpath 256 " X: 0 - Xout ":write command not suppressed after BufWritePre error" - endif - if post - Xpath 512 " X: 0 - Xout "BufWritePost commands executed after BufWritePre error" - endif - au! TMP - aug! TMP - endtry - catch /.*/ - Xpath 1024 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -call delete(tmpfile) - -call Delete_autocommands("BufWritePre", "BufWritePost", - \ "BufReadPre", "BufReadPost", "FileReadPre", "FileReadPost") - -while 1 - try - try - let post = 0 - aug TMP - au! FileReadPost * let post = 1 - aug END - let caught = 0 - read /n/o/n/e/x/i/s/t/e/n/t - catch /^Vim(read):/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim(read):', '', "") - finally - Xpath 2048 " X: 2048 - if !caught && !$VIMNOERRTHROW - Xpath 4096 " X: 0 - endif - let v:errmsg = substitute(v:errmsg, ' /n/o/n/e/x/i/s/t/e/n/t$', - \ '', "") - if !MSG('E484', "Can't open file") - Xpath 8192 " X: 0 - endif - if post - Xpath 16384 " X: 0 - Xout "FileReadPost commands executed after write error" - endif - au! TMP - aug! TMP - endtry - catch /.*/ - Xpath 32768 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -while 1 - try - let infile = tempname() - let tmpfile = tempname() - exec "!echo XYZ >" . infile - exec "edit" tmpfile - try - Xpath 65536 " X: 65536 - try - let post = 0 - aug TMP - au! FileReadPre * asdf - au! FileReadPost * let post = 1 - aug END - let caught = 0 - exec "0read" infile - catch /^Vim\((read)\)\=:/ - let caught = 1 - let v:errmsg = substitute(v:exception, '^Vim\((read)\)\=:', '', - \ "") - finally - Xpath 131072 " X: 131072 - if !caught && !$VIMNOERRTHROW - Xpath 262144 " X: 0 - endif - let v:errmsg = substitute(v:errmsg, ' '.infile.'$', '', "") - if !MSG('E492', "Not an editor command") - Xpath 524288 " X: 0 - endif - if getline("1") == "XYZ" - Xpath 1048576 " X: 0 - Xout ":read command not suppressed after FileReadPre error" - endif - if post - Xpath 2097152 " X: 0 - Xout "FileReadPost commands executed after " . - \ "FileReadPre error" - endif - au! TMP - aug! TMP - endtry - finally - bwipeout! - endtry - catch /.*/ - Xpath 4194304 " X: 0 - Xout v:exception "in" v:throwpoint - finally - break " discard error for $VIMNOERRTHROW - endtry -endwhile - -call delete(infile) -call delete(tmpfile) -unlet! caught post infile tmpfile -delfunction MSG -delfunction Delete_autocommands - -Xcheck 198689 - -"------------------------------------------------------------------------------- -" Test 86: setloclist crash {{{1 -" -" Executing a setloclist() on BufUnload shouldn't crash Vim -"------------------------------------------------------------------------------- - -func F - au BufUnload * :call setloclist(0, [{'bufnr':1, 'lnum':1, 'col':1, 'text': 'tango down'}]) - - :lvimgrep /.*/ *.mak -endfunc - -XpathINIT - -ExecAsScript F - -delfunction F -Xout "No Crash for vimgrep on BufUnload" -Xcheck 0 - -" Test 87 was moved to test_vimscript.vim -let Xtest = 88 - - -"------------------------------------------------------------------------------- -" Test 88: $VIMNOERRTHROW and $VIMNOINTTHROW support {{{1 -" -" It is possible to configure Vim for throwing exceptions on error -" or interrupt, controlled by variables $VIMNOERRTHROW and -" $VIMNOINTTHROW. This is just for increasing the number of tests. -" All tests here should run for all four combinations of setting -" these variables to 0 or 1. The variables are intended for the -" development phase only. In the final release, Vim should be -" configured to always use error and interrupt exceptions. -" -" The test result is "OK", -" -" - if the $VIMNOERRTHROW and the $VIMNOINTTHROW control are not -" configured and exceptions are thrown on error and on -" interrupt. -" -" - if the $VIMNOERRTHROW or the $VIMNOINTTHROW control is -" configured and works as intended. -" -" What actually happens, is shown in the test output. -" -" Otherwise, the test result is "FAIL", and the test output describes -" the problem. -" -" IMPORTANT: This must be the last test because it sets $VIMNOERRTHROW and -" $VIMNOINTTHROW. -"------------------------------------------------------------------------------- - -XpathINIT - -if ExtraVim() - - function! ThrowOnError() - XloopNEXT - let caught = 0 - try - Xloop 1 " X: 1 + 8 + 64 - asdf - catch /.*/ - let caught = 1 " error exception caught - finally - Xloop 2 " X: 2 + 16 + 128 - return caught " discard aborting error - endtry - Xloop 4 " X: 0 - endfunction - - let quits_skipped = 0 - - function! ThrowOnInterrupt() - XloopNEXT - let caught = 0 - try - Xloop 1 " X: (1 + 8 + 64) * 512 - "INTERRUPT3 - let dummy = 0 - let g:quits_skipped = g:quits_skipped + 1 - catch /.*/ - let caught = 1 " interrupt exception caught - finally - Xloop 2 " X: (2 + 16 + 128) * 512 - return caught " discard interrupt - endtry - Xloop 4 " X: 0 - endfunction - - function! CheckThrow(Type) - execute 'return ThrowOn' . a:Type . '()' - endfunction - - function! CheckConfiguration(type) " type is "error" or "interrupt" - - let type = a:type - let Type = substitute(type, '.*', '\u&', "") - let VAR = '$VIMNO' . substitute(type, '\(...\).*', '\U\1', "") . 'THROW' - - if type == "error" - XloopINIT! 1 8 - elseif type == "interrupt" - XloopINIT! 512 8 - endif - - exec 'let requested_for_tests = exists(VAR) && ' . VAR . ' == 0' - exec 'let suppressed_for_tests = ' . VAR . ' != 0' - let used_in_tests = CheckThrow(Type) - - exec 'let ' . VAR . ' = 0' - let request_works = CheckThrow(Type) - - exec 'let ' . VAR . ' = 1' - let suppress_works = !CheckThrow(Type) - - if type == "error" - XloopINIT! 262144 8 - elseif type == "interrupt" - XloopINIT! 2097152 8 - - if g:quits_skipped != 0 - Xloop 1 " X: 0*2097152 - Xout "Test environment error. Interrupt breakpoints skipped: " - \ . g:quits_skipped . ".\n" - \ . "Cannot check whether interrupt exceptions are thrown." - return - endif - endif - - let failure = - \ !suppressed_for_tests && !used_in_tests - \ || !request_works - - let contradiction = - \ used_in_tests - \ ? suppressed_for_tests && !request_works - \ : !suppressed_for_tests - - if failure - " Failure in configuration. - Xloop 2 " X: 0 * 2* (262144 + 2097152) - elseif contradiction - " Failure in test logic. Should not happen. - Xloop 4 " X: 0 * 4 * (262144 + 2097152) - endif - - let var_control_configured = - \ request_works != used_in_tests - \ || suppress_works == used_in_tests - - let var_control_not_configured = - \ requested_for_tests || suppressed_for_tests - \ ? request_works && !suppress_works - \ : request_works == used_in_tests - \ && suppress_works != used_in_tests - - let with = used_in_tests ? "with" : "without" - - let set = suppressed_for_tests ? "non-zero" : - \ requested_for_tests ? "0" : "unset" - - let although = contradiction && !var_control_not_configured - \ ? ",\nalthough " - \ : ".\n" - - let output = "All tests were run " . with . " throwing exceptions on " - \ . type . although - - if !var_control_not_configured - let output = output . VAR . " was " . set . "." - - if !request_works && !requested_for_tests - let output = output . - \ "\n" . Type . " exceptions are not thrown when " . VAR . - \ " is\nset to 0." - endif - - if !suppress_works && (!used_in_tests || - \ !request_works && - \ !requested_for_tests && !suppressed_for_tests) - let output = output . - \ "\n" . Type . " exceptions are thrown when " . VAR . - \ " is set to 1." - endif - - if !failure && var_control_configured - let output = output . - \ "\nRun tests also with " . substitute(VAR, '^\$', '', "") - \ . "=" . used_in_tests . "." - \ . "\nThis is for testing in the development phase only." - \ . " Remove the \n" - \ . VAR . " control in the final release." - endif - else - let output = output . - \ "The " . VAR . " control is not configured." - endif - - Xout output - endfunction - - call CheckConfiguration("error") - Xpath 16777216 " X: 16777216 - call CheckConfiguration("interrupt") - Xpath 33554432 " X: 33554432 -endif - -Xcheck 50443995 - -" IMPORTANT: No test should be added after this test because it changes -" $VIMNOERRTHROW and $VIMNOINTTHROW. - - -"------------------------------------------------------------------------------- -" Modelines {{{1 -" vim: ts=8 sw=4 tw=80 fdm=marker -"------------------------------------------------------------------------------- diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index c44c847619..6ec4ef2529 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -753,6 +753,7 @@ func Test_popup_with_mask() \ posinvert: 0, \ wrap: 0, \ fixed: 1, + \ scrollbar: v:false, \ zindex: 90, \ padding: [], \ highlight: 'PopupColor', @@ -772,6 +773,7 @@ func Test_popup_with_mask() \ posinvert: 0, \ wrap: 0, \ fixed: 1, + \ scrollbar: v:false, \ close: 'button', \ zindex: 90, \ padding: [], @@ -2169,6 +2171,11 @@ func Test_popup_too_high_scrollbar() call term_sendkeys(buf, ":call ShowPopup()\") call VerifyScreenDump(buf, 'Test_popupwin_toohigh_2', {}) + call term_sendkeys(buf, ":call popup_clear()\") + call term_sendkeys(buf, "gg$") + call term_sendkeys(buf, ":call ShowPopup()\") + call VerifyScreenDump(buf, 'Test_popupwin_toohigh_3', {}) + " clean up call StopVimInTerminal(buf) call delete('XtestPopupToohigh') @@ -3472,6 +3479,31 @@ func Test_popupwin_filter_input_multibyte() unlet g:bytes endfunc +func Test_popupwin_filter_close_ctrl_c() + CheckScreendump + + let lines =<< trim END + vsplit + set laststatus=2 + set statusline=%!Statusline() + + function Statusline() abort + return '%<%f %h%m%r%=%-14.(%l,%c%V%) %P' + endfunction + + call popup_create('test test test test...', {'filter': {-> 0}}) + END + call writefile(lines, 'XtestPopupCtrlC') + + let buf = RunVimInTerminal('-S XtestPopupCtrlC', #{rows: 10}) + + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_popupwin_ctrl_c', {}) + + call StopVimInTerminal(buf) + call delete('XtestPopupCorners') +endfunc + func Test_popupwin_atcursor_far_right() new diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index e71a3dfdec..6a86b1d77c 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -5040,4 +5040,27 @@ func Test_lhelpgrep_from_help_window() new | only! endfunc +" Test for the crash fixed by 7.3.715 +func Test_setloclist_crash() + %bw! + let g:BufNum = bufnr() + augroup QF_Test + au! + au BufUnload * call setloclist(0, [{'bufnr':g:BufNum, 'lnum':1, 'col':1, 'text': 'tango down'}]) + augroup END + + try + lvimgrep /.*/ *.mak + catch /E926:/ + endtry + call assert_equal('tango down', getloclist(0, {'items' : 0}).items[0].text) + call assert_equal(1, getloclist(0, {'size' : 0}).size) + + augroup QF_Test + au! + augroup END + unlet g:BufNum + %bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_tabpage.vim b/src/testdir/test_tabpage.vim index 67469718f2..e561064ebc 100644 --- a/src/testdir/test_tabpage.vim +++ b/src/testdir/test_tabpage.vim @@ -784,6 +784,7 @@ func Test_lastused_tabpage() call assert_beeps('call feedkeys("g\", "xt")') call assert_beeps('call feedkeys("\", "xt")') call assert_beeps('call feedkeys("\g\", "xt")') + call assert_fails('tabnext #', 'E475:') " open four tab pages tabnew @@ -808,17 +809,41 @@ func Test_lastused_tabpage() call assert_equal(4, tabpagenr()) call assert_equal(2, tabpagenr('#')) + " Test for :tabnext # + tabnext # + call assert_equal(2, tabpagenr()) + call assert_equal(4, tabpagenr('#')) + " Try to jump to a closed tab page - tabclose 2 + tabclose # call assert_equal(0, tabpagenr('#')) call feedkeys("g\", "xt") - call assert_equal(3, tabpagenr()) + call assert_equal(2, tabpagenr()) call feedkeys("\", "xt") - call assert_equal(3, tabpagenr()) + call assert_equal(2, tabpagenr()) call feedkeys("\g\", "xt") - call assert_equal(3, tabpagenr()) + call assert_equal(2, tabpagenr()) + call assert_fails('tabnext #', 'E475:') + call assert_equal(2, tabpagenr()) - tabclose! + " Test for :tabonly # + let wnum = win_getid() + $tabnew + tabonly # + call assert_equal(wnum, win_getid()) + call assert_equal(1, tabpagenr('$')) + + " Test for :tabmove # + tabnew + let wnum = win_getid() + tabnew + tabnew + tabnext 2 + tabmove # + call assert_equal(4, tabpagenr()) + call assert_equal(wnum, win_getid()) + + tabonly! endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index aa59973189..22ac442bcb 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -706,7 +706,7 @@ def RetVoid() let x = 1 enddef -def Test_expr4_vimscript() +def Test_expr4_vim9script() # check line continuation let lines =<< trim END vim9script @@ -819,6 +819,12 @@ def Test_expr4_vimscript() echo 2!= 3 END CheckScriptFailure(lines, 'E1004:') + + lines =<< trim END + vim9script + echo len('xxx') == 3 + END + CheckScriptSuccess(lines) enddef func Test_expr4_fails() @@ -1738,7 +1744,7 @@ def Test_expr7_call() assert_equal('yes', 'yes'->Echo()) assert_equal('yes', 'yes' ->s:Echo4Arg()) - assert_equal(1, !range(5)->empty()) + assert_equal(true, !range(5)->empty()) assert_equal([0, 1, 2], --3->range()) call CheckDefFailure(["let x = 'yes'->Echo"], 'E107:') @@ -1750,31 +1756,38 @@ enddef def Test_expr7_not() - assert_equal(true, !'') - assert_equal(true, ![]) - assert_equal(false, !'asdf') - assert_equal(false, ![2]) - assert_equal(true, !!'asdf') - assert_equal(true, !![2]) + let lines =<< trim END + assert_equal(true, !'') + assert_equal(true, ![]) + assert_equal(false, !'asdf') + assert_equal(false, ![2]) + assert_equal(true, !!'asdf') + assert_equal(true, !![2]) - assert_equal(true, !test_null_partial()) - assert_equal(false, !{-> 'yes'}) + assert_equal(true, !test_null_partial()) + assert_equal(false, !{-> 'yes'}) - assert_equal(true, !test_null_dict()) - assert_equal(true, !{}) - assert_equal(false, !{'yes': 'no'}) + assert_equal(true, !test_null_dict()) + assert_equal(true, !{}) + assert_equal(false, !{'yes': 'no'}) - if has('channel') - assert_equal(true, !test_null_job()) - assert_equal(true, !test_null_channel()) - endif + if has('channel') + assert_equal(true, !test_null_job()) + assert_equal(true, !test_null_channel()) + endif - assert_equal(true, !test_null_blob()) - assert_equal(true, !0z) - assert_equal(false, !0z01) + assert_equal(true, !test_null_blob()) + assert_equal(true, !0z) + assert_equal(false, !0z01) - assert_equal(true, !test_void()) - assert_equal(true, !test_unknown()) + assert_equal(true, !test_void()) + assert_equal(true, !test_unknown()) + + assert_equal(false, ![1, 2, 3]->reverse()) + assert_equal(true, ![]->reverse()) + END + CheckDefSuccess(lines) + CheckScriptSuccess(['vim9script'] + lines) enddef func Test_expr7_fails() diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 4a020c9afa..772b52ab97 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -203,6 +203,15 @@ def Test_global_local_function() assert_equal('local', Func()) END CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + def g:Funcy() + echo 'funcy' + enddef + s:Funcy() + END + CheckScriptFailure(lines, 'E117:') enddef func TakesOneArg(arg) diff --git a/src/testdir/test_vimscript.vim b/src/testdir/test_vimscript.vim index 02cf2d1c48..1b00fc9e78 100644 --- a/src/testdir/test_vimscript.vim +++ b/src/testdir/test_vimscript.vim @@ -1,5 +1,6 @@ " Test various aspects of the Vim script language. -" Most of this was formerly in test49. +" Most of this was formerly in test49.vim (developed by Servatius Brandt +" ) source check.vim source shared.vim @@ -23,6 +24,7 @@ com! -nargs=1 Xout call Xout() " file. If the test passes successfully, then Xtest.out should be empty. func RunInNewVim(test, verify) let init =<< trim END + set cpo-=C " support line-continuation in sourced script source script_util.vim XpathINIT XloopINIT @@ -3719,6 +3721,381 @@ func Test_execption_info_for_error() call RunInNewVim(test, verify) endfunc +"------------------------------------------------------------------------------- +" +" Test 59: v:exception and v:throwpoint when discarding exceptions {{{1 +" +" When a :catch clause is left by a ":break" etc or an error or +" interrupt exception, v:exception and v:throwpoint are reset. They +" are not affected by an exception that is discarded before being +" caught. +"------------------------------------------------------------------------------- +func Test_exception_info_on_discard() + CheckEnglish + + let test =<< trim [CODE] + let sfile = expand("") + + while 1 + try + throw "x1" + catch /.*/ + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + while 1 + try + throw "x2" + catch /.*/ + break + finally + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + endtry + break + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + while 1 + try + let errcaught = 0 + try + try + throw "x3" + catch /.*/ + let lnum = expand("") + asdf + endtry + catch /.*/ + let errcaught = 1 + call assert_match('Vim:E492: Not an editor command:', v:exception) + call assert_match('line ' .. (lnum + 1), v:throwpoint) + endtry + finally + call assert_equal(1, errcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'a' + + while 1 + try + let intcaught = 0 + try + try + throw "x4" + catch /.*/ + let lnum = expand("") + call interrupt() + endtry + catch /.*/ + let intcaught = 1 + call assert_match('Vim:Interrupt', v:exception) + call assert_match('line ' .. (lnum + 1), v:throwpoint) + endtry + finally + call assert_equal(1, intcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'b' + + while 1 + try + let errcaught = 0 + try + try + if 1 + let lnum = expand("") + throw "x5" + " missing endif + catch /.*/ + call assert_report('should not get here') + endtry + catch /.*/ + let errcaught = 1 + call assert_match('Vim(catch):E171: Missing :endif:', v:exception) + call assert_match('line ' .. (lnum + 3), v:throwpoint) + endtry + finally + call assert_equal(1, errcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'c' + + try + while 1 + try + throw "x6" + finally + break + endtry + break + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + try + while 1 + try + throw "x7" + finally + break + endtry + break + endwhile + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + endtry + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + while 1 + try + let errcaught = 0 + try + try + throw "x8" + finally + let lnum = expand("") + asdf + endtry + catch /.*/ + let errcaught = 1 + call assert_match('Vim:E492: Not an editor command:', v:exception) + call assert_match('line ' .. (lnum + 1), v:throwpoint) + endtry + finally + call assert_equal(1, errcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'd' + + while 1 + try + let intcaught = 0 + try + try + throw "x9" + finally + let lnum = expand("") + call interrupt() + endtry + catch /.*/ + let intcaught = 1 + call assert_match('Vim:Interrupt', v:exception) + call assert_match('line ' .. (lnum + 1), v:throwpoint) + endtry + finally + call assert_equal(1, intcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'e' + + while 1 + try + let errcaught = 0 + try + try + if 1 + let lnum = expand("") + throw "x10" + " missing endif + finally + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + endtry + catch /.*/ + let errcaught = 1 + call assert_match('Vim(finally):E171: Missing :endif:', v:exception) + call assert_match('line ' .. (lnum + 3), v:throwpoint) + endtry + finally + call assert_equal(1, errcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'f' + + while 1 + try + let errcaught = 0 + try + try + if 1 + let lnum = expand("") + throw "x11" + " missing endif + endtry + catch /.*/ + let errcaught = 1 + call assert_match('Vim(endtry):E171: Missing :endif:', v:exception) + call assert_match('line ' .. (lnum + 3), v:throwpoint) + endtry + finally + call assert_equal(1, errcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'g' + [CODE] + let verify =<< trim [CODE] + call assert_equal('abcdefg', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +"------------------------------------------------------------------------------- +" +" Test 60: (Re)throwing v:exception; :echoerr. {{{1 +" +" A user exception can be rethrown after catching by throwing +" v:exception. An error or interrupt exception cannot be rethrown +" because Vim exceptions cannot be faked. A Vim exception using the +" value of v:exception can, however, be triggered by the :echoerr +" command. +"------------------------------------------------------------------------------- + +func Test_rethrow_exception_1() + XpathINIT + try + try + Xpath 'a' + throw "oops" + catch /oops/ + Xpath 'b' + throw v:exception " rethrow user exception + catch /.*/ + call assert_report('should not get here') + endtry + catch /^oops$/ " catches rethrown user exception + Xpath 'c' + catch /.*/ + call assert_report('should not get here') + endtry + call assert_equal('abc', g:Xpath) +endfunc + +func Test_rethrow_exception_2() + XpathINIT + try + let caught = 0 + try + Xpath 'a' + write /n/o/n/w/r/i/t/a/b/l/e/_/f/i/l/e + call assert_report('should not get here') + catch /^Vim(write):/ + let caught = 1 + throw v:exception " throw error: cannot fake Vim exception + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'b' + call assert_equal(1, caught) + endtry + catch /^Vim(throw):/ " catches throw error + let caught = caught + 1 + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + call assert_equal(2, caught) + endtry + call assert_equal('abc', g:Xpath) +endfunc + +func Test_rethrow_exception_3() + XpathINIT + try + let caught = 0 + try + Xpath 'a' + asdf + catch /^Vim/ " catch error exception + let caught = 1 + " Trigger Vim error exception with value specified after :echoerr + let value = substitute(v:exception, '^Vim\((.*)\)\=:', '', "") + echoerr value + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'b' + call assert_equal(1, caught) + endtry + catch /^Vim(echoerr):/ + let caught = caught + 1 + call assert_match(value, v:exception) + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + call assert_equal(2, caught) + endtry + call assert_equal('abc', g:Xpath) +endfunc + +func Test_rethrow_exception_3() + XpathINIT + try + let errcaught = 0 + try + Xpath 'a' + let intcaught = 0 + call interrupt() + catch /^Vim:/ " catch interrupt exception + let intcaught = 1 + " Trigger Vim error exception with value specified after :echoerr + echoerr substitute(v:exception, '^Vim\((.*)\)\=:', '', "") + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'b' + call assert_equal(1, intcaught) + endtry + catch /^Vim(echoerr):/ + let errcaught = 1 + call assert_match('Interrupt', v:exception) + finally + Xpath 'c' + call assert_equal(1, errcaught) + endtry + call assert_equal('abc', g:Xpath) +endfunc + "------------------------------------------------------------------------------- " Test 61: Catching interrupt exceptions {{{1 " @@ -3845,6 +4222,513 @@ func Test_catch_intr_exception() call RunInNewVim(test, verify) endfunc +"------------------------------------------------------------------------------- +" Test 62: Catching error exceptions {{{1 +" +" An error inside a :try/:endtry region is converted to an exception +" and can be caught. The error exception has a "Vim(cmdname):" prefix +" where cmdname is the name of the failing command, or a "Vim:" prefix +" if no command name is known. The "Vim" prefixes cannot be faked. +"------------------------------------------------------------------------------- + +func Test_catch_err_exception_1() + XpathINIT + while 1 + try + try + let caught = 0 + unlet novar + catch /^Vim(unlet):/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim(unlet):', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match('E108: No such variable: "novar"', v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abc', g:Xpath) +endfunc + +func Test_catch_err_exception_2() + XpathINIT + while 1 + try + try + let caught = 0 + throw novar " error in :throw + catch /^Vim(throw):/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match('E121: Undefined variable: novar', v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abc', g:Xpath) +endfunc + +func Test_catch_err_exception_3() + XpathINIT + while 1 + try + try + let caught = 0 + throw "Vim:faked" " error: cannot fake Vim exception + catch /^Vim(throw):/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match("E608: Cannot :throw exceptions with 'Vim' prefix", + \ v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abc', g:Xpath) +endfunc + +func Test_catch_err_exception_4() + XpathINIT + func F() + while 1 + " Missing :endwhile + endfunc + + while 1 + try + try + let caught = 0 + call F() + catch /^Vim(endfunction):/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim(endfunction):', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match("E170: Missing :endwhile", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abc', g:Xpath) + delfunc F +endfunc + +func Test_catch_err_exception_5() + XpathINIT + func F() + while 1 + " Missing :endwhile + endfunc + + while 1 + try + try + let caught = 0 + ExecAsScript F + catch /^Vim:/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim:', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match("E170: Missing :endwhile", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abc', g:Xpath) + delfunc F +endfunc + +func Test_catch_err_exception_6() + XpathINIT + func G() + call G() + endfunc + + while 1 + try + let mfd_save = &mfd + set mfd=3 + try + let caught = 0 + call G() + catch /^Vim(call):/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim(call):', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match("E132: Function call depth is higher than 'maxfuncdepth'", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + let &mfd = mfd_save + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abc', g:Xpath) + delfunc G +endfunc + +func Test_catch_err_exception_7() + XpathINIT + func H() + return H() + endfunc + + while 1 + try + let mfd_save = &mfd + set mfd=3 + try + let caught = 0 + call H() + catch /^Vim(return):/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim(return):', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match("E132: Function call depth is higher than 'maxfuncdepth'", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + let &mfd = mfd_save + break " discard error for $VIMNOERRTHROW + endtry + call assert_report('should not get here') + endwhile + + call assert_equal('abc', g:Xpath) + delfunc H +endfunc + +"------------------------------------------------------------------------------- +" Test 63: Suppressing error exceptions by :silent!. {{{1 +" +" A :silent! command inside a :try/:endtry region suppresses the +" conversion of errors to an exception and the immediate abortion on +" error. When the commands executed by the :silent! themselves open +" a new :try/:endtry region, conversion of errors to exception and +" immediate abortion is switched on again - until the next :silent! +" etc. The :silent! has the effect of setting v:errmsg to the error +" message text (without displaying it) and continuing with the next +" script line. +" +" When a command triggering autocommands is executed by :silent! +" inside a :try/:endtry, the autocommand execution is not suppressed +" on error. +" +" This test reuses the function MSG() from the previous test. +"------------------------------------------------------------------------------- + +func Test_silent_exception() + XpathINIT + XloopINIT + let g:taken = "" + + func S(n) abort + XloopNEXT + let g:taken = g:taken . "E" . a:n + let v:errmsg = "" + exec "asdf" . a:n + + " Check that ":silent!" continues: + Xloop 'a' + + " Check that ":silent!" sets "v:errmsg": + call assert_match("E492: Not an editor command", v:errmsg) + endfunc + + func Foo() + while 1 + try + try + let caught = 0 + " This is not silent: + call S(3) + catch /^Vim:/ + Xpath 'b' + let caught = 1 + let errmsg3 = substitute(v:exception, '^Vim:', '', "") + silent! call S(4) + finally + call assert_equal(1, caught) + Xpath 'c' + call assert_match("E492: Not an editor command", errmsg3) + silent! call S(5) + " Break out of try conditionals that cover ":silent!". This also + " discards the aborting error when $VIMNOERRTHROW is non-zero. + break + endtry + catch /.*/ + call assert_report('should not get here') + endtry + endwhile + " This is a double ":silent!" (see caller). + silent! call S(6) + endfunc + + func Bar() + try + silent! call S(2) + silent! execute "call Foo() | call S(7)" + silent! call S(8) + endtry " normal end of try cond that covers ":silent!" + " This has a ":silent!" from the caller: + call S(9) + endfunc + + silent! call S(1) + silent! call Bar() + silent! call S(10) + + call assert_equal("E1E2E3E4E5E6E7E8E9E10", g:taken) + + augroup TMP + au! + autocmd BufWritePost * Xpath 'd' + augroup END + + Xpath 'e' + silent! write /i/m/p/o/s/s/i/b/l/e + Xpath 'f' + + call assert_equal('a2a3ba5ca6a7a8a9a10a11edf', g:Xpath) + + augroup TMP + au! + augroup END + augroup! TMP + delfunction S + delfunction Foo + delfunction Bar +endfunc + +"------------------------------------------------------------------------------- +" Test 64: Error exceptions after error, interrupt or :throw {{{1 +" +" When an error occurs after an interrupt or a :throw but before +" a matching :catch is reached, all following :catches of that try +" block are ignored, but the error exception can be caught by the next +" surrounding try conditional. Any previous error exception is +" discarded. An error is ignored when there is a previous error that +" has not been caught. +"------------------------------------------------------------------------------- + +func Test_exception_after_error_1() + XpathINIT + while 1 + try + try + Xpath 'a' + let caught = 0 + while 1 + if 1 + " Missing :endif + endwhile " throw error exception + catch /^Vim(/ + Xpath 'b' + let caught = 1 + finally + Xpath 'c' + call assert_equal(1, caught) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'd' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abcd', g:Xpath) +endfunc + +func Test_exception_after_error_2() + XpathINIT + while 1 + try + try + Xpath 'a' + let caught = 0 + try + if 1 + " Missing :endif + catch /.*/ " throw error exception + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + endtry + catch /^Vim(/ + Xpath 'b' + let caught = 1 + finally + Xpath 'c' + call assert_equal(1, caught) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'd' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abcd', g:Xpath) +endfunc + +func Test_exception_after_error_3() + XpathINIT + while 1 + try + try + let caught = 0 + try + Xpath 'a' + call interrupt() + catch /do_not_catch/ + call assert_report('should not get here') + if 1 + " Missing :endif + catch /.*/ " throw error exception + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + endtry + catch /^Vim(/ + Xpath 'b' + let caught = 1 + finally + Xpath 'c' + call assert_equal(1, caught) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'd' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abcd', g:Xpath) +endfunc + +func Test_exception_after_error_4() + XpathINIT + while 1 + try + try + let caught = 0 + try + Xpath 'a' + throw "x" + catch /do_not_catch/ + call assert_report('should not get here') + if 1 + " Missing :endif + catch /x/ " throw error exception + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + endtry + catch /^Vim(/ + Xpath 'b' + let caught = 1 + finally + Xpath 'c' + call assert_equal(1, caught) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'd' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abcd', g:Xpath) +endfunc + +func Test_exception_after_error_5() + XpathINIT + while 1 + try + try + let caught = 0 + Xpath 'a' + endif " :endif without :if; throw error exception + if 1 + " Missing :endif + catch /do_not_catch/ " ignore new error + call assert_report('should not get here') + catch /^Vim(endif):/ + Xpath 'b' + let caught = 1 + catch /^Vim(/ + call assert_report('should not get here') + finally + Xpath 'c' + call assert_equal(1, caught) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'd' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abcd', g:Xpath) +endfunc + "------------------------------------------------------------------------------- " Test 65: Errors in the /pattern/ argument of a :catch {{{1 " @@ -3910,6 +4794,1605 @@ func Test_catch_pattern_error() delfunc F endfunc +"------------------------------------------------------------------------------- +" Test 66: Stop range :call on error, interrupt, or :throw {{{1 +" +" When a function which is multiply called for a range since it +" doesn't handle the range itself has an error in a command +" dynamically enclosed by :try/:endtry or gets an interrupt or +" executes a :throw, no more calls for the remaining lines in the +" range are made. On an error in a command not dynamically enclosed +" by :try/:endtry, the function is executed again for the remaining +" lines in the range. +"------------------------------------------------------------------------------- + +func Test_stop_range_on_error() + let test =<< trim [CODE] + let file = tempname() + exec "edit" file + call setline(1, ['line 1', 'line 2', 'line 3']) + let taken = "" + let expected = "G1EF1E(1)F1E(2)F1E(3)G2EF2E(1)G3IF3I(1)G4TF4T(1)G5AF5A(1)" + + func F(reason, n) abort + let g:taken = g:taken .. "F" .. a:n .. + \ substitute(a:reason, '\(\l\).*', '\u\1', "") .. + \ "(" .. line(".") .. ")" + + if a:reason == "error" + asdf + elseif a:reason == "interrupt" + call interrupt() + elseif a:reason == "throw" + throw "xyz" + elseif a:reason == "aborting error" + XloopNEXT + call assert_equal(g:taken, g:expected) + try + bwipeout! + call delete(g:file) + asdf + endtry + endif + endfunc + + func G(reason, n) + let g:taken = g:taken .. "G" .. a:n .. + \ substitute(a:reason, '\(\l\).*', '\u\1', "") + 1,3call F(a:reason, a:n) + endfunc + + Xpath 'a' + call G("error", 1) + try + Xpath 'b' + try + call G("error", 2) + call assert_report('should not get here') + finally + Xpath 'c' + try + call G("interrupt", 3) + call assert_report('should not get here') + finally + Xpath 'd' + try + call G("throw", 4) + call assert_report('should not get here') + endtry + endtry + endtry + catch /xyz/ + Xpath 'e' + catch /.*/ + call assert_report('should not get here') + endtry + Xpath 'f' + call G("aborting error", 5) + call assert_report('should not get here') + [CODE] + let verify =<< trim [CODE] + call assert_equal('abcdef', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +"------------------------------------------------------------------------------- +" Test 67: :throw across :call command {{{1 +" +" On a call command, an exception might be thrown when evaluating the +" function name, during evaluation of the arguments, or when the +" function is being executed. The exception can be caught by the +" caller. +"------------------------------------------------------------------------------- + +func THROW(x, n) + if a:n == 1 + Xpath 'A' + elseif a:n == 2 + Xpath 'B' + elseif a:n == 3 + Xpath 'C' + endif + throw a:x +endfunc + +func NAME(x, n) + if a:n == 1 + call assert_report('should not get here') + elseif a:n == 2 + Xpath 'D' + elseif a:n == 3 + Xpath 'E' + elseif a:n == 4 + Xpath 'F' + endif + return a:x +endfunc + +func ARG(x, n) + if a:n == 1 + call assert_report('should not get here') + elseif a:n == 2 + call assert_report('should not get here') + elseif a:n == 3 + Xpath 'G' + elseif a:n == 4 + Xpath 'I' + endif + return a:x +endfunc + +func Test_throw_across_call_cmd() + XpathINIT + + func F(x, n) + if a:n == 2 + call assert_report('should not get here') + elseif a:n == 4 + Xpath 'a' + endif + endfunc + + while 1 + try + let v:errmsg = "" + + while 1 + try + Xpath 'b' + call {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1) + call assert_report('should not get here') + catch /^name$/ + Xpath 'c' + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + + while 1 + try + Xpath 'd' + call {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2) + call assert_report('should not get here') + catch /^arg$/ + Xpath 'e' + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + + while 1 + try + Xpath 'f' + call {NAME("THROW", 3)}(ARG("call", 3), 3) + call assert_report('should not get here') + catch /^call$/ + Xpath 'g' + catch /^0$/ " default return value + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + + while 1 + try + Xpath 'h' + call {NAME("F", 4)}(ARG(4711, 4), 4) + Xpath 'i' + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + + catch /^0$/ " default return value + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + + call assert_equal('bAcdDBefEGCghFIai', g:Xpath) + delfunction F +endfunc + +"------------------------------------------------------------------------------- +" Test 68: :throw across function calls in expressions {{{1 +" +" On a function call within an expression, an exception might be +" thrown when evaluating the function name, during evaluation of the +" arguments, or when the function is being executed. The exception +" can be caught by the caller. +" +" This test reuses the functions THROW(), NAME(), and ARG() from the +" previous test. +"------------------------------------------------------------------------------- + +func Test_throw_across_call_expr() + XpathINIT + + func F(x, n) + if a:n == 2 + call assert_report('should not get here') + elseif a:n == 4 + Xpath 'a' + endif + return a:x + endfunction + + while 1 + try + let error = 0 + let v:errmsg = "" + + while 1 + try + Xpath 'b' + let var1 = {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1) + call assert_report('should not get here') + catch /^name$/ + Xpath 'c' + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + call assert_true(!exists('var1')) + + while 1 + try + Xpath 'd' + let var2 = {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2) + call assert_report('should not get here') + catch /^arg$/ + Xpath 'e' + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + call assert_true(!exists('var2')) + + while 1 + try + Xpath 'f' + let var3 = {NAME("THROW", 3)}(ARG("call", 3), 3) + call assert_report('should not get here') + catch /^call$/ + Xpath 'g' + catch /^0$/ " default return value + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + call assert_true(!exists('var3')) + + while 1 + try + Xpath 'h' + let var4 = {NAME("F", 4)}(ARG(4711, 4), 4) + Xpath 'i' + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + call assert_true(exists('var4') && var4 == 4711) + + catch /^0$/ " default return value + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + break + endtry + endwhile + + call assert_equal('bAcdDBefEGCghFIai', g:Xpath) + delfunc F +endfunc + +"------------------------------------------------------------------------------- +" Test 76: Errors, interrupts, :throw during expression evaluation {{{1 +" +" When a function call made during expression evaluation is aborted +" due to an error inside a :try/:endtry region or due to an interrupt +" or a :throw, the expression evaluation is aborted as well. No +" message is displayed for the cancelled expression evaluation. On an +" error not inside :try/:endtry, the expression evaluation continues. +"------------------------------------------------------------------------------- + +func Test_expr_eval_error() + let test =<< trim [CODE] + let taken = "" + + func ERR(n) + let g:taken = g:taken .. "E" .. a:n + asdf + endfunc + + func ERRabort(n) abort + let g:taken = g:taken .. "A" .. a:n + asdf + endfunc " returns -1; may cause follow-up msg for illegal var/func name + + func WRAP(n, arg) + let g:taken = g:taken .. "W" .. a:n + let g:saved_errmsg = v:errmsg + return arg + endfunc + + func INT(n) + let g:taken = g:taken .. "I" .. a:n + call interrupt() + endfunc + + func THR(n) + let g:taken = g:taken .. "T" .. a:n + throw "should not be caught" + endfunc + + func CONT(n) + let g:taken = g:taken .. "C" .. a:n + endfunc + + func MSG(n) + let g:taken = g:taken .. "M" .. a:n + let errmsg = (a:n >= 37 && a:n <= 44) ? g:saved_errmsg : v:errmsg + let msgptn = (a:n >= 10 && a:n <= 27) ? "^$" : "asdf" + call assert_match(msgptn, errmsg) + let v:errmsg = "" + let g:saved_errmsg = "" + endfunc + + let v:errmsg = "" + + try + let t = 1 + while t <= 9 + Xloop 'a' + try + if t == 1 + let v{ERR(t) + CONT(t)} = 0 + elseif t == 2 + let v{ERR(t) + CONT(t)} + elseif t == 3 + let var = exists('v{ERR(t) + CONT(t)}') + elseif t == 4 + unlet v{ERR(t) + CONT(t)} + elseif t == 5 + function F{ERR(t) + CONT(t)}() + endfunction + elseif t == 6 + function F{ERR(t) + CONT(t)} + elseif t == 7 + let var = exists('*F{ERR(t) + CONT(t)}') + elseif t == 8 + delfunction F{ERR(t) + CONT(t)} + elseif t == 9 + let var = ERR(t) + CONT(t) + endif + catch /asdf/ + " v:errmsg is not set when the error message is converted to an + " exception. Set it to the original error message. + let v:errmsg = substitute(v:exception, '^Vim:', '', "") + catch /^Vim\((\a\+)\)\=:/ + " An error exception has been thrown after the original error. + let v:errmsg = "" + finally + call MSG(t) + let t = t + 1 + XloopNEXT + continue " discard an aborting error + endtry + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + + try + let t = 10 + while t <= 18 + Xloop 'b' + try + if t == 10 + let v{INT(t) + CONT(t)} = 0 + elseif t == 11 + let v{INT(t) + CONT(t)} + elseif t == 12 + let var = exists('v{INT(t) + CONT(t)}') + elseif t == 13 + unlet v{INT(t) + CONT(t)} + elseif t == 14 + function F{INT(t) + CONT(t)}() + endfunction + elseif t == 15 + function F{INT(t) + CONT(t)} + elseif t == 16 + let var = exists('*F{INT(t) + CONT(t)}') + elseif t == 17 + delfunction F{INT(t) + CONT(t)} + elseif t == 18 + let var = INT(t) + CONT(t) + endif + catch /^Vim\((\a\+)\)\=:\(Interrupt\)\@!/ + " An error exception has been triggered after the interrupt. + let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") + finally + call MSG(t) + let t = t + 1 + XloopNEXT + continue " discard interrupt + endtry + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + + try + let t = 19 + while t <= 27 + Xloop 'c' + try + if t == 19 + let v{THR(t) + CONT(t)} = 0 + elseif t == 20 + let v{THR(t) + CONT(t)} + elseif t == 21 + let var = exists('v{THR(t) + CONT(t)}') + elseif t == 22 + unlet v{THR(t) + CONT(t)} + elseif t == 23 + function F{THR(t) + CONT(t)}() + endfunction + elseif t == 24 + function F{THR(t) + CONT(t)} + elseif t == 25 + let var = exists('*F{THR(t) + CONT(t)}') + elseif t == 26 + delfunction F{THR(t) + CONT(t)} + elseif t == 27 + let var = THR(t) + CONT(t) + endif + catch /^Vim\((\a\+)\)\=:/ + " An error exception has been triggered after the :throw. + let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") + finally + call MSG(t) + let t = t + 1 + XloopNEXT + continue " discard exception + endtry + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + + let v{ERR(28) + CONT(28)} = 0 + call MSG(28) + let v{ERR(29) + CONT(29)} + call MSG(29) + let var = exists('v{ERR(30) + CONT(30)}') + call MSG(30) + unlet v{ERR(31) + CONT(31)} + call MSG(31) + function F{ERR(32) + CONT(32)}() + endfunction + call MSG(32) + function F{ERR(33) + CONT(33)} + call MSG(33) + let var = exists('*F{ERR(34) + CONT(34)}') + call MSG(34) + delfunction F{ERR(35) + CONT(35)} + call MSG(35) + let var = ERR(36) + CONT(36) + call MSG(36) + + let saved_errmsg = "" + + let v{WRAP(37, ERRabort(37)) + CONT(37)} = 0 + call MSG(37) + let v{WRAP(38, ERRabort(38)) + CONT(38)} + call MSG(38) + let var = exists('v{WRAP(39, ERRabort(39)) + CONT(39)}') + call MSG(39) + unlet v{WRAP(40, ERRabort(40)) + CONT(40)} + call MSG(40) + function F{WRAP(41, ERRabort(41)) + CONT(41)}() + endfunction + call MSG(41) + function F{WRAP(42, ERRabort(42)) + CONT(42)} + call MSG(42) + let var = exists('*F{WRAP(43, ERRabort(43)) + CONT(43)}') + call MSG(43) + delfunction F{WRAP(44, ERRabort(44)) + CONT(44)} + call MSG(44) + let var = ERRabort(45) + CONT(45) + call MSG(45) + Xpath 'd' + + let expected = "" + \ .. "E1M1E2M2E3M3E4M4E5M5E6M6E7M7E8M8E9M9" + \ .. "I10M10I11M11I12M12I13M13I14M14I15M15I16M16I17M17I18M18" + \ .. "T19M19T20M20T21M21T22M22T23M23T24M24T25M25T26M26T27M27" + \ .. "E28C28M28E29C29M29E30C30M30E31C31M31E32C32M32E33C33M33" + \ .. "E34C34M34E35C35M35E36C36M36" + \ .. "A37W37C37M37A38W38C38M38A39W39C39M39A40W40C40M40A41W41C41M41" + \ .. "A42W42C42M42A43W43C43M43A44W44C44M44A45C45M45" + call assert_equal(expected, taken) + [CODE] + let verify =<< trim [CODE] + let expected = "a1a2a3a4a5a6a7a8a9" + \ .. "b10b11b12b13b14b15b16b17b18" + \ .. "c19c20c21c22c23c24c25c26c27d" + call assert_equal(expected, g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +"------------------------------------------------------------------------------- +" Test 77: Errors, interrupts, :throw in name{brace-expression} {{{1 +" +" When a function call made during evaluation of an expression in +" braces as part of a function name after ":function" is aborted due +" to an error inside a :try/:endtry region or due to an interrupt or +" a :throw, the expression evaluation is aborted as well, and the +" function definition is ignored, skipping all commands to the +" ":endfunction". On an error not inside :try/:endtry, the expression +" evaluation continues and the function gets defined, and can be +" called and deleted. +"------------------------------------------------------------------------------- +func Test_brace_expr_error() + let test =<< trim [CODE] + func ERR() abort + Xloop 'a' + asdf + endfunc " returns -1 + + func OK() + Xloop 'b' + let v:errmsg = "" + return 0 + endfunc + + let v:errmsg = "" + + Xpath 'c' + func F{1 + ERR() + OK()}(arg) + " F0 should be defined. + if exists("a:arg") && a:arg == "calling" + Xpath 'd' + else + call assert_report('should not get here') + endif + endfunction + call assert_equal("", v:errmsg) + XloopNEXT + + Xpath 'e' + call F{1 + ERR() + OK()}("calling") + call assert_equal("", v:errmsg) + XloopNEXT + + Xpath 'f' + delfunction F{1 + ERR() + OK()} + call assert_equal("", v:errmsg) + XloopNEXT + + try + while 1 + try + Xpath 'g' + func G{1 + ERR() + OK()}(arg) + " G0 should not be defined, and the function body should be + " skipped. + call assert_report('should not get here') + " Use an unmatched ":finally" to check whether the body is + " skipped when an error occurs in ERR(). This works whether or + " not the exception is converted to an exception. + finally + call assert_report('should not get here') + endtry + try + call assert_report('should not get here') + endfunction + + call assert_report('should not get here') + catch /asdf/ + " Jumped to when the function is not defined and the body is + " skipped. + Xpath 'h' + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'i' + break + endtry " jumped to when the body is not skipped + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + [CODE] + let verify =<< trim [CODE] + call assert_equal('ca1b1ea2b2dfa3b3ga4hi', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +"------------------------------------------------------------------------------- +" Test 78: Messages on parsing errors in expression evaluation {{{1 +" +" When an expression evaluation detects a parsing error, an error +" message is given and converted to an exception, and the expression +" evaluation is aborted. +"------------------------------------------------------------------------------- +func Test_expr_eval_error_msg() + CheckEnglish + + let test =<< trim [CODE] + let taken = "" + + func F(n) + let g:taken = g:taken . "F" . a:n + endfunc + + func MSG(n, enr, emsg) + let g:taken = g:taken . "M" . a:n + call assert_match('^' .. a:enr .. ':', v:errmsg) + call assert_match(a:emsg, v:errmsg) + endfunc + + func CONT(n) + let g:taken = g:taken . "C" . a:n + endfunc + + let v:errmsg = "" + try + let t = 1 + while t <= 14 + let g:taken = g:taken . "T" . t + let v:errmsg = "" + try + if t == 1 + let v{novar + CONT(t)} = 0 + elseif t == 2 + let v{novar + CONT(t)} + elseif t == 3 + let var = exists('v{novar + CONT(t)}') + elseif t == 4 + unlet v{novar + CONT(t)} + elseif t == 5 + function F{novar + CONT(t)}() + endfunction + elseif t == 6 + function F{novar + CONT(t)} + elseif t == 7 + let var = exists('*F{novar + CONT(t)}') + elseif t == 8 + delfunction F{novar + CONT(t)} + elseif t == 9 + echo novar + CONT(t) + elseif t == 10 + echo v{novar + CONT(t)} + elseif t == 11 + echo F{novar + CONT(t)} + elseif t == 12 + let var = novar + CONT(t) + elseif t == 13 + let var = v{novar + CONT(t)} + elseif t == 14 + let var = F{novar + CONT(t)}() + endif + catch /^Vim\((\a\+)\)\=:/ + Xloop 'a' + " v:errmsg is not set when the error message is converted to an + " exception. Set it to the original error message. + let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") + finally + Xloop 'b' + if t <= 8 && t != 3 && t != 7 + call MSG(t, 'E475', 'Invalid argument\>') + else + call MSG(t, 'E121', "Undefined variable") + endif + let t = t + 1 + XloopNEXT + continue " discard an aborting error + endtry + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + + func T(n, expr, enr, emsg) + try + let g:taken = g:taken . "T" . a:n + let v:errmsg = "" + try + execute "let var = " . a:expr + catch /^Vim\((\a\+)\)\=:/ + Xloop 'c' + " v:errmsg is not set when the error message is converted to an + " exception. Set it to the original error message. + let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") + finally + Xloop 'd' + call MSG(a:n, a:enr, a:emsg) + XloopNEXT + " Discard an aborting error: + return + endtry + catch /.*/ + call assert_report('should not get here') + endtry + endfunc + + call T(15, 'Nofunc() + CONT(15)', 'E117', "Unknown function") + call T(16, 'F(1 2 + CONT(16))', 'E116', "Invalid arguments") + call T(17, 'F(1, 2) + CONT(17)', 'E118', "Too many arguments") + call T(18, 'F() + CONT(18)', 'E119', "Not enough arguments") + call T(19, '{(1} + CONT(19)', 'E110', "Missing ')'") + call T(20, '("abc"[1) + CONT(20)', 'E111', "Missing ']'") + call T(21, '(1 +) + CONT(21)', 'E15', "Invalid expression") + call T(22, '1 2 + CONT(22)', 'E15', "Invalid expression") + call T(23, '(1 ? 2) + CONT(23)', 'E109', "Missing ':' after '?'") + call T(24, '("abc) + CONT(24)', 'E114', "Missing quote") + call T(25, "('abc) + CONT(25)", 'E115', "Missing quote") + call T(26, '& + CONT(26)', 'E112', "Option name missing") + call T(27, '&asdf + CONT(27)', 'E113', "Unknown option") + + let expected = "" + \ .. "T1M1T2M2T3M3T4M4T5M5T6M6T7M7T8M8T9M9T10M10T11M11T12M12T13M13T14M14" + \ .. "T15M15T16M16T17M17T18M18T19M19T20M20T21M21T22M22T23M23T24M24T25M25" + \ .. "T26M26T27M27" + + call assert_equal(expected, taken) + [CODE] + let verify =<< trim [CODE] + let expected = "a1b1a2b2a3b3a4b4a5b5a6b6a7b7a8b8a9b9a10b10a11b11a12b12" + \ .. "a13b13a14b14c15d15c16d16c17d17c18d18c19d19c20d20" + \ .. "c21d21c22d22c23d23c24d24c25d25c26d26c27d27" + call assert_equal(expected, g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +"------------------------------------------------------------------------------- +" Test 79: Throwing one of several errors for the same command {{{1 +" +" When several errors appear in a row (for instance during expression +" evaluation), the first as the most specific one is used when +" throwing an error exception. If, however, a syntax error is +" detected afterwards, this one is used for the error exception. +" On a syntax error, the next command is not executed, on a normal +" error, however, it is (relevant only in a function without the +" "abort" flag). v:errmsg is not set. +" +" If throwing error exceptions is configured off, v:errmsg is always +" set to the latest error message, that is, to the more general +" message or the syntax error, respectively. +"------------------------------------------------------------------------------- +func Test_throw_multi_error() + CheckEnglish + + let test =<< trim [CODE] + func NEXT(cmd) + exec a:cmd . " | Xloop 'a'" + endfun + + call NEXT('echo novar') " (checks nextcmd) + XloopNEXT + call NEXT('let novar #') " (skips nextcmd) + XloopNEXT + call NEXT('unlet novar #') " (skips nextcmd) + XloopNEXT + call NEXT('let {novar}') " (skips nextcmd) + XloopNEXT + call NEXT('unlet{ novar}') " (skips nextcmd) + + call assert_equal('a1', g:Xpath) + XpathINIT + XloopINIT + + func EXEC(cmd) + exec a:cmd + endfunc + + try + while 1 " dummy loop + try + let v:errmsg = "" + call EXEC('echo novar') " normal error + catch /^Vim\((\a\+)\)\=:/ + Xpath 'b' + call assert_match('E121: Undefined variable: novar', v:exception) + finally + Xpath 'c' + call assert_equal("", v:errmsg) + break + endtry + endwhile + + Xpath 'd' + let cmd = "let" + while cmd != "" + try + let v:errmsg = "" + call EXEC(cmd . ' novar #') " normal plus syntax error + catch /^Vim\((\a\+)\)\=:/ + Xloop 'e' + call assert_match('E488: Trailing characters', v:exception) + finally + Xloop 'f' + call assert_equal("", v:errmsg) + if cmd == "let" + let cmd = "unlet" + else + let cmd = "" + endif + XloopNEXT + continue + endtry + endwhile + + Xpath 'g' + let cmd = "let" + while cmd != "" + try + let v:errmsg = "" + call EXEC(cmd . ' {novar}') " normal plus syntax error + catch /^Vim\((\a\+)\)\=:/ + Xloop 'h' + call assert_match('E475: Invalid argument: {novar}', v:exception) + finally + Xloop 'i' + call assert_equal("", v:errmsg) + if cmd == "let" + let cmd = "unlet" + else + let cmd = "" + endif + XloopNEXT + continue + endtry + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + Xpath 'j' + [CODE] + let verify =<< trim [CODE] + call assert_equal('bcde1f1e2f2gh3i3h4i4j', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +"------------------------------------------------------------------------------- +" Test 80: Syntax error in expression for illegal :elseif {{{1 +" +" If there is a syntax error in the expression after an illegal +" :elseif, an error message is given (or an error exception thrown) +" for the illegal :elseif rather than the expression error. +"------------------------------------------------------------------------------- +func Test_if_syntax_error() + CheckEnglish + + let test =<< trim [CODE] + let v:errmsg = "" + if 0 + else + elseif 1 ||| 2 + endif + Xpath 'a' + call assert_match('E584: :elseif after :else', v:errmsg) + + let v:errmsg = "" + if 1 + else + elseif 1 ||| 2 + endif + Xpath 'b' + call assert_match('E584: :elseif after :else', v:errmsg) + + let v:errmsg = "" + elseif 1 ||| 2 + Xpath 'c' + call assert_match('E582: :elseif without :if', v:errmsg) + + let v:errmsg = "" + while 1 + elseif 1 ||| 2 + endwhile + Xpath 'd' + call assert_match('E582: :elseif without :if', v:errmsg) + + while 1 + try + try + let v:errmsg = "" + if 0 + else + elseif 1 ||| 2 + endif + catch /^Vim\((\a\+)\)\=:/ + Xpath 'e' + call assert_match('E584: :elseif after :else', v:exception) + finally + Xpath 'f' + call assert_equal("", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'g' + break + endtry + endwhile + + while 1 + try + try + let v:errmsg = "" + if 1 + else + elseif 1 ||| 2 + endif + catch /^Vim\((\a\+)\)\=:/ + Xpath 'h' + call assert_match('E584: :elseif after :else', v:exception) + finally + Xpath 'i' + call assert_equal("", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'j' + break + endtry + endwhile + + while 1 + try + try + let v:errmsg = "" + elseif 1 ||| 2 + catch /^Vim\((\a\+)\)\=:/ + Xpath 'k' + call assert_match('E582: :elseif without :if', v:exception) + finally + Xpath 'l' + call assert_equal("", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'm' + break + endtry + endwhile + + while 1 + try + try + let v:errmsg = "" + while 1 + elseif 1 ||| 2 + endwhile + catch /^Vim\((\a\+)\)\=:/ + Xpath 'n' + call assert_match('E582: :elseif without :if', v:exception) + finally + Xpath 'o' + call assert_equal("", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'p' + break + endtry + endwhile + Xpath 'q' + [CODE] + let verify =<< trim [CODE] + call assert_equal('abcdefghijklmnopq', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +"------------------------------------------------------------------------------- +" Test 81: Discarding exceptions after an error or interrupt {{{1 +" +" When an exception is thrown from inside a :try conditional without +" :catch and :finally clauses and an error or interrupt occurs before +" the :endtry is reached, the exception is discarded. +"------------------------------------------------------------------------------- + +func Test_discard_exception_after_error_1() + let test =<< trim [CODE] + try + Xpath 'a' + try + Xpath 'b' + throw "arrgh" + call assert_report('should not get here') + if 1 + call assert_report('should not get here') + " error after :throw: missing :endif + endtry + call assert_report('should not get here') + catch /arrgh/ + call assert_report('should not get here') + endtry + call assert_report('should not get here') + [CODE] + let verify =<< trim [CODE] + call assert_equal('ab', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +" TODO: Need to interrupt the code before the endtry is invoked +func Disable_Test_discard_exception_after_error_2() + let test =<< trim [CODE] + try + Xpath 'a' + try + Xpath 'b' + throw "arrgh" + call interrupt() " FIXME: throw is not interrupted here + call assert_report('should not get here') + endtry + call assert_report('should not get here') + catch /arrgh/ + call assert_report('should not get here') + endtry + call assert_report('should not get here') + [CODE] + let verify =<< trim [CODE] + call assert_equal('ab', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +"------------------------------------------------------------------------------- +" Test 82: Ignoring :catch clauses after an error or interrupt {{{1 +" +" When an exception is thrown and an error or interrupt occurs before +" the matching :catch clause is reached, the exception is discarded +" and the :catch clause is ignored (also for the error or interrupt +" exception being thrown then). +"------------------------------------------------------------------------------- + +func Test_ignore_catch_after_error_1() + let test =<< trim [CODE] + try + try + Xpath 'a' + throw "arrgh" + call assert_report('should not get here') + if 1 + call assert_report('should not get here') + " error after :throw: missing :endif + catch /.*/ + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + endtry + call assert_report('should not get here') + catch /arrgh/ + call assert_report('should not get here') + endtry + call assert_report('should not get here') + [CODE] + let verify =<< trim [CODE] + call assert_equal('a', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +func Test_ignore_catch_after_error_2() + let test =<< trim [CODE] + func E() + try + try + Xpath 'a' + throw "arrgh" + call assert_report('should not get here') + if 1 + call assert_report('should not get here') + " error after :throw: missing :endif + catch /.*/ + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + endtry + call assert_report('should not get here') + catch /arrgh/ + call assert_report('should not get here') + endtry + endfunc + + call E() + call assert_report('should not get here') + [CODE] + let verify =<< trim [CODE] + call assert_equal('a', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +" TODO: Need to interrupt the code right before the catch is invoked +func FIXME_Test_ignore_catch_after_intr_1() + let test =<< trim [CODE] + try + try + Xpath 'a' + throw "arrgh" + call assert_report('should not get here') + catch /.*/ " TODO: Need to interrupt before this catch is + call interrupt() " invoked + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + endtry + call assert_report('should not get here') + catch /arrgh/ + call assert_report('should not get here') + endtry + call assert_report('should not get here') + [CODE] + let verify =<< trim [CODE] + call assert_equal('a', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +" TODO: Need to interrupt the code right before the catch is invoked +func FIXME_Test_ignore_catch_after_intr_2() + let test =<< trim [CODE] + func I() + try + try + Xpath 'a' + throw "arrgh" + call assert_report('should not get here') + catch /.*/ " TODO: Need to interrupt before this catch is + " invoked + call interrupt() + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + endtry + call assert_report('should not get here') + catch /arrgh/ + call assert_report('should not get here') + endtry + endfunc + + call I() + call assert_report('should not get here') + [CODE] + let verify =<< trim [CODE] + call assert_equal('a', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +"------------------------------------------------------------------------------- +" Test 83: Executing :finally clauses after an error or interrupt {{{1 +" +" When an exception is thrown and an error or interrupt occurs before +" the :finally of the innermost :try is reached, the exception is +" discarded and the :finally clause is executed. +"------------------------------------------------------------------------------- + +func Test_finally_after_error() + let test =<< trim [CODE] + try + Xpath 'a' + try + Xpath 'b' + throw "arrgh" + call assert_report('should not get here') + if 1 + call assert_report('should not get here') + " error after :throw: missing :endif + finally + Xpath 'c' + endtry + call assert_report('should not get here') + catch /arrgh/ + call assert_report('should not get here') + endtry + call assert_report('should not get here') + [CODE] + let verify =<< trim [CODE] + call assert_equal('abc', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +" TODO: Need to interrupt the code right before the finally is invoked +func FIXME_Test_finally_after_intr() + let test =<< trim [CODE] + try + Xpath 'a' + try + Xpath 'b' + throw "arrgh" + call assert_report('should not get here') + finally " TODO: Need to interrupt before the finally is invoked + Xpath 'c' + endtry + call assert_report('should not get here') + catch /arrgh/ + call assert_report('should not get here') + endtry + call assert_report('should not get here') + [CODE] + let verify =<< trim [CODE] + call assert_equal('abc', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +"------------------------------------------------------------------------------- +" Test 84: Exceptions in autocommand sequences. {{{1 +" +" When an exception occurs in a sequence of autocommands for +" a specific event, the rest of the sequence is not executed. The +" command that triggered the autocommand execution aborts, and the +" exception is propagated to the caller. +" +" For the FuncUndefined event under a function call expression or +" :call command, the function is not executed, even when it has +" been defined by the autocommands before the exception occurred. +"------------------------------------------------------------------------------- + +func Test_autocmd_exception() + let test =<< trim [CODE] + func INT() + call interrupt() + endfunc + + aug TMP + autocmd! + + autocmd User x1 Xpath 'a' + autocmd User x1 throw "x1" + autocmd User x1 call assert_report('should not get here') + + autocmd User x2 Xpath 'b' + autocmd User x2 asdf + autocmd User x2 call assert_report('should not get here') + + autocmd User x3 Xpath 'c' + autocmd User x3 call INT() + autocmd User x3 call assert_report('should not get here') + + autocmd FuncUndefined U1 func U1() + autocmd FuncUndefined U1 call assert_report('should not get here') + autocmd FuncUndefined U1 endfunc + autocmd FuncUndefined U1 Xpath 'd' + autocmd FuncUndefined U1 throw "U1" + autocmd FuncUndefined U1 call assert_report('should not get here') + + autocmd FuncUndefined U2 func U2() + autocmd FuncUndefined U2 call assert_report('should not get here') + autocmd FuncUndefined U2 endfunc + autocmd FuncUndefined U2 Xpath 'e' + autocmd FuncUndefined U2 ASDF + autocmd FuncUndefined U2 call assert_report('should not get here') + + autocmd FuncUndefined U3 func U3() + autocmd FuncUndefined U3 call assert_report('should not get here') + autocmd FuncUndefined U3 endfunc + autocmd FuncUndefined U3 Xpath 'f' + autocmd FuncUndefined U3 call INT() + autocmd FuncUndefined U3 call assert_report('should not get here') + aug END + + try + try + Xpath 'g' + doautocmd User x1 + catch /x1/ + Xpath 'h' + endtry + + while 1 + try + Xpath 'i' + doautocmd User x2 + catch /asdf/ + Xpath 'j' + finally + Xpath 'k' + break + endtry + endwhile + + while 1 + try + Xpath 'l' + doautocmd User x3 + catch /Vim:Interrupt/ + Xpath 'm' + finally + Xpath 'n' + " ... but break loop for caught interrupt exception, + " or discard interrupt and break loop if $VIMNOINTTHROW + break + endtry + endwhile + + if exists("*U1") | delfunction U1 | endif + if exists("*U2") | delfunction U2 | endif + if exists("*U3") | delfunction U3 | endif + + try + Xpath 'o' + call U1() + catch /U1/ + Xpath 'p' + endtry + + while 1 + try + Xpath 'q' + call U2() + catch /ASDF/ + Xpath 'r' + finally + Xpath 's' + " ... but break loop for caught error exception, + " or discard error and break loop if $VIMNOERRTHROW + break + endtry + endwhile + + while 1 + try + Xpath 't' + call U3() + catch /Vim:Interrupt/ + Xpath 'u' + finally + Xpath 'v' + " ... but break loop for caught interrupt exception, + " or discard interrupt and break loop if $VIMNOINTTHROW + break + endtry + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + Xpath 'w' + [CODE] + let verify =<< trim [CODE] + call assert_equal('gahibjklcmnodpqerstfuvw', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + +"------------------------------------------------------------------------------- +" Test 85: Error exceptions in autocommands for I/O command events {{{1 +" +" When an I/O command is inside :try/:endtry, autocommands to be +" executed after it should be skipped on an error (exception) in the +" command itself or in autocommands to be executed before the command. +" In the latter case, the I/O command should not be executed either. +" Example 1: BufWritePre, :write, BufWritePost +" Example 2: FileReadPre, :read, FileReadPost. +"------------------------------------------------------------------------------- + +func Test_autocmd_error_io_exception() + let test =<< trim [CODE] + " Remove the autocommands for the events specified as arguments in all used + " autogroups. + func Delete_autocommands(...) + let augfile = tempname() + while 1 + try + exec "redir >" . augfile + aug + redir END + exec "edit" augfile + g/^$/d + norm G$ + let wrap = "w" + while search('\%( \|^\)\@<=.\{-}\%( \)\@=', wrap) > 0 + let wrap = "W" + exec "norm y/ \n" + let argno = 1 + while argno <= a:0 + exec "au!" escape(@", " ") a:{argno} + let argno = argno + 1 + endwhile + endwhile + catch /.*/ + finally + bwipeout! + call delete(augfile) + break + endtry + endwhile + endfunc + + call Delete_autocommands("BufWritePre", "BufWritePost") + + while 1 + try + try + let post = 0 + aug TMP + au! BufWritePost * let post = 1 + aug END + write /n/o/n/e/x/i/s/t/e/n/t + catch /^Vim(write):/ + Xpath 'a' + call assert_match("E212: Can't open file for writing", v:exception) + finally + Xpath 'b' + call assert_equal(0, post) + au! TMP + aug! TMP + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + break + endtry + endwhile + + while 1 + try + try + let post = 0 + aug TMP + au! BufWritePre * asdf + au! BufWritePost * let post = 1 + aug END + let tmpfile = tempname() + exec "write" tmpfile + catch /^Vim\((write)\)\=:/ + Xpath 'd' + call assert_match('E492: Not an editor command', v:exception) + finally + Xpath 'e' + if filereadable(tmpfile) + call assert_report('should not get here') + endif + call assert_equal(0, post) + au! TMP + aug! TMP + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'f' + break + endtry + endwhile + + call delete(tmpfile) + + call Delete_autocommands("BufWritePre", "BufWritePost", + \ "BufReadPre", "BufReadPost", "FileReadPre", "FileReadPost") + + while 1 + try + try + let post = 0 + aug TMP + au! FileReadPost * let post = 1 + aug END + let caught = 0 + read /n/o/n/e/x/i/s/t/e/n/t + catch /^Vim(read):/ + Xpath 'g' + call assert_match("E484: Can't open file", v:exception) + finally + Xpath 'h' + call assert_equal(0, post) + au! TMP + aug! TMP + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'i' + break + endtry + endwhile + + while 1 + try + let infile = tempname() + let tmpfile = tempname() + call writefile(["XYZ"], infile) + exec "edit" tmpfile + try + Xpath 'j' + try + let post = 0 + aug TMP + au! FileReadPre * asdf + au! FileReadPost * let post = 1 + aug END + exec "0read" infile + catch /^Vim\((read)\)\=:/ + Xpath 'k' + call assert_match('E492: Not an editor command', v:exception) + finally + Xpath 'l' + if getline("1") == "XYZ" + call assert_report('should not get here') + endif + call assert_equal(0, post) + au! TMP + aug! TMP + endtry + finally + Xpath 'm' + bwipeout! + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'n' + break + endtry + endwhile + + call delete(infile) + call delete(tmpfile) + [CODE] + let verify =<< trim [CODE] + call assert_equal('abcdefghijklmn', g:Xpath) + [CODE] + call RunInNewVim(test, verify) +endfunc + "------------------------------------------------------------------------------- " Test 87 using (expr) ? funcref : funcref {{{1 " diff --git a/src/testdir/vim9.vim b/src/testdir/vim9.vim index fdad9f7c3a..448aa3db94 100644 --- a/src/testdir/vim9.vim +++ b/src/testdir/vim9.vim @@ -1,5 +1,13 @@ " Utility functions for testing vim9 script +" Check that "lines" inside ":def" has no error. +func CheckDefSuccess(lines) + call writefile(['def Func()'] + a:lines + ['enddef', 'defcompile'], 'Xdef') + so Xdef + call Func() + call delete('Xdef') +endfunc + " Check that "lines" inside ":def" results in an "error" message. func CheckDefFailure(lines, error) call writefile(['def Func()'] + a:lines + ['enddef', 'defcompile'], 'Xdef') diff --git a/src/userfunc.c b/src/userfunc.c index 7d3039a459..9ab5ffe525 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -686,7 +686,10 @@ get_func_tv( while (--argcount >= 0) clear_tv(&argvars[argcount]); - *arg = skipwhite(argp); + if (in_vim9script()) + *arg = argp; + else + *arg = skipwhite(argp); return ret; } @@ -2129,8 +2132,8 @@ call_func( char_u *p = untrans_function_name(rfname); // If using Vim9 script try not local to the script. - // TODO: should not do this if the name started with "s:". - if (p != NULL) + // Don't do this if the name starts with "s:". + if (p != NULL && (funcname[0] != 's' || funcname[1] != ':')) fp = find_func(p, is_global, NULL); } @@ -4097,6 +4100,7 @@ ex_call(exarg_T *eap) if (!failed || eap->cstack->cs_trylevel > 0) { // Check for trailing illegal characters and a following command. + arg = skipwhite(arg); if (!ends_excmd2(eap->arg, arg)) { if (!failed) diff --git a/src/version.c b/src/version.c index d9fbaa74d2..f779a29d6d 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,30 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1424, +/**/ + 1423, +/**/ + 1422, +/**/ + 1421, +/**/ + 1420, +/**/ + 1419, +/**/ + 1418, +/**/ + 1417, +/**/ + 1416, +/**/ + 1415, +/**/ + 1414, +/**/ + 1413, /**/ 1412, /**/ @@ -3948,20 +3972,11 @@ list_version(void) # if defined(MSWIN) msg_puts(_("with GUI.")); # else -# if defined(FEAT_GUI_MACVIM) +# if defined(FEAT_GUI_MACVIM) msg_puts(_("with MacVim GUI.")); -# else -# if defined(TARGET_API_MAC_CARBON) && TARGET_API_MAC_CARBON - msg_puts(_("with Carbon GUI.")); -# else -# if defined(TARGET_API_MAC_OSX) && TARGET_API_MAC_OSX - msg_puts(_("with Cocoa GUI.")); -# else -# endif -# endif -# endif -# endif # endif +# endif +# endif # endif # endif # endif diff --git a/src/vim.h b/src/vim.h index 45cc277665..2ae86c7147 100644 --- a/src/vim.h +++ b/src/vim.h @@ -97,7 +97,6 @@ // Unless made through the Makefile enforce GUI on Mac #if defined(MACOS_X) && !defined(HAVE_CONFIG_H) # define UNIX -# define FEAT_GUI_MAC #endif #if defined(FEAT_GUI_MOTIF) \ @@ -105,7 +104,6 @@ || defined(FEAT_GUI_ATHENA) \ || defined(FEAT_GUI_HAIKU) \ || defined(FEAT_GUI_MACVIM) \ - || defined(FEAT_GUI_MAC) \ || defined(FEAT_GUI_MSWIN) \ || defined(FEAT_GUI_PHOTON) # define FEAT_GUI_ENABLED // also defined with NO_X11_INCLUDES @@ -2155,7 +2153,7 @@ typedef enum { // been seen at that stage. But it must be before globals.h, where error_ga // is declared. #if !defined(MSWIN) && !defined(FEAT_GUI_X11) && !defined(FEAT_GUI_HAIKU) \ - && !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MAC) && !defined(PROTO) + && !defined(FEAT_GUI_GTK) && !defined(PROTO) # define mch_errmsg(str) fprintf(stderr, "%s", (str)) # define display_errors() fflush(stderr) # define mch_msg(str) printf("%s", (str)) @@ -2165,8 +2163,7 @@ typedef enum { # if defined(FEAT_EVAL) \ && (!defined(FEAT_GUI_MSWIN) \ - || !(defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME))) \ - && !(defined(FEAT_GUI_MAC) && defined(MACOS_CONVERT)) + || !(defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME))) // Whether IME is supported by im_get_status() defined in mbyte.c. // For Win32 GUI it's in gui_w32.c when FEAT_MBYTE_IME or GLOBAL_IME is defined. // for Mac it is in gui_mac.c for the GUI or in os_mac_conv.c when @@ -2177,8 +2174,7 @@ typedef enum { #if defined(FEAT_XIM) \ || defined(IME_WITHOUT_XIM) \ || (defined(FEAT_GUI_MSWIN) \ - && (defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME))) \ - || defined(FEAT_GUI_MAC) + && (defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME))) // im_set_active() is available # define HAVE_INPUT_METHOD #endif diff --git a/src/vim9compile.c b/src/vim9compile.c index 81206b3aca..72c26ce46e 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2723,11 +2723,12 @@ compile_get_register(char_u **arg, cctx_T *cctx) /* * Apply leading '!', '-' and '+' to constant "rettv". + * When "numeric_only" is TRUE do not apply '!'. */ static int -apply_leader(typval_T *rettv, char_u *start, char_u *end) +apply_leader(typval_T *rettv, int numeric_only, char_u *start, char_u **end) { - char_u *p = end; + char_u *p = *end; // this works from end to start while (p > start) @@ -2762,6 +2763,11 @@ apply_leader(typval_T *rettv, char_u *start, char_u *end) rettv->vval.v_number = val; } } + else if (numeric_only) + { + ++p; + break; + } else { int v = tv2bool(rettv); @@ -2772,6 +2778,7 @@ apply_leader(typval_T *rettv, char_u *start, char_u *end) rettv->vval.v_number = v ? VVAL_FALSE : VVAL_TRUE; } } + *end = p; return OK; } @@ -2860,11 +2867,12 @@ get_compare_type(char_u *p, int *len, int *type_is) /* * Compile code to apply '-', '+' and '!'. + * When "numeric_only" is TRUE do not apply '!'. */ static int -compile_leader(cctx_T *cctx, char_u *start, char_u *end) +compile_leader(cctx_T *cctx, int numeric_only, char_u *start, char_u **end) { - char_u *p = end; + char_u *p = *end; // this works from end to start while (p > start) @@ -2890,6 +2898,11 @@ compile_leader(cctx_T *cctx, char_u *start, char_u *end) if (isn == NULL) return FAIL; } + else if (numeric_only) + { + ++p; + break; + } else { int invert = TRUE; @@ -2903,6 +2916,7 @@ compile_leader(cctx_T *cctx, char_u *start, char_u *end) return FAIL; } } + *end = p; return OK; } @@ -2914,10 +2928,12 @@ compile_leader(cctx_T *cctx, char_u *start, char_u *end) compile_subscript( char_u **arg, cctx_T *cctx, - char_u **start_leader, - char_u *end_leader, + char_u *start_leader, + char_u **end_leader, ppconst_T *ppconst) { + char_u *name_start = *end_leader; + for (;;) { char_u *p = skipwhite(*arg); @@ -2959,7 +2975,7 @@ compile_subscript( *arg = skipwhite(p + 1); if (compile_arguments(arg, cctx, &argcount) == FAIL) return FAIL; - if (generate_PCALL(cctx, argcount, end_leader, type, TRUE) == FAIL) + if (generate_PCALL(cctx, argcount, name_start, type, TRUE) == FAIL) return FAIL; } else if (*p == '-' && p[1] == '>') @@ -2972,9 +2988,8 @@ compile_subscript( // something->method() // Apply the '!', '-' and '+' first: // -1.0->func() works like (-1.0)->func() - if (compile_leader(cctx, *start_leader, end_leader) == FAIL) + if (compile_leader(cctx, TRUE, start_leader, end_leader) == FAIL) return FAIL; - *start_leader = end_leader; // don't apply again later p += 2; *arg = skipwhite(p); @@ -3191,6 +3206,15 @@ compile_expr7( case '9': case '.': if (eval_number(arg, rettv, TRUE, FALSE) == FAIL) return FAIL; + // Apply "-" and "+" just before the number now, right to + // left. Matters especially when "->" follows. Stops at + // '!'. + if (apply_leader(rettv, TRUE, + start_leader, &end_leader) == FAIL) + { + clear_tv(rettv); + return FAIL; + } break; /* @@ -3329,14 +3353,6 @@ compile_expr7( if (rettv->v_type != VAR_UNKNOWN && used_before == ppconst->pp_used) { - // apply the '!', '-' and '+' before the constant - if (apply_leader(rettv, start_leader, end_leader) == FAIL) - { - clear_tv(rettv); - return FAIL; - } - start_leader = end_leader; // don't apply again below - if (cctx->ctx_skip == SKIP_YES) clear_tv(rettv); else @@ -3373,18 +3389,18 @@ compile_expr7( // Handle following "[]", ".member", etc. // Then deal with prefixed '-', '+' and '!', if not done already. - if (compile_subscript(arg, cctx, &start_leader, end_leader, + if (compile_subscript(arg, cctx, start_leader, &end_leader, ppconst) == FAIL) return FAIL; if (ppconst->pp_used > 0) { // apply the '!', '-' and '+' before the constant rettv = &ppconst->pp_tv[ppconst->pp_used - 1]; - if (apply_leader(rettv, start_leader, end_leader) == FAIL) + if (apply_leader(rettv, FALSE, start_leader, &end_leader) == FAIL) return FAIL; return OK; } - if (compile_leader(cctx, start_leader, end_leader) == FAIL) + if (compile_leader(cctx, FALSE, start_leader, &end_leader) == FAIL) return FAIL; return OK; } diff --git a/src/window.c b/src/window.c index 553533f62f..48ed90a8e2 100644 --- a/src/window.c +++ b/src/window.c @@ -3849,6 +3849,7 @@ free_tabpage(tabpage_T *tp) win_new_tabpage(int after) { tabpage_T *tp = curtab; + tabpage_T *prev_tp = curtab; tabpage_T *newtp; int n; @@ -3898,7 +3899,7 @@ win_new_tabpage(int after) newtp->tp_topframe = topframe; last_status(FALSE); - lastused_tabpage = tp; + lastused_tabpage = prev_tp; #if defined(FEAT_GUI) // When 'guioptions' includes 'L' or 'R' may have to remove or add